1、C语言所有关键字(含C99新增的5个)
2、各个关键字简要说明
auto声明自动变量,缺省时编译器一般默认为auto
int声明整型变量
double声明双精度变量
long声明长整型变量
char声明字符型变量
float声明浮点型变量
short声明短整型变量
signed声明有符号类型变量
unsigned声明无符号类型变量
struct声明结构体变量
union声明联合数据类型
enum声明枚举类型
static声明静态变量
switch用于开关语句
case开关语句分支
default开关语句中的“其他”分支
break跳出当前循环
register声明寄存器变量
const声明只读变量
volatile说明变量在程序执行中可被隐含地改变
typedef用以给数据类型取别名(当然还有其他作用)
extern声明变量
return子程序返回语句(可以带参数,也可不带)
void声明函数无返回值或无参数,声明空类
continue结束当前循环,开始下一轮循环
do循环语句的循环体
while循环语句的循环条件
if条件语句
else条件语句否定分支(与if连用)
for一种循环语句(可意会不可言传)
goto无条件跳转语句
sizeof计算对象所占内存空间大小
3、重点关键字详细说明
3.1 auto,register,extern,static说明四种存储类别
3.1.1 auto
auto是变量是C语言最常用的。编译器在默认的缺省情况下,所有变量都是auto的。对于函数的形参,也是auto型的。
3.1.2.extern
语言中存在这样的一种变量,在一个函数中合法出现的同时,又可以在其他的函数中合法出现,这就是外部变量。它的生命周期是整个程序的执行周期。
3.1.3.register
寄存器变量,其值存放在寄存器中,访问速度快。有最快的关键字的称呼。虽然寄存器的速度非常快,但是使用register修饰符也有些限制的:register变量必须是能被CPU寄存器所接受的类型。意味着register变量必须是一个单个的值,并且其长度应小于或等于整型的长度。而且register变量可能不存放在内存中, 所以不能用取址运算符 “&”来获取register变量的地址。
3.1.4.static
静态变量,两个作用。第一个作用:修饰变量,都存在内存的静态区。
静态局部变量:出现在函数体内,生命周期是整个程序的执行过程,由于被static修饰的变量总是存在内存的静态区,即使该函数生命结束,其值不会被销毁,同样要修改该变量,就要到函数内部完成,所以用起来比较安全,起到信息屏蔽的作用。
静态全局变量:出现在函数体外,作用域仅限于变量被定义的文件中,其他文件即使用extern声明也没法使用他。
第二个作用,修饰函数,函数前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。
3.2 struct声明结构体变量,union声明联合数据类型
3.2.1 结构体
struct:内部成员各自拥有自己的内存互不干涉,按照定义的先后顺序存放,一个struct的总长度等于所有成员长度之和。
1)结构体变量的首地址能够被其对齐字节数的大小所整除
2)结构体每个成员相对结构体首地址的偏移都是成员大小的整数倍,如不满足,对前一个成员填充字节以满足
3)结构体的总大小为结构体对最大成员大小的整数倍,如不满足,最后填充字节以满
struct u4{int a,short b,char c}U5, struct u5{char b, int a ,short c}U6,sizeof(U5)=8,sizeof(U6)=12
U5中a四个字节,后面b和c加起来3个字节,正好补1个字节对齐;U6中b1个字节,要和后面的a对齐,需要补3个字节对齐,c也要补1个字节对齐,因而最终U6为12个字节。另外,要想改变这种默认对齐设置,可以用#pragma pack (2) /*指定按2字节对齐*/#pragma pack () /*取消指定对齐,恢复缺省对齐*/
3.2.2 联合体
union:各成员共用一块内存空间,并且同时只有一个成员可以得到这块内存的使用权(对该内存的读写),各变量共用一个内存首地址。因而,联合体比结构体更节约内存。一个union变量的总长度至少能容纳最大的成员变量,而且要满足是所有成员变量类型大小的整数倍。不允许对联合体变量名U2直接赋值或其他操作。
union u2 {char a, int b ,short c, double d,int e[5]} U3 sizeof(U3)=24
大端模式(Big_endian):字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中。
小端模式(Little_endian):字数据的高字节存储在高地址中,而字数据的低字节则存放在低地址中。
例子:
#include
union var{
char c[4];
int i;
};
int main(){
union var data;
data.c[0] = 0x04;//因为是char类型,数字不要太大,算算ascii的范围~
data.c[1] = 0x03;//写成16进制为了方便直接打印内存中的值对比
data.c[2] = 0x02;
data.c[3] = 0x11;//数组中下标低的,地址也低,按地址从低到高,内存内容依次为:04,03,02,11。总共四字节!
//而把四个字节作为一个整体(不分类型,直接打印十六进制),应该从内存高地址到低地址看,0x11020304,低位04放在低地址上。
printf("%x\n",data.i);
}
结果:
11020304
3.3 sizeof
sizeof 是关键字不是函数,sizeof 在计算变量所占空间大小时,括号可以省略,而计算数据类型大小时不能省略。
3.3.1 为什么在32位的计算机中,指针占4个字节。同理,在64位的计算机中,指针占8个字节
我们平时所说的计算机是64位、32位、16位,指的是计算机CPU中通用寄存器一次性处理、传输、暂时存储的信息的最大长度。即CPU在单位时间内(同一时间)能一次处理的二进制数的位数。假如,某计算机的地址总线是32位,那么其一次可以处理的信息是32条,每一条地址总线有0或1两种可能,那么32根地址总线一共有232种可能,也就是其描述的地址空间为0x0000 0000 0000 0000 ~ 232-1。所以32位系统一般需要32个0或1的组合就可以找到内存中所有的地址,而32个0或1的组合,就是32个位,也就是4个字节的大小,我们只需要4个字节就可以找到所有的数据。
3.4 volatile
volatile 是易变的、不稳定的意思。volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改。volatile 提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有 volatile 关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。所以遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
volatile关键字应用场景:
1)并行设备的硬件寄存器(如:状态寄存器)
存储器映射的硬件寄存器通常也要加 voliate,因为每次对它的读写都可能有不同意义。
2)中断服务程序中修改的供其它程序检测的变量,需要加volatile;
3)多任务环境下各任务间共享的标志,应该加volatile;
4)存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;
3.5 inline
内联:当编译器发现某段代码在调用一个内联函数时,它不是去调用该函数,而是将该函数的代码,整段插入到当前位置。这样做的好处是省去了调用的过程,加快程序运行速度。内联函数的本质是,节省时间但是消耗空间。
3.5.1 inline函数的规则
(1)一个函数可以自已调用自已,称为递归调用(后面讲到),含有递归调用的函数不能设置为inline;
(2)使用了复杂流程控制语句:循环语句和switch语句,无法设置为inline;
(3)由于inline增加体积的特性,所以建议inline函数内的代码应很短小。最好不超过5行。
(4)inline仅做为一种“请求”,特定的情况下,编译器将不理会inline关键字,而强制让函数成为普通函数。出现这种情况,编译器会给出警告消息。
(5)在你调用一个内联函数之前,这个函数一定要在之前有声明或已定义为inline,如果在前面声明为普通函数,而在调用代码后面才定义为一个inline函数,程序可以通过编译,但该函数没有实现inline。
(6)为了调试方便,在程序处于调试阶段时,所有内联函数都不被实现。
3.5.2 使用内联函数时应注意以下几个问题
(1) 在一个文件中定义的内联函数不能在另一个文件中使用。它们通常放在头文件中共享。
(2) 内联函数应该简洁,只有几个语句,如果语句较多,不适合于定义为内联函数。
(3) 内联函数体中,不能有循环语句、if语句或switch语句,否则,函数定义时即使有inline关键字,编译器也会把该函数作为非内联函数处理。
(4) 内联函数要在函数被调用之前声明。关键字inline 必须与函数定义体放在一起才能使函数成为内联,仅将inline 放在函数声明前面不起任何作用。
3.6 typedef
类型重定义,定义变量时如果前面加入typedef那么变量名就变成了这种类型(注意:不是替换关系)
3.7 continue
结束当前这一次循环 ,进入下一次循环
例子: 正常s等于10 但因为在i等于5的时候遇到了continue 后面语句不执行了 少+了一次 最后等于9
int i,s=0;
for(i=0;i<10;i++){
if(5==i)
continue;
s++;
}
printf("%d",s);
3.8 goto
无条件跳转语句 ,可以实现在函数内任意跳转 ,但不建议使用。 太灵活了,导致别人很难理解代码,且出错了很难找到。但是它在驱动编程时特别适合处理异常。