1. 语句表达式

GNU C 把包含在括号中的复合语句看做是一个表达式,称作语句表达式,它可以出现在任何允许表达式的地方。我们可以在语句表达式中使用原本只能在复合语句中使用的循环、局部变量等,例如:

#define min_t(type, x, y)   \
({ type _x = (x); type _y = (y); _x < _y ? _x : _y; }) int ia, ib, mini;
float fa, fb, minf; mini = min_t(int, ia, ib);
minf = min_t(float, fa, fb);

因为重新定义了 _x 和 __y 这两个局部变量,所以以上述方式定义人宏将不会有副作用。在标准 C 中,对应的如下宏则会产生副作用:

#define min(x, y) ((x) < (y) ? (x) : (y))

代码 min(++ia, ++ib) 会被展开为 ((++ia) < (++ib) ? (++ia) : (++ib)),传入宏的“参数”被增加 2 次。

2. typeof 关键字

typeof(x) 语句可以获得 x 的类型,因此,我们可以借助 typeof 重新定义 min 这个宏:

#define min(x, y)   ({          \
const typeof(x) _x = (x); \
const typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x < _y ? _x : _y; })

(void) (&_x == &_y) 的作用

我们不需要像 min_t(type, x, y) 这个宏那样把 type 传入,因为通过 typeof(x)、typeof(y) 可以获得 type。代码行 (void)(&_x == &_y) 的作用是检查 _x 和 _y 的类型是否一致。

3. 可变参数宏

标准 C 就支持可变参数函数,意味着函数的参数是不固定,例如 printf() 函数的原型为:

int printf(const char *format [, argument]...);

而在 GNU C 中,宏也可以接受可变数目的参数,例如:

#define per_debug(fmt, arg...)  \
printk(fmt, ##arg)

这里 arg 表示其余的参数,可以是零个或多个,这些参数以及参数之间的逗号构成 arg 的值,在宏扩展时替换 arg,例如下列代码:

pr_debug("%s : %d", filename, line)

会被扩展为:

printk("%s : %d", filename, line)

使用“##”的原因是处理 arg 不代表任何参数的情况,这时候,前面的逗号就变得多余了。使用“##”之后,GNU C 预处理会丢弃前面的逗号。

参考自:《Linux 设备驱动开发》

GNU C 与 ANSI C(下)的更多相关文章

  1. GNU C 、ANSI C、标准C、标准c++区别和联系

    转载自点击打开链接 GNU计划,又称革奴计划,是由Richard Stallman在1983年9月27日公开发起的.它的目标是创建一套完全自由的操作系统.它在编写linux的时候自己制作了一个标准成为 ...

  2. VC 编程ANSI环境下读写Unicode文件

    没有注意到文件编码的不同会产生这么多的问题,在动手以前查询了很多资料,在本博客中收藏了不少先辈的成果,在这里一并表示致敬!       关于ANSI和Unicode编码的原理在这里也不说了,主要讲下如 ...

  3. GNU C 与 ANSI C的区别

    1.零长度数组 GNU C允许使用零长度数组,定义变长度对象时比较方便 struct var_data { int len; char data[0]; }; var_data的大小仅为一个int型, ...

  4. GNU C 与 ANSI C(上)

    Linux 上可用的 C 编译器是 GNU C 编译器,它建立在自由软件基金会的编程许可证的基础上,因此可以自由发布.GNU C 是对标准 C 进行的一系列扩展,以增强标准 C 的功能. 1. 零长度 ...

  5. GNU C与ANSI C的不同

    引用:http://tsroad.lofter.com/post/376316_57ac519 1.GNU C可定义0长度数组,目的是为了定义可变长结构体. struct var_struct{    ...

  6. C11 (GNU Dialect) -std=gnu11 和 -std=c11

    C11 (GNU Dialect) -std=gnu11 和 -std=c11 C11 (GNU Dialect) -std=gnu11 和 -std=c11 用于 IntelliSense 的 C ...

  7. C++对象模型与内存位对齐的简单分析(GNU GCC&VS2015编译器)

    以Fruit和Apple为例进行分析: Fruit和Apple的定义如下: 通过在两种编译环境下的测试(GNU GCC & VS2015),可以发现这两种编译器的对象模型是一样的,如下图所示: ...

  8. linux下阅读源代码的工具

    说来真是惭愧呀.一直在用VIM 做开发.却不知道VI 里还有这么好使的工具.以前一直都是用: find -type f -print | xargs grep -i **** 在源代码里查找. 原来L ...

  9. 有关UNICODE、ANSI字符集和相关字符串操作

    Q UNICODE字符串如何显示 A 如果程序定义了_UNICODE宏直接用 WCHAR *str=L"unicodestring"; TextOut(0,0,str); 否则就需 ...

随机推荐

  1. VUE项目 npm run build卡住不动,也不报错

    npm config set registry http://registry.cnpmjs.org try again npm run build 居然能动了....

  2. Layui++>>ajax传递数组,防止深度序列化

  3. flask-cookie & session

    Cookie @app.route('/') def hello_world(): name=request.cookies.get('Name')  # 获取cookie resp = Respon ...

  4. PWM of STM32

    下面是STM32用来产生PWM得文件,分别是PWM.c和PWM.h /***************************************************************** ...

  5. java面试问题收集(2)

    1 Integer int相等问题 Integer对象和int比较的时候会有一个拆箱的过程,始终相等 Integer和new Integer对象不会相等,引用不同 两个Integer对象比较,Inte ...

  6. Djangoの1

    有ip无路由是404,ip也无是无法访问此网站.url中?前的是路由,?后是GET请求的各组参数.   子项目和子应用下的两类urls.py:[]内的各个路由函数url,其首参网址的开头无/,结尾有/ ...

  7. 《python语言程序设计》_第三章(数字函数、字符串和对象)

    3.2_常见的Python函数 (1) abs()函数 求绝对值 (2) max(x1,x2,x3,....)求最大值 (3) min(x1,x2,x3,....)求最小值 (4) pow 返回a的b ...

  8. [转]异常声音检测之kaldi DNN 训练

    转自:http://blog.csdn.net/huchad/article/details/52092796 使用kaldi的DNN做音频分类,异常声音检测. HMM/GMM -> HMM/D ...

  9. 每天学点SpringCloud(十四):Zipkin使用SpringCloud Stream以及Elasticsearch

    在前面的文章中,我们已经成功的使用Zipkin收集了项目的调用链日志.但是呢,由于我们收集链路信息时采用的是http请求方式收集的,而且链路信息没有进行保存,ZipkinServer一旦重启后就会所有 ...

  10. fixed Oracle SQL报错 #ORA-01460: 转换请求无法实施或不合理

    最近遇到一个oracle错误,之前并没有遇到过,并不是select in超过1000个导致的,通过网上资料说是oracle版本导致,也有的说是oracle SQL过长导致. 然后通过自己实践应该说是o ...