
3.7 技术大牛访谈——GNU C和标准C的差异
什么是GNU?GNU是GNU'S Not Unix的缩写,中文名为革奴计划,是由Richard Stall-man在1983年9月27日公开发起的,目标是创建一套完全自由的操作系统。它在编写Linux的时候自己制作了一个C语言标准,称为GNU C标准。1989年美国国家标准协会组织(ANSI)对C语言的标准重新修订,这也就是所说的标准C(C89),1990年国际标准协会ISO组织将C语言作为国际标准(C90)。这里所说的ANSI C和ISO C就是通常所指的标准C。但是GNU C和标准C是有区别的,具体区别如下。
1.GNU C支持零长度的数组
零长度的数组属于一种柔性数组,通常用在可变结构体中,主要功能是满足结构体声明以后可以动态调整结构体的大小,一般用法是在结构体内最后一行声明一个长度为0的数组,对于编译,只是在结构体内部申请了一个数组名字,因此它不占用内存空间,而且数组名字本身就是一个不可修改的地址常量,相关代码如下。


运行结果,如图3-13所示

图3-13 零长度的数组运行结果
2.GNU C特殊多分支条件语句的用法
GNU C支持switch-case语句,并且允许case后面跟着一个整型的范围。如果我们之前只接触过标准C语言的话,会明白switch-case语句中分支条件一定要是整型数,而且case后面要匹配唯一的整型常量数值。这在某些应用场合就会受到限制。

运行结果,如图3-14所示。

图3-14 case范围语句运行结果
3.GNU C支持语句表达式
GNU C把包含在括号里的复合语句看成是一个表达式,称为语句表达式,它可以出现在任何允许表达式的地方。可以在语句表达式中使用原本只能在复合语句中使用的循环变量和局部变量等,相关代码如下。

运行结果,如图3-15所示。

图3-15 语句表达式运行结果
4.GNU C支持内建函数
所谓内建函数,指的是编译器内部建立实现的函数。内建函数的使用和关键字类似,可以直接使用不需要引用任何文件,因为我们在使用GNU gcc编译器时编译器能够自动识别。内建函数的函数名通常以_builtin开头,由于内建函数主要为编译工作,其用途有以下几点。
1)可以用来处理动态变长的参数列表。
2)可以用来处理程序在运行时的告警和异常。
3)可以优化编译过程,提高代码的效率,优化硬件性能。
内建函数是编译器内部定义,主要由编译器相关的工具和程序调用,因此这些内建函数缺少文档说明,而且版本变更快。对于程序开发者来说,不建议使用这些函数。但有些函数,对于我们了解程序运行的底层信息、编译优化很有帮助,做Linux嵌入式开发经常使用这些函数,所以还是很有必要去了解Linux内核中常用的一些内建函数,相关代码如下。


运行结果,如图3-16所示。

图3-16 内建函数运行结果
此外,GNU C还支持typeof关键字、可变参数宏、标号元素以及特殊属性声明等。为什么要了解GNU C和标准C的区别呢?首先要了解标准C语言的由来,其次更重要的原因是嵌入式Linux系统开发接触内核源代码是早晚的事情,而Linux内核源代码就是由GNU C完成的,其中会有很多标准C语言无法解释的语句表达式,比如带可变参数的宏、内建函数、零数组等。所以了解GNU C和标准C语言的区别以后,再去看内核源代码就不至于摸不到头绪。