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. B树/[oracle]connect BY语句

    读大神的书,出现很多没有见过的函数和便捷操作,特此记录 connect by 之前没有接触过,为了学习这个语句,先了解一下B树数据类型是最好的方法. [本人摘自以下博客] https://www.cn ...

  2. ES6 generators in depth 一(译)

    今天在学习redux-saga时,外部链接推荐了这篇文章ES6 generators in depth,所以翻译的同时也可以加深一下对Generator的理解. 这里对原文一些只能在高版本现代浏览器使 ...

  3. python3+redis问题求解

    学生管理系统   更新学生信息没做出来,找个大神补全下.谢谢. # 记录: # bug:操作后若退出需要两次退出才行. 待修复 # 下一步:链接redis进行使用. # 更新学生库信息 待完成 imp ...

  4. 2.Spring 拦截器应用

    首先咱们来了解一下具体的业务场景(这个跟第一篇中的很相似但有不同):具体的业务是这样的,现在系统中有六十多个主档(功能模块),每个主档都有新增.修改.删除功能,当我们在对每个主档做这些操作时需要对其记 ...

  5. javascript中数组总结

    数组是所有高级语言都会有的东西,数组是JS中使用最多的类型之一,所以掌握JS中数组的用法相当有帮助: 由于JS是一门弱类型的语言,所以数组里面可以放各种不同的数据类型,比如 var a = [1993 ...

  6. Codeforces Round #418 (Div. 2)

    A: 不细心WA了好多次 题意:给你一个a序列,再给你个b序列,你需要用b序列中的数字去替换a序列中的0,如果能够替换,则需要判断a是否能构成一个非递增的序列,a,b中所有的数字不会重复 思路:就是一 ...

  7. PHP的生命周期:

  8. 为什么我们要使用int类型来保存时间类型的数据。

    1.如果数据保存的是timestamp类型那么,如果某个服务器系统时区配置错误,那么悲剧的是通过该服务器写入的时间都是有偏差的.  如果使用int类型保存unix时间戳的话,那么就是在前端展示的时候转 ...

  9. 程序员工作 996 生病 ICU ?

    阅读本文大概需要 2 分钟. 说实话,一般平时这个点我已经睡着了,今天准备好的文章也会准时在凌晨推送给大家.睡前看篇关于强制 996 加班的消息,里面有句口号还挺溜,上班996,下班ICU,为此还特意 ...

  10. SpringBoot条件注解@Conditional

    最近项目中使用到了关于@Conditional注解的一些特性,故写此文记录一下 @Conditional是啥呀? @Conditional注解是个什么东西呢,它可以根据代码中设置的条件装载不同的bea ...