编程珠玑之关键字(1)--《c语言深度剖析》整理(转)
一、最快关键字register
关键字regiter请求编译器尽可能的将变量存在CPU的寄存器中。有几点注意的地方。
1、register变量必须是能被CPU寄存器所接受的类型,这通常意味着register变量必须是一个单个的值,并且其长度应小于或等于整型的长度。
但是,有些机器的寄存器也能存放浮点数。
2、register变量可能不存放在内存中,所以不能用取址符运算符“ & ”。
3、只有局部变量和形参可以作为register变量,全局变量不行。
4、静态变量不能定义为register。
总结:寄存器变量不是越多越好,当寄存器变量的个数超过寄存器的数目的时候,寄存变量也就退化为放到内存中。因此寄存器变量应用较少。
二、static作用
1. 修饰变量
(1) 限定变量的作用域: (存放于文件的静态区中)
本文件中:
静态全局变量:作用域从变量定义开始处到文件结束(本文中在定义之前引用此变量也要加extern)
静态局部变量:作用域限于定义的函数中
工程文件中: 仅限本文件中,其他的文件的不能引用此变量
(2) 生命周期:
从程序启动直至程序结束。
2. 修饰函数
限定函数的作用域为本文件中,其他的文件不能引用此函数
三、最容易混淆的关键字sizeof(本人之前一直以为sizeof是函数 惭愧)
事实证明 sizeof是关键字,如下:
int i=0;
A),sizeof(int); B),sizeof(i); C),sizeof int; D),sizeof i;
此处四种用法第三种是错误的 ,由此可见sizeof 是关键字
关于sizeof的 一些用法习题:
int *p = NULL;
sizeof(p)——
sizeof(*p)——
int a[100];
sizeof (a) ——
sizeof(a[100])——
sizeof(&a)——
sizeof(&a[0])——
int b[100];
void fun(int b[100])
{
sizeof(b);// sizeof (b) ——
}
答案: 4 4 400 4 4 4 4
四、 bool, float , 指针类型与零值的比较
1. bool类型的值与0比较
A), if(bTestFlag == 0); if(bTestFlag == 1);
B), if(bTestFlag == TRUE); if(bTestFlag == FLASE);
C), if(bTestFlag); if(!bTestFlag);
解析:
A :可读性比较差,不知道bTestFlag变量的类型,误以为是整形
B:不同的编译器,true值的定义不同:Visual C++定义为1,而Visual Basic 就把TRUE 定义为-1
C:规范 编译器中0 为false 非零为true
2. float 与 0 比较
float fTestVal = 0.0;
A), if(fTestVal == 0.0); if(fTestVal != 0.0);
B), if((fTestVal >= -EPSINON) && (fTestVal <= EPSINON)); //EPSINON 为定义好的精度。
解析:float 在计算机存储有精度限制,与0,与具体的浮点数直接比较都是不准确的,所以B的定义较好。[0.0-EPSINON,0.0+EPSINON] 当然EPSINON范围不能过大
3. 指针变量与0 比较
int* p = NULL;//定义指针一定要同时初始化,指针与数组那章会详细讲解。
A), if(p == 0); if(p != 0);
B), if(p); if(!p);
C) , if(NULL == p); if(NULL != p);
解析:A 容易和int 类型的想混淆;B 容易和bool类型想混淆(可读性比较差)
五、c语言中的空语句的写法
1) ;
2) NULL;
六、switch 关键字
switch关键字使用注意事项:
1) case 后面变量: 整形或字符型或者常量表达式(可以跟const类型修饰的变量,比如const int KEY = 1)
2) 每个case 后面必须接break ,除非集中case的叠加(但case 后面绝对不可以跟continue,continue 用于循环中)
3) deflaut 后面应用于异常情况的处理,不应将自己的case 最后一种情况介于default 之后,降低程序的容错性
七、const 修饰只读变量
1. const 修饰的变量 是只读的,变量的值不可以改变,变量存在于符号表中,没有了存储与读内存的操作;
#define M 3 //宏常量
const int N=5; //此时并未将N 放入内存中
......
int i=N; //此时为N 分配内存,以后不再分配!
int I=M; //预编译期间进行宏替换,分配内存
int j=N; //没有内存分配
int J=M; //再进行宏替换,又一次分配内存!
2. const 修饰的变量定义的时候必须初始化
3、const 修饰的变量是编译器变量,define 定义的变量是预编译期变量
4、const 修饰的变量和define修饰的变量的区别
(1)const 定义的只读变量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数
(2)const 定义的只读变量在程序运行过程中只有一份拷贝(因为它是全局的只读变量,存放在静态区),而#define 定义的宏常量在内存中有若干个拷贝。
(3)#define 宏是在预编译阶段进行替换,而const 修饰的只读变量是在编译的时候确定其值
(4)#define 宏没有类型,而const 修饰的只读变量具有特定的类型。
5. const 修饰指针
const int *p; // p 可变,p 指向的对象不可变
int const *p; // p 可变,p 指向的对象不可变
int *const p; // p 不可变,p 指向的对象可变
const int *const p; //指针p 和p 指向的对象都不可变
八、最异变的关键字volatile
volatile 修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优 化,从而可以提供对特殊地址的稳定访问;
九、struct
1、空结构体的大小
struct A
{
}aa;
sizeof(aa) 结果等于 1
2. 柔性数组
typedef struct A
{
int i;
int a[];
}aa;
sizeof(aa) 等于 4,可见结构的体中的柔性数组的大小是0,不占结构体的空间,仿佛不是结构的体得一部分;
十、union
存储模式:大端模式和小端模式。
大端模式(Big_endian):字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中。
小端模式(Little_endian):字数据的高字节存储在高地址中,而字数据的低字节则存放在低地址中。
union 型数据所占的空间等于其最大的成员所占的空间。对union 型的成员的存取都是相对于该联合体基地址的偏移量为0 处开始,也就是联合体的访问不论对哪个变量的存 取都是从union 的首地址位置开始
1. 枚举类型所占空间大小
enum Color
{
GREEN = 1,
RED,
BLUE,
GREEN_RED = 10,
GREEN_BLUE
}ColorVal;
sizeof(ColorVal)等于4
2. 枚举与#define 宏的区别
1),#define 宏常量是在预编译阶段进行简单替换。枚举常量则是在编译的时候确定其值。
2),一般在编译器里,可以调试枚举常量,但是不能调试宏常量。
3),枚举可以一次定义大量相关的常量,而#define 宏一次只能定义一个。
3. 用函数确定系统的大小端模式
- int checkSystem( )
- {
- union check
- {
- int i;
- char ch;
- } c;
- c.i = 1;
- return (c.ch ==1);
- }