标签: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 */ }
不带参数的define的格式是:
#define 名字 替换文本
在定义之后,程序出现定义的名字,都将用相应的替换文本代替。
#define VTAB ‘\103‘ //ASCII纵向制表符
#define MAXLINE 100 char line[MAXLINE+1]
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))
这样的好处是,不用每次都对不同的数据类型定义不同的函数
#define square(x) x*x square(z+1) //会有错
#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 || strcmp(&fname[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
欢迎指正
标签:not 语言 OLE 列表 cto 表示 阅读 扩展 ali
原文地址:https://www.cnblogs.com/mumutoday/p/9744603.html