linux内核中GNU C和标准C的区别

今天看了一下午的linux内核编程方面的内容,发现linux 内核中GNU C与标准C有一些差别,特记录如下:

linux 系统上可用的C编译器是GNU C编译器,它建立在自由软件基金会的编程许可证的基础上,因此可以自由发布。GNU C对标准C进行进一步扩展,以增强标准C的功能。下面我们对GNU 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,

};

将结构ext2_file_operations的元素 llseek 初始化为 generic_file_llseek,元素 read 初始化为 genenric_file_read,依次类推。我觉得这是 GNU C 扩展中最好的特性之一,当结构的定义变化以至元素的偏移改变时,这种初始化方法仍然保证已知元素的正确性。对于未出现在初始化中的元素,其初值为 0。

7、当前函数名

GNU CC 预定义了两个标志符保存当前函数的名字,__FUNCTION__保存函数在源码中的名字,__PRETTY_FUNCTION__保存带语言特色的名字。在 C 函数中,这两个名字是相同的,在 C++ 函数中,__PRETTY_FUNCTION__包括函数返回类型等额外信息,Linux 内核只使用了

__FUNCTION__。

void example()

{

printf{“This is function:%s”, __FUNCTION__};

}

代码中__FUNCTION__意味着字符串“example”。

8、特殊属性声明

GNU C 允许声明函数、变量和类型的特殊属性,以便手工的代码优化和更仔细的代码检查。要指定一个声明的属性,在声明后写 attribute (( ATTRIBUTE ))其中 ATTRIBUTE 是属性说明,多个属性以逗号分隔。GNU C 支持十几个属性,这里介绍最常用的:

* noreturn

属性 noreturn 用于函数,表示该函数从不返回。这可以让编译器生成稍微优化的代码,最重要的是可以消除不必要的警告信息比如未初使化的变量。例如:

# define ATTRIB_NORET __attribute__((noreturn))....

asmlinkage NORET_TYPE void do_exit(long error_code) ATTRIB_NORET;

* format

属性 format 用于函数,表示该函数使用 printf, scanf 或 strftime 风格的参数,使用这类函数最容易犯的错误是格式串与参数不匹配,指定 format 属性可以让编译器根据格式串检查参数类型。例如:

asmlinkage int printk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2)));

表示第一个参数是格式串,从第二个参数起根据格式串检查参数。

* unused

属性 unused 用于函数和变量,表示该函数或变量可能不使用,这个属性可以避免编译器产生警告信息。

* aligned

属性 aligned 用于变量、结构或联合类型,指定变量、结构域、结构或联合的对齐量,以字节为单位,例如:

struct example_struct

{

char a;

int b;

long c;

} __attribute__((aligned(4)));

表示该结构类型的变量以4字节对界。

packed

属性 packed 用于变量和类型,用于变量或结构域时表示使用最小可能的对齐,用

于枚举、结构或联合类型时表示该类型使用最小的内存。例如:

struct example_struct

{

char a;

int b__attribute__ ((packed));

long c__attribute__((packed));

};

对于结构体example_struct而言,在i386平台下,其sizeof的结果为9,如果删除其中的2个—attribute__((packed)),其sizeof将为12.

9、内建函数

GNU C 提供了大量的内建函数,其中很多是标准 C 库函数的内建版本,例如memcpy,它们与对应的 C 库函数功能相同,不属于库函数的其他内建函数的名字通常以 __builtin开始。例如:

__builtin_return_address (LEVEL)

内建函数 __builtin_return_address 返回当前函数或其调用者的返回地址,参数 LEVEL 指定在栈上搜索框架的个数,0 表示当前函数的返回地址,1 表示当前函数的调用者的返回地址,依此类推。

__builtin_constant_p(EXP)

内建函数 __builtin_constant_p 用于判断一个值是否为编译时常数,如果参数EXP 的值是常数,函数返回 1,否则返回 0。

__builtin_expect(EXP, C)

内建函数 __builtin_expect 用于为编译器提供分支预测信息,其返回值是整数表

达式 EXP 的值,C 的值必须是编译时常数。

例如,下面的代码检测第一个参数是否为编译时常数以确定采用参数版本还是非参数版本代码:

#define test_bit(nr,addr) \

(__builtin_constant_p(nr) ? \

constant_test_bit((nr),(addr)) : \

variable_test_bit((nr),(addr)))

标签:__,case,函数,GNU,参数,内核,file,linux

来源: https://www.cnblogs.com/muahao/p/10344382.html

