在QEMU里学C语言-01- #define

2021-05-17 09:30

阅读:253

标签:not   语言   OLE   列表   cto   表示   阅读   扩展   ali   

QEMU中对C语言的使用非常高级,这里想从QEMU中对C语言的用法中,来重新认识C语言,今天的任务就是从弄懂这几段代码的意思开始吧!

#define module_init(function, type)                                         static void __attribute__((constructor)) do_qemu_init_ ## function(void)    {                                                                               register_module_init(function, type);                                   }
#endif
#define QTAILQ_INSERT_TAIL(head, elm, field) do {                       \
        (elm)->field.tqe_next = NULL;                                           (elm)->field.tqe_prev = (head)->tqh_last;                               *(head)->tqh_last = (elm);                                              (head)->tqh_last = &(elm)->field.tqe_next;                      } while (/*CONSTCOND*/0)
#define Q_TAILQ_HEAD(name, type, qual)                                  struct name {                                                                   qual type *tqh_first;           /* first element */                     qual type *qual *tqh_last;      /* addr of last next element */ }

 

  1. 先从C语言里关于define的语法进行整理

不带参数的define的格式是:

#define 名字  替换文本

在定义之后,程序出现定义的名字,都将用相应的替换文本代替。

  • 有些字符可以通过转义字符序列表示为字符和字符串常量
#define VTAB ‘\103‘  //ASCII纵向制表符
  • 常量表达式,仅仅包含常量的表达式这种表达式在编译时求值,而不再运行时求值。
#define MAXLINE 100
char line[MAXLINE+1]
  • #define和枚举常量
    enum boolean {NO,YES} //NO的值为0,yes为1 ,以此类推

    枚举为常量值和名字之间的关联提供了一种遍历方式,相对于#define而言,它的优势在于常量值能自动生成。

宏替换:

  • 作用域:从宏定义开始,到被编译的源文件的末尾处结束
  • 替换文本是任意的
#define forever for(;;)   //无限循环
  • 宏定义也可以带参数,这样可以对不同的宏调用使用不同的替换文本
  • #define max(A,B) ((A)>(B)?(A):(B))

    这样很像是函数调用,但宏调用直接将替换文本插入到代码中,形参A,B每次都会被替换为实参。

  • x = max(p+q,s+r)
    将会被替换成
    x = ((p+q)>(s+r)?(p+q):(r+s))

    这样的好处是,不用每次都对不同的数据类型定义不同的函数

  • 缺陷是:当max(i++,j++) 会加两次,有错
  • 适当用括号以保证计算的正确性
    #define square(x)  x*x
    
    square(z+1) //会有错
  • 例如:在头文件中有一个很实用的例子:getchar和putchar函数常被定义为宏,这样可以避免处理字符时调用函数所需要的运行时开销。(为什么?)
  • 用#undef可以取消名字的宏定义,这样可以保证后续的调用是函数调用,而不是宏调用
  • #undef getchar
    int getchar(void) {...}

    形参不能用带引号的字符串替换。(有什么能这样被替换吗?)但是,如果在替换文本中,参数名以#作为前缀则结果将被扩展为由实际参数替换该参数的带引号的字符串

  • #define dprint(expr) printf(#expr " = %g\n", expr)
    
    dprint(x\y);
    
    结果为
    printf("x\y""=%g\n",x\y);
    而字符串被连接在一起了,所以等价于
    printf("x\y = %g\n",x\y);

    预处理运算符##为宏扩展提供了一种连接实参的手段。若替换文本的参数与##响铃,则该参数会被实际参数替换!

#define paste(front, back)  front##back

paste(name,1) 

结果为: name1

 

2. 所以若type_init(ppc_heathrow_register_types):所以这一段代码的意思就是

#define type_init(function) module_init(function, MODULE_INIT_QOM)
#define module_init(function, type)                                         static void __attribute__((constructor)) do_qemu_init_ ## function(void)    {                                                                               register_module_init(function, type);                                   }
#endif

技术分享图片

3. 这段代码也是完成了宏调用,当(/*CONSTCOND*/0)时,完成把节点插在队尾

#define QTAILQ_INSERT_TAIL(head, elm, field) do {                       \
        (elm)->field.tqe_next = NULL;                                           (elm)->field.tqe_prev = (head)->tqh_last;                               *(head)->tqh_last = (elm);                                              (head)->tqh_last = &(elm)->field.tqe_next;                      } while (/*CONSTCOND*/0)

技术分享图片

 

总结:

#define 就是一种预编译时的替换(虽然不知道这样理解对不对)

用一个名字,替代掉复杂的函数,冗长的名字,和不让人理解的数字,其目的就是为了节约开销(为什么)和提高代码的阅读性

当然还有像这样的条件编译 : #ifdef 和 #endif 就不多说了

代码不管是用什么语言来写,最终都是编译成计算机能懂能执行的机器指令

路漫漫

#ifdef CONFIG_MODULES
static int module_load_file(const char *fname)
{
    GModule *g_module;
    void (*sym)(void);
    const char *dsosuf = HOST_DSOSUF;
    int len = strlen(fname);
    int suf_len = strlen(dsosuf);
    ModuleEntry *e, *next;
    int ret;

    if (len  suf_len], dsosuf)) {
        /* wrong suffix */
        ret = -EINVAL;
        goto out;
    }
    if (access(fname, F_OK)) {
        ret = -ENOENT;
        goto out;
    }

    assert(QTAILQ_EMPTY(&dso_init_list));

    g_module = g_module_open(fname, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
    if (!g_module) {
        fprintf(stderr, "Failed to open module: %s\n",
                g_module_error());
        ret = -EINVAL;
        goto out;
    }
    if (!g_module_symbol(g_module, DSO_STAMP_FUN_STR, (gpointer *)&sym)) {
        fprintf(stderr, "Failed to initialize module: %s\n",
                fname);
        /* Print some info if this is a QEMU module (but from different build),
         * this will make debugging user problems easier. */
        if (g_module_symbol(g_module, "qemu_module_dummy", (gpointer *)&sym)) {
            fprintf(stderr,
                    "Note: only modules from the same build can be loaded.\n");
        }
        g_module_close(g_module);
        ret = -EINVAL;
    } else {
        QTAILQ_FOREACH(e, &dso_init_list, node) {
            e->init();
            register_module_init(e->init, e->type);
        }
        ret = 0;
    }

    QTAILQ_FOREACH_SAFE(e, &dso_init_list, node, next) {
        QTAILQ_REMOVE(&dso_init_list, e, node);
        g_free(e);
    }
out:
    return ret;
}
#endif

欢迎指正

在QEMU里学C语言-01- #define

标签:not   语言   OLE   列表   cto   表示   阅读   扩展   ali   

原文地址:https://www.cnblogs.com/mumutoday/p/9744603.html


评论


亲,登录后才可以留言!