1.3、static关键字
a) 静态全局变量:作用域仅限于变量被定义的文件中,其他文件即使使用extern声明也没法使用它。
b) 静态局部变量:作用域仅限于定义该局部变量的函数,同一文件中的其他函数也用不了。
c) 静态函数:作用域仅限于本文件,使用内部函数的好处是不同的人编写不同的函数时,不用担心自己定义的函数是否会与其他文件中的函数同名。
1.5、sizeof关键字
sizeof是关键字不是函数,在计算变量所占空间大小时,括号可以省略,而计算类型大小时不能省略。且一般情况下,sizeof是在编译时求值,所以sizeof(i++)不会引起副作用,所以sizeof操作符里面不要有其他运算,否则不会达到预期目的。
在C99中,计算柔性数组所占空间大小时,sizeof是在运行时求值,此为特例。
1.6、signed、unsigned关键字
单纯的char类型应该只用于字符值的存储和使用;有符号和无符号的“char”型变量只能用于数值的存储和使用。
char有三种不同类型:单纯char、signed char及unsigned char。signed char和unsigned char类型是用来声明数值的;单纯char类型是真正的字符类型,是用来声明字符的。单纯char类型由编译环境决定,不能依赖。对于单纯char类型,唯一允许的操作是赋值和相同运算符(=,==,!=)。
signed char范围:-128~128
unsigned char范围:0~255
1.7、if、else组合
a) bool类型
C语言在C89标准中是没有bool类型定义的,但在C99标准中增加了bool关键字, 只要包含stdbool.h头文件,就可以在C语言中C++中一样使用bool类型,true表 示真,false表示假。
b) else始终与同一括号内最近的未匹配if语句结合。
c) 真正需要用空语句写成:NULL;
d) 如果把执行概率更大的代码入到后面,也就意味着if语句将进行多次无谓的比较。另外非常重要的一点是,把正常情况的处理放在if后面,而不是放在else后面。
e) 所有的if-else if结构应该由else子句结束。对最后的else语句的要求是保护性编程。Else语句或者要执行适当的动作,或者包含合适的注释以说明为何没有执行动作。这与switch语句中要求具有最后一个default子句是一致的。
1.8、switch、case组合
分支很多的时候用switch、case组合,在switch、case组合中,禁止使用return语句,switch表达式不应是有效的布尔值。
case后面只能是整型或字符型的常量或常量表达式,case语句的排列顺序要遵循下面规则:按字母或数字顺序排列各条case语句;把正常情况放在前面,异常情况放在后面;按执行频率排列case语句
老老实实的把每一种情况都用case语句来完成,而把真正默认情况的处理交给default字句来完成。
1.9、do、while、for关键字
a) 在多重循环中,如果可能,应当将最长的循环放在最内层,最短的循环放大最外层,以减少CPU跨切循环层的次数。底层原因:外层循环次数决定内层循环因子的赋值次数,这个赋值在编译成汇编时占用一条汇编指令,如x86汇编的mov指令,短循环放在外层可在循环次数比较大时显著减少执行时间。
1.11、void关键字
按照ANSI标准,不能对void指针进行算法操作,但GNU则不这么认为,它指定void 的算法操作与char 一致。
void不能代表一个真实的变量,因为定义变量时必须分配内存空间
1.12、return关键字
return语句不能返回指向“栈内存”的“指针”,因为该内存在函数体结束时被自动销毁。
1.13、const关键字
编译器通常不为普通const只读变量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的值,没有了存储与讲读内存的操作,使得它的效率也很高。
1.14、volatile关键字
volatile修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其他线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码不再进行优化,从而可以提供对特殊地址的稳定访问。
1.15、extern关键字
extern关键字可以置于变量或函数前,以表明变量或函数的定义在别的文件中,下面代码用到的变量或函数是外来的,不是本文件定义的,提示链接器遇到此变量和函数时在其他模块中解析/绑定此标识符。
1.16、柔性数组
C99中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员,但结构中的柔性数组成员前面必须至少有一个其他成员。可以用访问普通结构体成员的方式访问柔性数组,但柔性数组算不得结构体的正式成员。柔性数组只能形如int item[],如
typedef struct st_type
{
int i;
int item[];
} type_a;
而int item[0]的形式是非法的,但有些编译器把int item[0]作为非标准扩展来支持。
sizeof返回的这种结构大小不包括柔性数组的内存。包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
type_a *p =
(type_a *)malloc(sizeof(type_a) + 100*sizeof(type_a));
为柔性数组动态分配内存后,再用sizeof(*p)测试结构体的大小时会发现仍然为4。
1.17union关键字
union主要用来压缩空间。如果一些数据不可能在同一时间同时被用到,则可以使用union。
利用union联合体确认当前系统的存储模式:
int checkSystem()
{
union {
int i;
char ch;
} c;
c.i = 1;
return (ch.ch == 1);
}
若是Big_endian的,则返回0;若是Little_endian,则返回1。
1.18、enum关键字
枚举与#define宏的区别:
a)、#define宏常量是在预编译阶段进行简单替换;枚举常量则是在编译时候确定其值。
b)、一般在调试器里,可以调试枚举常量,但是不能调试宏常量。
c)、枚举可以一次定义大量相关的常量,而#define宏一次只能定义一个。
1.19、typedef关键字
typedef的真正意思是给一个已经存在的数据类型(注意:是类型不是变量)取一个别名,而非定义一个新的数据类型。
a)、typedef和const放在一起的时候:
typedef struct student {
//code
}Stu_st, *Stu_pst;
(C)const Stu_pst stu3;
(D)Stu_pst const stu3;
(C)和(D)中const修饰的都是stu3这个指针,因为对于编译器来说,只认为Stu_pst是一个类型名。
b)、typedef与#define的区别
(E) #define INT32 int
unsigned INT32 i = 10;
(F) typedef int int32;
unsigned int32 i = 10;
其中(F)编译的时候会出错,因为typedef取的别名不支持这种类型扩展。另外,typedef static int int32在编译时也会出错。