答疑解惑 | Linux GNU C 与 ANSI C 的区别

💡 原文中文,约5500字,阅读约需14分钟。
📝

内容提要

GNU C编译器在Linux上提供了多个扩展来增强标准C的功能。这些扩展包括零长度和可变长度数组、case范围、语句表达式、typeof关键字、可变参数宏、标记元素、当前函数名称、特殊属性声明和内置函数。这些扩展在编程中提供了更多的灵活性和优化。

🔎

延伸解读

GNU C扩展的适用场景与可移植性权衡

GNU C扩展为Linux内核和系统编程提供了便利,如零长度数组用于变长结构、case范围简化多分支判断。但这些扩展不被标准C支持,使用-ansi -pedantic编译选项会触发警告。若代码需要跨平台或严格遵循标准,应避免使用扩展,或通过条件编译隔离。

从GNU C扩展看Linux内核的编码风格演变

文章提到Linux 2.6推荐使用标准C的指定初始化方式(如.llseek = ...)替代GNU C的标号元素(如llseek: ...)。这反映了内核社区对代码可移植性和标准符合性的重视。类似地,__FUNCTION__被C99的__func__取代,也体现了向标准靠拢的趋势。

语句表达式与typeof:编写安全宏的关键

GNU C的语句表达式和typeof关键字允许在宏中定义局部变量并获取类型,从而避免参数多次求值带来的副作用。例如min宏通过typeof和语句表达式确保参数只计算一次,并检查类型一致性。这种技术在内核中常见,但需注意扩展语法可能降低代码可读性。

内建函数与属性声明:性能优化的双刃剑

GNU C提供__builtin_expect等内建函数用于分支预测,以及__attribute__属性用于对齐、打包等优化。这些特性可提升性能,但过度使用可能使代码依赖编译器,降低可移植性。开发者应权衡优化收益与代码可维护性,尤其在跨平台项目中。

❓

Q&A

GNU C 和 ANSI C 的主要区别是什么?

GNU C 在标准 C(ANSI C)的基础上进行了一系列扩展,以增强标准 C 的功能。这些扩展包括零长度和可变长度数组、case 范围、语句表达式、typeof 关键字、可变参数宏、标号元素、当前函数名、特殊属性声明和内建函数等。

GNU C 中零长度数组有什么用途?

零长度数组在定义变长对象的头结构时非常有用。例如,struct var_data { int len; char data[0]; }; 其中 data[0] 不占用内存,sizeof(struct var_data) 等于 sizeof(int)。通过 data[index] 可以访问 len 之后的数据。

GNU C 的 case 范围语法怎么用?

GNU C 支持 case x...y 语法,表示区间 [x, y] 中的数都满足该 case 条件。例如:case '0' ... '9': 等价于标准 C 中列出所有数字的 case。

GNU C 的 typeof 关键字有什么作用?

typeof(x) 可以获得变量 x 的类型。借助 typeof 可以重新定义宏,例如 min 宏,无需传入类型参数,因为通过 typeof(x) 和 typeof(y) 就能获得类型。代码行 (void)(&_x == &_y) 用于检查 _x 和 _y 的类型是否一致。

GNU C 中可变参数宏如何定义和使用?

GNU C 允许宏接受可变数目的参数,例如 printk(fmt, ...)。使用 '##' 处理参数为空的情况,避免多余的逗号。例如 pr_debug("success!") 会正确扩展为 printk("success!") 而不是 printk("success!",)。

GNU C 的特殊属性声明有哪些常见例子?

GNU C 允许使用 __attribute__((ATTRIBUTE)) 声明函数、变量和类型的特殊属性,如 noreturn(函数从不返回)、format(检查格式串参数)、unused(避免未使用警告)、aligned(指定对齐方式)、packed(使用最小对齐)等。

GNU C 提供了哪些内建函数?

GNU C 提供了大量内建函数,包括标准 C 库函数的内建版本(如 memcpy)和以 __builtin 开头的函数,例如 __builtin_return_address(返回地址)、__builtin_constant_p(判断编译时常数)、__builtin_expect(提供分支预测信息)。

如何让 GCC 不使用 GNU 扩展语法?

在使用 gcc 编译时,加上 -ansi -pedantic 选项可以告诉编译器不使用 GNU 扩展语法。例如,对于使用零长度数组的代码,编译时会报警告:ISO C forbids zero-size array 'data'。

🏷️

标签

➡️

继续阅读