Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1682199
  • 博文数量: 311
  • 博客积分: 7778
  • 博客等级: 少将
  • 技术积分: 4186
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-09 19:59
个人简介

蓝点工坊(http://www.bluedrum.cn) 创始人,App和嵌入式产品开发。同时也做相应培训和外包工作。 详细介绍 http://pan.baidu.com/s/1y2g88

文章存档

2012年(3)

2011年(115)

2010年(170)

2009年(23)

分类: C/C++

2010-05-08 15:31:20

Andrew Huang

 

一个学员拿了这样一个定义问我含义,我解释了后,看一下这个对于C预处理和gcc的细节问题还是很典型。因此跟大家分享一下。

typedef struct cmd_tbl{
        char *name;
        int (*cmd)(int argc, char *argv[]);
}cmd_tbl_t;

#define cmd_section __attribute__ ((unused,section (".g_boot_cmd")))

#define G_BOOT_CMD(cmd_name, cmd_cmd) \
cmd_tbl_t __g_boot_cmd_##cmd_name cmd_section =
{ \
        .name = #cmd_name, \
        .cmd = cmd_cmd, \
}

1.定义一个结构  struct cmd_tbl,有两个成员,第一个名字是name.第二是cmd,是一个函数指针。

2.宏cmd_section  定义是 __attribute__ ((unused,section (".g_boot_cmd"))),这个是gcc的特殊用法__atribute__是用来定义一些特性属性。用处在后面结构生成后再一并解释

3宏G_BOOT_CMD定义比较复杂了,这里采用\来做换行符,来用多行定义宏体。

4.这个宏有两参数cmd_name,cmd_cmd.

5.##在宏定义表示把宏变量联接成两个字符串,形成一个新的符号名字(如变量名,函数名)。主要用于变量名的定义,这样在用同一个宏里可以定义出不同变量

6.#在宏定义表示把宏变量字符串化,换句话说宏变量在C源码是怎么样的,将会转成对应字符串。如 #define PRINT_INT(e) printf("%s=%d\n",#e,e),这里的#e就是用把宏变量转成对应名字.

  1.   这里的在源码里执行 PRINT_INT(i); //--> printf("%s=%d\n","i",i)
  2.  PRINT_INT(2+3) ; //-->printf("%s=%d\n","2+3",2+3);
  3.  PRINT_INT(sizeof(int)); //--> printf("%s=%d\n","sizeof(int)",sizeof(int));

注意一下如果宏变量是char *类型,用#宏开时,与变量对应值无关,#只取显示的名字。比如

char * tmp = "hxy";  #define PRINT_STR(e) printf("%s=%s\n",#e,e

PRINT_STR(tmp);中#e,输出是"tmp",而不是"hxy";

  要注意#是转成字符串,##是转成一个符号,关于#和##具体用法。可以参见如下更为简单代码b
 

#include <stdio.h>

#define G_BOOT(abc,str) char * g_boot_##abc = #str

#define PRINT_STR(e) printf("%s=%s\n",#e,e)

int main()
{
  char * tmp = "hello";

  G_BOOT(hxy,tmp);
  printf("g_boot= %s\n",g_boot_hxy);

  PRINT_STR(g_boot_hxy);
  getchar();
}


其中的 G_BOOT()定义了,这里程序输出结果是

g_boot= tmp
g_boot_hxy=tmp

7..name = ...,和 .cmd = ....是gcc的结构初始化的特殊用法。这样可以不需要理会结构成员定义顺序,可以用 .成员名= 成员值 来指定名字来定义,这样结构成员位置调整后不需改变结构代码。另外用成员名来初始化。可以减少出错可能性。标准C只能采用{}来定义了

cmd_tbl boot = { "boot",boot_fn }; //标准C用法

cmd_tbl boot = { .cmd = boot_fn, .name ="boot"} ; //gcc 扩展用法

8.综合所述, G_BOOT_CMD是定义一个全局的cmd_tbl.并且完成初始化。这里可以谈cmd_section的用法了。全局变量默认是放在数据段里,section (".g_boot_cmd")表示这个变量链接在.g_boot_cmd这个自定义段中

阅读(2061) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~