C/C++深层探索——读书笔记

一、

1、关于字节顺序:话说在特定的硬件平台上,多字节数据的顺序存放有两种方式(little-endian、big-endian)。前者的数据的低字节

     部分存放在低地址内存,后者恰好相反。PC一般是基于IA-32微处理器,属于little-endian。某些RISC架构的CPU,例如SPARC、

    POWERPC等,则属于big-endian。

 

2、调用函数、栈,变量的可见范围与生命期:我们知道一个程序由数据和代码两大部分构成,而数据有几种类别,一种是“静态”的,也就

     是说在整个程序运行期间,它在内存中的地址是固定的,代码可以对其反复访问。C语言中的外部变量,内部静态变量就属于此类,存储

     于数据段(这些数据的地址在程序进行链接的时候就能准确算出)。另一种是“动态”的,他们在内存的地址不是固定的,对他们的操作

     就是对“栈”进行操作。

    

3、变量的声明和定义: “声明”只是告诉编译器某个标识符是:变量(什么类型?)还是函数(参数和返回值是什么?)。要是在后面的

     代码中出现该标识符,编译器就知道如何处理。声明变量不会导致编译器为这个变量分配存储空间。

 

4、编译与链接: 编译程序要做的事之一就是把所有需要确定地址的符号记录下来,然后链接程序在找到它们的定义点之后通过计算给予

     合适的地址。当所有的符号都有确定的地址时,链接程序就能够产生可执行文件。如果还有符号不能确定地址(找不到定义或重复定义)

     链接程序就会报错。

 

5、外部变量的链接性质与静态内部变量: 外部变量默认链接性质是外部的(extern),static改变外部变量的链接性质,使外部变量的

     链接性质是内部的。而对于内部变量,static改变的是其存储性质,使其可见范围不变,生存期为程序运行期间。

 

6、函数的声明、定义与链接性质:

 

7、使用头文件: 头文件应该包含:函数原型声明,全局变量的声明,自己定义的宏和类型;

                        不应该包含:全局变量和函数的定义(全局变量只能定义一次,如果你把“int global = 0;”这样的语句放在头文件)

                        则凡是包含了这个头文件的地方都定义了一次全局变量global,到了链接的时候,链接程序就会报告说找到很多歌global

                       ,不知该用哪一个。函数的情形也是这个道理,同样会产生名字冲突而导致链接失败。

                                          static变量和static函数(在全局变量声明与static变量的定义之间,static优先,于是本来应该访问一个

                        全局变量的代码,最后存取的却是一个由头文件定义的、毫无用处的static变量)。

 

 

二、

8、静态库: 静态库的结构比较简单,就是把原来的目标代码放在一起,链接的时候链接程序根据每一份目标代码的符号表查找相应的符号

     (函数和变量的名字),找到的话就把该函数里面需要定位的符号进行定位,然后将整块函数代码放进可执行文件里。

 

9、动态库: 动态链接就是在程序装载入内存的时候才真正把库函数代码链接进来确定它们的地址,并且就算是有多个程序运行,内存中也

     只存在一份函数代码。但动态库的数据仍然可能有多份副本。因为每一个链接到动态库的进程都可能会修改库的数据,每当出现这种情况

     的时候,操作系统就复制出一份数据的副本,然后修改进程的地址空间映射,使它指向新的数据副本,于是进程修改的知识属于自己的那

     份数据。

 

10、简单类型的转换: 整型之间的转换(如果被扩展变量是带符号的,那么扩展就是带符号的扩展;如果被扩展变量是不带符号的,那么

       扩展就是不带符号的扩展)。整型值转换为浮点型值不一定是安全的,浮点型值的数值范围虽然大,但却受精度的限制(不能超过6位

       有效数字)。

 

11、 复合类型的对齐

 

12、 指针: 指针数组,函数指针(存储调用函数地址,指向函数),

                   指针与数组: 指针和数组的名字都代表某种变量的地址,不同的是指针是变量,编译器会为指针分配存储空间,并且

                                      指针的值可以在运行期随意改变。

                                      数组名字只是代表某段存储空间的起始地址,数组名字相当于一个常量,编译器不会为数组名字本身分配空间,

                                      不能改变,不能改变数组名字代表的地址值。

                   数组指针,指向指针的指针,多维数组

 

13、 词法分析: 最大匹配原则

14、 注释:  /* */ 与 //

15、 优先级与运算顺序: 不要对运算的顺序作过多的假设。

16、 友好的typedef: 定义新的数据类型名,实际赋予别名。

                                  typedef 跟变量一样有可视范围,并且内层的可以覆盖外层的。

                                  在同一范围内,不能使用相同的名字定义不同的数据类型。

                                  #define(预编译指令)执行的仅仅是低级的符号替换,typedef是由编译器进行语法分析,用它定义的类型对

                                  声明或者定义语句中的每一个变量都起作用。

17、 C_V限定词: const在c++与c两种语言中存在差别

                            1)C++能够把(已有常量赋值的)const变量看作编译期常数,C没有这种功能。

                            2)C++默认const变量的链接性质是内部的,而C则相反,默认是外部的。

                            3)C只能允许用常量初始化const外部变量,C++没有这种限制。

                            volatile修饰一个变量的意思是告诉编译器这个变量可能会被外部事件修改,编译期在优化代码时不要擅自作出假

                            定,而导致错误的结果。

 

18、字符串: 字符串常量,不能被改变。指向字符串的指针 不能修改字符串。

                     可以使用字符串常量来初始化字符数组,可以修改字符数组的值。

 

19、void: void指针具有两个主要特性:

                  1)void指针可以和其他类型指针(函数指针除外)相互转化而不需要类型强制转换。

                  2)不能对它执行取值和下标操作。

   

                  在C++中,对类型的检查非常严格,任何指针(包括void指针)都不能不通过强制转换就直接赋值给其他指针;

                  但C++中,如果把其他类型指针的值赋给void指针,则不需要强制转换,与C一致。(void指针赋予其他指针就需要强制转

                  换)

 

20、 #pragma 为特定的编译器提供特定的编译指示。_Pragma

 

21、 _Complex 与 _Imaginary

 

22、 内联函数: 宏仅仅是一种记号替换,不像函数,它没有办法知道真正的参数是什么,从而无法对参数进行检查,也不能像

                         函数那样把某些运算局限于内部。

                        

                         由于内联函数要求编译器在调用点尽可能地嵌入函数的代码,所以,仅仅声明一个内联函数却没有在同一文件中给出函数

                         定义的做法是没有意义的。C++明确规定,一旦使用inline声明一个函数,这个函数就成为内联函数,所有调用该函数的

                         文件都应该给出函数的定义,并且所有这些定义都应该是相同的。所以内联函数的定义一般直接放在头文件。

 

                         C++的inline修饰符不改变函数的链接特性,所以内联函数完全可以有外部链接特性。进一步规定,所以外部链接的内联

                         函数都必须具有相同的地址,他们内部定义的静态变量都指向同一个实体。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(VC++,读书,编译器,扩展,存储,c,语言)