linux标准c和c编译器6,linux内核中GNU C和标准C的区别相关推荐

  1. linux标准c和c编译器6,Linux折腾记(六):感悟GNU C及把Vim打造成C/C++的半自动化IDE...

    C语言在Linux系统中的重要性自然是无与伦比.不可替代,所以我写Linux江湖系列不可能不提C语言.C语言是我的启蒙语言,感谢C语言带领我进入了程序世界.虽然现在不靠它吃饭,但是仍免不了经常和它打交 ...

  2. linux看缺省的编译器,修改Linux系统默认编辑器

    pip和requests模块的安装 1.配置python的环境变量 在path中加入pyhton的环境变量,如我的是E:\Python27 2. 如果没有pip,一个帮助软件管理的东东(现在的版本一般 ...

  3. L52.linux命令每日一练 -- 第八章 Linux磁盘与文件系统管理命令 -- resize2fs和fsck

    8.7 resize2fs:调整ext2/ext3/ext4文件系统大小 8.7.1 命令详解 ​ [命令星级] ★★★★☆ ​ [功能说明] ​ resize2fs命令用于扩容或收集未挂载的ext2 ...

  4. GNU C 对标准C语言的扩展(转载 懵懵懂懂)

    GNU C 对标准C语言的扩展 为了方便使用,GNU C在标准C语言的基础上进行了部分方便开发的扩展.这里讲解一些开发中可能会用到的,或者使用频率比较高的内容. 1 零长度数组和变量长度数组 GNU ...

  5. VB中窗体模块、标准模块、类模块的区别

    VB的代码存储在模块中.在VB中提供了三种类型的模块:窗体模块.标准模块和类模块. 简单的应用程序可以只有一个窗体,所用的程序都驻留在窗体模块中,而当应用程序庞大复杂时,就要另外附加窗体.最终可能有几 ...

  6. vs linux 交叉编译,Visual Studio交叉编译器提供对ARM的支持

    只要ARM平台能够运行Windows,Visual Studio就有能力拓展ARM平台.在Visual Studio 2017 15.5预览版2中,该IDE通过使用GCC编译器,增加了对基于ARM的计 ...

  7. linux6.3支持gcc版本,Linux编程中GCC对C++标准支持和如何选择GCC版本使用

    关注公众号cpp_coder,学习更多实用技术. [说明]本公众号纯属于个人,没有商业运作.推送文章是C++技术网原创文章,供大家学习.希望大家多多支持,多多推荐.我们所有的推送,没有收入一分钱,只是 ...

  8. 【CentOS Linux 7】【gcc编译器】

    Linux系统及应用---调研报告 [CentOS Linux 7]实验1[VMware安装.新建虚拟机:63个基础命令运行结果图] [CentOS Linux 7]实验2[Shell编程及应用] [ ...

  9. 【Linux03-基本工具之GCC】Linux下的C语言编译器

    前言 接上篇,继续学习基本工具. 三.gcc 是什么 Linux下的C语言编译器(C++的编译器是g++,用法选项基本一样). 既然是编译器,我们就再来加点餐-- 链接其实分为两种类型:静态链接和动态 ...

最新文章

  1. 正确修改MySQL最大连接数的三种好用方案
  2. PyCharm与git/GitHub取消关联
  3. linux鉴于它没有文件拓展名,linux中的文件类型以及查看文件类型的方法
  4. thinkphp gd 添加文字
  5. UE4学习-第三人称游戏的AI巡逻
  6. maven 热部署 web应用
  7. html5基础--audio标签元素
  8. 中国金融体系主要指标大全!
  9. 第六章节 三层架构(二. 模型层与数据访问层)
  10. java的启动信息_Java实现软件运行时启动信息窗口的方法
  11. BAT、360、网易等大公司开源项目
  12. 基于android的手机商城app
  13. csgo 机器人模式_csgo怎么加机器人
  14. 谷粒学院P21所需的maven jar包
  15. C#如何在Windows上接入蓝牙设备
  16. 使用C++,Python,Matlab进行facial 68 points landmarks
  17. 深圳市林享科技有限公司
  18. 编写一个python程序判断用户输入的8位银行卡_用Python编写的程序,提示用户输入一个由7位数字组成的帐号?...
  19. 漫画:什么是 “幼态持续” ?
  20. Liunx下Qos功能实现简析

热门文章

  1. 合并多个文本文件方法
  2. Linux之静态库与动态库20160706
  3. 利用max-height适应多尺寸屏幕的下拉动画
  4. 自己写 localtime 函数(含完整注释,代码)转载
  5. PE格式详细讲解1 - 系统篇01|解密系列
  6. 在WinForm中通过HTTP协议向服务器端上传文件(转)
  7. Nebula3的Input系统
  8. 关于类模板怎么用的简单介绍
  9. 华为的发展与管理浅析
  10. lib(静态库)和dll(动态库)的生成和使用详细说明以及注意事项