Linux入门学习教程:GNU C及将Vim打造成C/C++的半自

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

  Linux系统中普遍使用的是GNU-C,这里有一份Gnu-C语言手册.pdf,下载地址:。

------------------------------------------分割线------------------------------------------

免费下载地址在

用户名与密码都是

具体下载目录在 /2015年资料/3月/2日/Linux入门学习教程:GNU C及将Vim打造成C&C++的半自动化IDE/

下载方法见

------------------------------------------分割线------------------------------------------

The GNU C Reference Manual的主页在这里:。C语言的内核极其紧凑,该手册总共只有91页,去掉目录、附录和索引后就只有70页。我一般一个多小时就可以将其从头至尾复习一遍。我曾有过将其翻译成中文的想法,后来还是放弃了。翻译这种字斟句酌的事情还是让别人来干吧。我只写写我自己的感悟。

感悟一:C语言标准干不过GNU扩展

  最近为了研究X Window的底层协议,开始尝试使用XCB编程。当我打开XCB的头文件的时候,我被大量的__restrict__关键字惊呆了,好在有GNU C语言手册为我答疑解惑。__restrict__又是一个GNU扩展的关键字,后面我会详细讲解该关键字的用途。其实C语言的C99标准中已经引入了restrict关键字,没有前后的下划线,但是在大量的开源代码中,使用最普遍的还是GNU的扩展,而不是C语言标准。

  和restrict关键字有相同命运的还有inline、_Complex等,它们都是在C99标准中引入的关键字,但是其实在C99标准出来之前,GNU C中早就有了__inline__、__complex__等扩展关键字。还记得多年前我学习Linux 0.11版的源代码时,看到大量的__inline__曾经疑惑不已,不知道为什么Linus在91年就能用上了如此先进的语言功能,后来才知道,这是GNU的扩展关键字。

  C语言的标准有C89和C99,使用GCC的时候甚至要显示指定-std=c99才能全面支持C99标准,所以在开源界,大家还是喜欢首选GNU的扩展关键字。比如__inline__、__complex__和__restrict__。总而言之,C语言标准干不过GNU扩展。

  下面来看看__restrict__的真正含义。载过一篇文章《为什么有些语言会比别的快》,其中提到“很长一段时间,相同的两个程序在Fortran和C(或者C++)中运行,Fortran会快一些,因为Fortran的优化做的更好。这是真的,就算C语言和Fortran的编译器用了相同的代码生成器也是一样。这个不同不是因为Fortran的某种特性,事实上恰恰相反,是因为Fortran不具备的特性。”这是因为C语言中的指针给编译器的优化带来了困难,文章中继续说道:“问题就来了。这些指针可以代替任何内存地址。更重要的是,他们可以重叠。输出数组的内存地址也可以同时是输入数组的。甚至可以部分重叠,输出数组可以覆盖一个输入数组的一半。这对编译器优化来说是个大问题,因为之前基于数组的优化不再适用。特别的,添加元素的顺序也成问题,如果输出重叠的数组,计算的结果会变得不确定,取决于输出元素的动作是发生在元素被覆盖之前还是之后。”

  有了__restrict__,C语言的该问题将不复存在。用__restrict__修饰一个指针后,①该指针只能在定义的时候被初始化;②不会再有别的指针指向该指针指向的内存,因此编译器可以对算法进行优化。如下代码:

int * __restrict__ p = (int*)malloc(100*sizeof(int));

指针p有__restrict__关键字修饰,所以它只能在定义的时候被初始化,以后不能赋值,而没有__restrict__修饰的指针,可以随时赋值,如下:

int arr[100]; int* pArr; pArr = arr;

指针pArr没有被__restrict__关键字修饰,所以可以将数组的首地址赋值给它。

  比如我们定义一个函数对两块数据进行操作,结果放入第3块内存,如下:

void func1(void* p1, void* p2, void* p3, int size){ for(int i=0; i<size; i++){ p3[i] = p1[i] + p2[i]; } }

很显然,由于编译器没办法判断指针p1、p2、p3指向的内存是否重叠,所以无法进行优化,加上__restrict__关键字后,如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/16706.html