GNU C是什么?GNU C建立在自由软件基金会的编程许可证的基础上 , 因此可以自由发布 。GNU C对标准C进行进一步扩展 , 以增强标准C的功能 。
特别是嵌入式软件开发过程中 , 经常会遇到很多GNU C的语法 , 以为是C语言没学过关 , 其实很多都不是标准C语言中的语法 。哈哈!
扩展差异1、零长度数组
GNU C 允许使用零长度数组 , 在定义变长对象的头结构时 , 这个特性非常有用 。例如:
struct minix_dir_entry { __u16 inode; char name[0];};
结构的最后一个元素定义为零长度数组 , 它不占结构的空间 。在标准 C 中则需要定义数组长度为 1 , 分配时计算对象大小比较复杂 。
2、case范围
GNU C 允许在一个 case 标号中指定一个连续范围的值 , 例如:
case '0' ... '9': c -= '0'; break; case 'a' ... 'f': c -= 'a'-10; break; case 'A' ... 'F': c -= 'A'-10; break;
其中case '0' ... '9': 相当于 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
3、语句表达式
GNU C 把包含在括号中的复合语句看做是一个表达式 , 称为语句表达式 , 它可以出现在任何允许表达式的地方 , 你可以在语句表达式中使用循环、局部变量等 , 原本只能在复合语句中使用 。例如:
#define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
复合语句的最后一个语句应该是一个表达式 , 它的值将成为这个语句表达式的值 。这里定义了一个安全的求最小值的宏 , 在标准 C 中 , 通常定义为:
#define min(x,y) ((x) < (y) ? (x) : (y))
这个定义计算 x 和 y 分别两次 , 当参数有副作用时(比如出现参数自增或自减语句时) , 将产生不正确的结果 , 使用语句表达式只计算参数一次 , 避免了可能的错误 。语句表达式通常用于宏定义 。
4、typeof关键字
使用前一节定义的宏需要知道参数的类型 , 利用 typeof 可以定义更通用的宏 , 不必事先知道参数的类型 , 例如:
#define min(x,y) ({ const typeof(x) _x = (x); const typeof(y) _y = (y); (void) (&_x == &_y); _x < _y ? _x : _y; })
这里 typeof(x) 表示 x 的值类型 , const typeof(x) _x = (x); 中定义了一个与 x 类型相同的局部变量 _x 并初使化为 x , (void) (&_x == &_y); 的作用是检查参数 x 和 y 的类型是否相同 。typeof 可以用在任何类型可以使用的地方 , 通常用于宏定义 。
5、可变参数的宏
在 GNU C 中 , 宏可以接受可变数目的参数 , 就象函数一样 , 例如:
#define pr_debug(fmt,arg...) printk(fmt,##arg)
这里 arg 表示其余的参数 , 可以是零个或多个 , 这些参数以及参数之间的逗号构成 arg 的值 , 在宏扩展时替换 arg , 例如:
pr_debug("%s:%d",filename,line)
会被扩展为
printk("%s:%d", filename, line)
使用 ## 的原因是处理 arg 不匹配任何参数的情况 , 这时 arg 的值为空 , GNU C 预处理器在这种特殊情况下 , 丢弃 ## 之前的逗号 , 这样
pr_debug("success!n")
会被扩展为
printk("success!n")
而不是printk("success!n" , )
注意最后的逗号 。
6、标号元素
标准 C 要求数组或结构变量的初使化值必须以固定的顺序出现 , 在 GNU C 中 , 通过指定索引或结构域名 , 允许初始化值以任意顺序出现 。指定数组索引的方法是在初始化值前写 '[INDEX] =' , 要指定一个范围使用 '[FIRST ... LAST] =' 的形式 , 例如:
static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
将数组的所有元素初使化为 ~0UL , 这可以看做是一种简写形式 。
要指定结构元素 , 在元素值前写 'FIELDNAME:' , 例如:
struct file_operations ext2_file_operations = { llseek: generic_file_llseek, read: generic_file_read, write: generic_file_write, ioctl: ext2_ioctl, mmap: generic_file_mmap, open: generic_file_open, release: ext2_release_file, fsync: ext2_sync_file, };
推荐阅读
- 如何在windows7和 win10电脑上添加删除静态路由
- 洛神花和玫瑰花,洛神花和玫瑰花能起泡吗
- 玳玳花和玫瑰花陈皮,玳玳花的功效
- 河南省取暖费补贴标准是怎样的?
- 红茶普洱茶等都适宜,普洱茶和速溶红茶功效与作用的区别
- 黄瓜|长期化妆和素颜的人,有什么不同?
- 花茶怎么搭配好喝,花茶怎么搭配喝
- 洛神花功效作用和效果,洛神花的功效与作用
- 水荠菜和荠菜的区别
- 七月菊苗,七月菊花茶和十月菊花茶有什么不同