C语言中的const修饰符用于修饰一个变量是const属性的。被C语言的const修饰的变量具备只读属性,而且不能被修改。html
const修饰的变量 != 常量,const修饰的变量虽然不能别修改,可是和常量仍是有本质的区别的。数组
在定义const类型的变量的时候,必须进行初始化,固然,在const做为函数的参数的时候,是不须要初始化的。函数
编译器一般不为普通const 只读变量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的值,没有了存储与读内存的操做,使得它的效率也很高。优化
const 定义的只读变量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define同样给出的是当即数,因此,const定义的只读变量在程序运行过程当中只有一份拷贝(由于它是全局的只读变量,存放在静态区),而#define定义的宏常量在内存中有若干个拷贝。#define宏是在预编译阶段进行替换,而const修饰的只读变量是在编译的时候肯定其值。#define宏没有类型,而const修饰的只读变量具备特定的类型。网站
typedef struct student { /*code*/ }Stu_st,*Stu_pst; 1)const Stu_pst stu3; 2)Stu_pst const stu4;
对于定义的stu3 和stu4,它们的类型同样吗?答案是同样的。为何?this
在这里咱们不能想固然的认为typedef和#define同样,直接进行展开。实际上,由于const修饰的都是变量自身,const对变量进行修饰的时候,不考虑类型,也就是说1)和2)中的typedef类型都被认为是一个类型,而不是被展开。因此上述就至关因而:spa
const type var
type const var操作系统
也就是说,const修饰的是变量var。线程
volatile 关键字和const 同样是一种类型修饰符,用它修饰的变量表示能够被某些编译器未知的因素更改,好比操做系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就再也不进行优化,从而能够提供对特殊地址的稳定访问。code
柔性数组又称为0长数组(zero-length arrays),这是C99加进去的一个特性。能够这样定义一个柔性数组:
struct line { int length; char contents[]; }; struct line *thisline = (struct line *) malloc (sizeof (struct line) + this_length); thisline->length = this_length;
在ISO C90中,在定义一个相似于柔性数组(在C90标准中尚未柔性数组的概念)的结构体成员的时候,contents[]在定义的时候须要定义成这样:contents[0],其中的0是必须的。
在ISO C99中,能够直接在结构体中定义一个自由数组成员,自由数组的语法以下:
关于GCC对柔性数组的支持,能够访问这个网站:http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html#Zero-Length
对于这样一个表达式:
a+++b
到底表示的是什么呢?是a+ (++b)仍是(a++) +b?这个就须要考虑C语言在语法分析的时候是以什么方式解析的。
在C语言的编译器进行语法分析的时候,使用的是贪心法则。也就是说在处理表达式的时候,若是当前的字符能够和前一个字符串组成一个有意义的符号,则继续读入下一个字符,直到没法组成一个有意义的字符。
也就说对于上述的表达式,在解析到a+后碰到了+,这个时候,因为a++在C语言中是合法的,那么它继续处理下一个+,因为a+++在C语言中是非法的,那么就不把+做为表达式的一部分,也就说上述的表达式就被解析为:(a++) + b。
在编译的时候可使用的一些指令,用于在编译的时候输出一些有用的信息,便于追踪编译过程,以及控制编译。
#line //改变当前的行数和文件名称,基本语法以下:#line number["filename"] #error //编译程序时,若是遇到#error就会产生一个编译错误提示信息,并中止编译。
编译器在编译过程预约义了一些宏,用于输出一些编译过程的信息:
_LINE_ //编译器正在编译的行号 _FILE_ //编译器正在变异的文件名 _TIME_ //编译的时间 _STDC_ //判断该文件是否是定义成标准C程序
参考:《C语言深度剖析》