关键字
C语言的关键字有32个
类型说明保留字
关键字 | 作用 |
---|---|
int | 声明整型变量或指针 |
long | 声明整型变量或指针 |
short | 声明短整型变量或指针 |
unsigned | 声明无符号型变量 |
signed | 声明有符号型变量 |
char | 声明字符型变量或指针 |
double | 声明双精度浮点型变量或指针 |
float | 声明单精度浮点型变量或指针 |
const | 声明只读变量 |
void | 声明函数无返回值或无参数或空类型指针 |
volatile | 说明变量在程序执行中可被隐含地改变,防止编译器优化 |
- const关键字
- 便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患
void f(const int i) {} //编译器就会知道i是一个常量,不允许修改
- 可以保护被修饰的东西,防止意外的修改,增强程序的安全性,还是上面的例子,如果在函数体内修改了i,编译器就会报错;
void f(const int i) {i=10;} //error!
- 可以节省空间,避免不必要的内存分配,const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是像#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干份拷贝(注意:宏是不占内存的,但宏替换是要给变量分配内存的)
#define PI 3.14159 //常量宏
const double Pi=3.14159; //放在常量表中
double I=PI; //编译期间进行宏替换,分配内存
double j=Pi; //给出对应地址
double J=PI; //再进行宏替换,又一次分配内存!
- 编译器通常不为普通const常量分配存储空间,而是将它们保存在常量表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高,编译器也可能产生更紧凑的代码
- const声明解读
方法:将类型名去掉就是const关键字限定的内容
const a //变量a内容不可修改
const int *p = int const *p //p可以指向其他变量,p指向内容不可修改
int* const p //p不可以指向其他变量,p指向内容可以修改
const int* const p //p不可以指向其他变量,p指向内容也不可以修改
- const与define区别
- define是预编译指令,而const是普通变量的定义。define定义的宏是在预处理阶段展开的,而const定义的只读变量是在编译运行阶段使用的
- const定义的是变量,而宏定义的是常量,所以const定义的对象有数据类型,而宏定义的对象没有数据类型。所以编译器可以对前者进行类型安全检查,而对后者只是机械地进行字符替换,没有类型安全检查,这样就很容易出问题,即“边际问题”或者说是“括号问题”
- volatile关键字
volatile的本意是“易变的”, 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读脏数据。当要求使用volatile声明变量值的时候,系统总是重新从它所在的内存读取数据。精确地说就是,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,并且每次都去内存取值;如果不使用valatile,则编译器将对所声明的语句进行优化。
下面是volatile变量的几个例子:
1、并行设备的硬件寄存器
2、一个中断服务子程序中会访问的非自动变量
3、多线程应用中被几个任务共享的变量
下面是关于volatile的几个问题:
1、一个参数既可以是const还可以是volatile吗?为什么
可以,假如一个变量不希望本程序改变,通常会给它加上const,但如果该变量可能被其他程序改变而本程序又在检测这个变量的值,就需要给它加上volatile,于是变量就同时有const和volatile的双重属性
2、一个指针可以是volatile 吗?解释为什么
可以,指针也会像变量一样变化,也需要防止编译器优化
3、下面的函数被用来计算某个整数的平方,它能实现预期设计目标吗?如果不能,试回答存在什么问题:
int square(volatile int *ptr) {
return *ptr * *ptr;
}
这段代码的目的是用来返指针ptr指向值的平方,但是,由于ptr指向的是一个volatile型参数,编译器将产生类似下面的代码:
int square(volatile int *ptr) {
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果返回的可能不是平方值!正确的代码如下:
long square(volatile int *ptr) {
int a;
a = *ptr;
return a * a;
}
语句定义保留字
关键字 | 作用 |
---|---|
If | 条件语句 |
else | 条件语句的否认连枝,与if连用 |
goto | 无条件跳转语句 |
switch | 开关语句 |
case | 开关语句分止 |
do | 循环语句的循环体 |
while | 循环语句的循环条件 |
for | 一般循环语句 |
continue | 结束当前循环,进入下一轮循环 |
break | 跳出当前循环 |
return | 子程序返回语句,可带参数,也可不带 |
default | 开关语句的其他分支 |
typedef | 给数据类型取别名 |
- typedef与define区别
区别 | |
---|---|
用法 | typedef主要用来定义一种数据类型的别名,增强程序的可读性 define主要用来定义常量,以及使用频率高书写复杂的宏 |
执行时间 | typedef是编译过程中的一部分,有类型检查 define是预编译,进行字符串替换,不进行类型检查 |
作用域 | typedef有作用域限制 define没有作用域限制 |
声明 | typedef是语句,结尾要加分号 define不是语句,结尾不能添加分号 |
封装 | typedef可以看做彻底的封装,声明之后不能添加别的声明 define可以 |
typedef int banana;
unsigned banana i;//不允许
//
define banana int
unsigned banana i;//允许
存储类说明关键字
关键字 | 作用 |
---|---|
auto | 声明自动变量,缺省时默认所有变量为自动变量 |
register | 声明寄存器变量 |
extern | 声明变量从其他文件引用 |
static | 声明静态变量或函数 |
- register关键字
1、尽可能将变量放在CPU寄存器中访问,必须为单个值,且小于整型长度;
2、由于不存在于内存中,不能用&运算符 - static关键字
- 修饰局部变量,static修饰的局部变量存放在全局数据区的静态变量区,默认初始化为0,static修饰的静态局部变量只初始化一次,延长了局部变量的生命周期,直到程序运行结束以后才释放。
- 修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是extern外部声明也不可以。
- 修饰函数,这个函数的只能在本文件中调用,不能被其他文件调用
int main(){
static int a;
b = func();
c = func();
printf("%d %d %d",a, b, c);
return 0;
}
int func(void){
static int count = 10;
count--;
}
0 9 8
其他关键字
关键字 | 作用 |
---|---|
sizeof | 返回对象所占内存空间大小 |