C语言深度剖析读书笔记

相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

C语言深度剖析读书笔记

第1章关键字

1.1、定义与声明的区别:定义创建了对象并为对象分配了内存,声明没有分配内存

1.2、register请求编译器尽可能将变量存在CPU寄存器中以提高访问速度,register变量必须为CPU寄存器所能接受的类型,它须是一个单一的值,并且长度<=整型的长度,由于register变量可能不放在内存中,故不可以用”&”来获取它的地址

1.3、函数前面加static使得函数成为静态函数,它的作用域仅限于本文件中,故又称内部函数

1.4、case关键字后面只能是整数或字符型的常量或常量表达式。

const int a = 5;

case a: //const只读变量,编译出错,case label does not reduce to an integer constant

case 1.1: //小数,编译出错,case label does not reduce to an integer constant

case 3/2: //没有问题,分数会被转换成整数

1.5、“跨循环层”的概念本身是说,由外层循环进入内层循环是要重新初始化循环计数器的,包括保存外层循环的计数器和加载内层循环计数器,退出内层的时候再恢复外层循环计数器。把长循环放在里面可以显著减小这些操作的数量,还可以增加cache的命中率。在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环层的次数。

for(i = 0; i < 50; i++){

for(j = 0; j < 10000; j++){

}

}

效率比下面这个高

for(i = 0; i < 10000; i++){

for(j = 0; j < 50; j++){

}

}

1.6、void指针的算术操作

void *pvoid;

pvoid++; //ANSI认为是错误的,因为它认为进行算术操作的指针必须知道它所指向的数据类型大小

pvoid += 1; //ANSI认为是错误的

//但GNU指定void *的算术操作跟char *相同。

1.7、const

编译器通常不为普通const 只读变量分配存储空间,而是将它们保存在符号表中,这使

得它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也很高。

例如:

#define M 3//宏常量

const int N=5; //此时并未将N 放入内存中

......

int i=N;//此时为N 分配内存,以后不再分配!

int I=M;//预编译期间进行宏替换,分配内存

int j=N;//没有内存分配

int J=M;//再进行宏替换,又一次分配内存!

const 定义的只读变量从汇编的角度来看,只是给出了对应的内存地址,在程序运行过程中只有一份拷贝。

#define 定义的宏常量在内存中有若干个拷贝。

#define 宏是在预编译阶段进行替换,而const 修饰的只读变量是在编译的时候确定其

怎么看const修饰哪个对象

先忽略类型名(编译器解析的时候也是忽略类型名)。看const 离哪个近。离谁近就修饰谁。

const int *p; //const *p

//const 修饰*p,p 是指针,*p 是指针指向的对象,不可变

int const *p; //const *p

//const 修饰*p,p 是指针,*p 是指针指向的对象,不可变

int *const p; //*const p

//const 修饰p,p 不可变,p 指向的对象可变

const int *const p; //前一个const 修饰*p,后一个const 修饰p,指针p 和p 指向的对象

都不可变

1.8、volatile

编译器遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问

先看看下面的例子:

int i=10;

int j = i;//(1)语句

int k = i;//(2)语句

这时候编译器对代码进行优化,因为在(1)(2)两条语句中,i 没有被用作左值。这时候

编译器认为i 的值没有发生改变,所以在(1)语句时从内存中取出i 的值赋给j 之后,这个

值并没有被丢掉,而是在(2)语句时继续用这个值给k 赋值。编译器不会生成出汇编代码

重新从内存里取i 的值,这样提高了效率。但要注意:

(1)(2)语句之间i 没有被用作左值才行。

再看另一个例子:

volatile int i=10;

int j = i;//(3)语句

int k = i;//(4)语句

volatile 关键字告诉编译器i 是随时可能发生变化的,

每次使用它的时候必须从内存中取出i

的值,因而编译器生成的汇编代码会重新从i 的地址处读取数据放在k 中。

这样看来,如果i 是一个寄存器变量或者表示一个端口数据或者是多个线程的共享数

据,就容易出错,所以说volatile 可以保证对特殊地址的稳定访问。

1.9 、大部分编译器中,默认情况,enum会转化为int

enum Color

{

GREEN = 1,

RED

}Col

故sizeof(Col) = sizeof(int)

第2章、符号

2.1、注释

int /*...*/i; //编译器会用空格代替原来的注释,这里相当于 int i 编译能通过

2.2、a<

+优先级高于 <<

2.3、贪心法a+++b 表达式与(a++) +b 一致

C 语言有这样一个规则:每一个符号应该包含尽可能多的字符。也就是说,编译器将程

序分解成符号的方法是,从左到右一个一个字符地读入,如果该字符可能组成一个符号,

那么再读入下一个字符,判断已经读入的两个字符组成的字符串是否可能是一个符号的组

相关文档
最新文档