资源预览内容
第1页 / 共6页
第2页 / 共6页
第3页 / 共6页
第4页 / 共6页
第5页 / 共6页
第6页 / 共6页
亲,该文档总共6页全部预览完了,如果喜欢就下载吧!
资源描述
一、调用函数以及压栈:(1) 、每个 int 占 4 个字节。 (2) 、通常栈是王内存低地址方向增长的,也就是说,先压栈的内容存放在高 地址区域,后压的存放在低地址区域。 (3) 、一般调用函数时,汇编中 call(通常调用函数都是用 call 指令实现跳转) 指令会在主函数体内进行自动压栈。将调用函数后面的语句的地址压栈存。 (4) 、一般调用函数前会将传入参数都压栈保存。 二、变量的可见范围和生存期:(1) 、函数内部的非静态变量都会放到栈里面去。 (2) 、函数间不能互相访问各自的内部变量(即使是静态的都不行,那是基于 语义的要求) ,基于堆栈的声明和释放。 (3) 、外部变量一般存放在数据段(data segment)中,而不是栈中。 (4) 、外部变量的定义如果在某函数的函数声明之前,则可以直接使用,如果 在某函数名之后,则要用 extern 进行声明(注意,不是定义,但是造型蛮像定 义的) 。然后还是要在外面再重新定义的。 (5) 、不是所有的外部变量都是任何函数都能使用的,如果在某函数内声明的 时候使用了 static 静态修饰,则不能了。 三、变量的声明和定义:(1) 、声明变量不会使编译器为其分配存贮空间。声明的关键字是 extern,有 extern 的时候,编译器只是知道这个符号是什么意思,此外什么都不做。但是 若同时又对其初始化,则会为其分配空间。 (2) 、1、在 C 中,我们常见的类似 int a;之类的都是对 a 的暂时定义(有初 始化才叫正式定义,C 中,外部变量只能被定义一次,注意是正式定义一次, 暂时定义就没有限制了) 。2、C+中没有暂时定义和正式定义之分,所有都是 正式的。要注意。所以最好要么声明,要么定义,而且都只定义一次。3、C 中的暂时变量可以定义多次,当在连接时系统全局空间没有相同名字的变量定 义,暂时就升级为正式定义。系统就会为其分配存储空间。 四、编译(complie)和链接(link):(1) 、一般来说程序的编译和链接是整个工作的 2 个部分,首先是编译,然后 链接。 (2) 、编译有:预处理程序(包括包含入头文件等)编译器将代码文件编译成 汇编代码文件汇编编译器将汇编代码文件编译成目标代码文件。 (3) 、链接就是将编译得到的汇编代码中每个记录下的需要确定地址的符号 (包括变量,子函数等)的地址计算并确定后传入。 五、外部变量的链接性质:(1) 、问题:如何使一个变量像外部变量那样存放在数据段,又不会被其他文 件的代码影响到,因为不同文件的同名的外部变量会有冲突。 (2) 、当对外部变量进行定义的时候(从这个时候开始,我应该注意区别定义、 暂时定义和声明的不同) ,加 static 就会将该变量的链接性质从 external 变为internal,在汇编中就会相应不产生“.globl xx”此句,该变量就只能在本文件 中被使用。 (3) 、对于暂时定义同理也是加 static,但是其会在汇编中加上“.local a”一 句,效果是一样的。 (4) 、同一个变量的定义和暂时定义间或者几个暂时定义之间,在使用 static 问题上前后不一致会导致报错。降低程序的可移植性。 (5) 、暂时定义与声明不一致则以暂时定义为准,但编译器会发出警告。 六、静态内部变量:(1) 、有 static 修饰的内部变量可以使内部变量具有外部变量的存储性质,又 具有内部变量的可见范围 (2) 、静态内部变量汇编时会被编译器加后缀,用以区别不同函数内部定义的 同名变量。而汇编时不加“.globl xx”使不同文件不会冲突。 (3) 、静态内部变量只会被初始化一次。汇编时“.long xx”对其初始化存放 到目标代码文件和后面的可执行文件中。不仅静态变量、所有存放在.data 数 据段的数据都是这样初始化的。 (4) 、 ”int f(); void g()int a=f();”可行,但是”int f(); static void g()int a=f();” 就不行。因为:初始化静态变量的值必须是编译期就能够求出的常数。 七、函数的声明和定义:(1) 、对函数的调用的步骤:参数的压栈地址转移通过压栈或者寄存器返 回值。 (2) 、函数在调用前若不声明则为 K /(5) 、C90 继承了 K int I; ; 8bitsstruct s char x; int I; char y; int j; ;16bitsstruct s int i; int j; char x; char y; ;12bits 而前面的要 用 16bits。同理 struct s int I; char x; ;8bits 而不是 5bits。 十四、指针:(1) 、像函数名也是一种函数指针,代表函数入口地址,比如:void fun(void);ptr=fun; (*ptr)();也是可以调用函数的。 (2) 、如果知道了函数的入口地址的值(假设 0x12345678)也可以调用函数: (假设是一个返回值 void 的函数)(*(void(*)()0x12345678();看一个数据的类 型,方法是在声明中去掉其名字,我们知道函数(1)中的例子用 ptr 进行声明 时为 void (*ptr)();那么去掉名字 ptr 后,其类型应该为 void (*)();故强制类型 转换时加一个括号成为(void (*)()即可强制装换。 (3) 、指针和数组名都代表某种变量的地址。但是指针是变量,编译器会为其 分配空间,那么其值也可以改变。而数组名编译器不会赋给空间,其被当做一 个常量,不能改变。(4) 、注意:1、数组名和指针虽然都是地址,但是不好混用的,因为初始化数 组的时候赋的值被指针当做地址去访问的时候有时会出错,比如像 0 之类的, 会被当做空指针。2、当用作函数参数时,2 者就相等了。因为在入栈的时候, 都会被赋予存储空间,那么数组名其实也成了指针。/有问题 十五、typedef:(1) 、typedef 跟变量一样,是有可视范围的,同时也有内层覆盖外层的属性。(2) 、同一范围内不能有相同的名字定义不同的类型。 (3) 、与#define 想比,typedef 有先天的优势,编译器会对其进行语义分析, 而不是前者的单纯替换,前者可能会因为优先级的问题产生问题,而后者一般 很友好。 。 。 (4) 、但是 typedef 不能和其他的标识符组合使用,比如 typedef int INT;unsigned INT a;就不行的。不能组合,而#define 可以 (5)typedef 和 const 组合起来的时候也会有问题,要知道在使用 typedef 后,const 修饰的对象就是 typedef 定义的性的类型了,那么,就是定义了一 个 const 的类型的对象:typedef char * str;const str s;定义的是一个指向 char 的 const 指针。char * const s; 十六、C-V 限定词:(1) 、C+能将已用常数赋值的 const 变量看做编译期常数,C 不行(const int BUF 1024;char bufBUF在 C+里可以,C 不行,而 C 必须是#define BUF 1024 char bufBUF;使用预编译) 。用常量初始化的 const 变量可以当 常数。 (2) 、C+默认 const 变量的链接性质是内部的,而 C 则是外部的(const int a=0;int main(void)在 C 中无疑是外部的,而在 C+中除非加上 extern, 否则一律内部,其他的文件看不到 const 的 a) 。 (3) 、const 只能允许用常理初始化 const 外部变量,C+没有这种限制(int f(void); const int a=f(); int main(void)在 C+中可以而 C 不行) 。 (4) 、volatile 告诉编译器这个变量可能会被外部事件修改,让其在优化代码 的时候不要擅自作出假定而导致错误。通常用在一些硬件的时钟端口上。 十七、字符串:(1) 、字符串是常理的一种,其会被编译器安排到只读区。 (2) 、用字符串初始化指针和初始化数组是不同的,前者用指针指向该字符串 的地址,对其修改时会报错。而后者在栈中给数组分配了存储空间,那么仅仅 用只读区的字符串值初始化了栈内的区域,接下来的操作都是对栈的,故不会 报错。 (3) 、但是,并不是字符串永远被放在只读区的。当我们将字符串在一些特定 的地方声明而编译器有特殊处理这些位置的设定,则该字符串就不一定是在只 读区了。比如将字符串定义在全局(即放函数外部) ,那么就会被编译器默认放 到数据段去(汇编是:.data .type xx,object .size xx,yy) 。那么在函数里对 其修改就没有问题了。同理将字符串定义为静态内部变量或者静态外部变量都 可以实现目的。十八、void:(1) 、void*void 指针,其指向的对象时不确定的,可以是除函数外任何对 象。它的主要特性有:1、它可以和其他类型的指针(函数指针除外)相互转化 而不需类型强制转换(即进行不区分类型的相互赋值) 。2、不能对其执行取值 和下标操作,即在其被赋值(所谓赋值就是将另外一个指针值给它)之前,不 能对其做类似*pv,pvx等操作,因为根本不知道他是什么。 (2) 、我们常见的 malloc 函数等返回的值其实是 void*,C90 函数库说明为: void malloc(size_t size),那么申请 100 个 int 的空间给指针 ptr 的语句可以写 成:int *ptr = malloc(100*sizeof(int)而不一定要强制类型转换。 (3) 、当时 C+中对于 void*的限制要求我们还是要在该加的地方加上强制转 换。 (4) 、常数 0 也能够无需转换赋值给任何指针,作为空指针。 (5) 、在 C 中定义 NULL 指针的方式为#define NULL (void*)0,但不被 C+ 认可,C/C+同时认可的是#define NULL 0。那么 NULL 指针也成为万精油了。十九、#pragma 与_Pragma:(1) 、其作用是为特定的编译器提供特定的编译指示。有较强的针对性, #pragma 的实现与具体的平台有关。 (2) 、#pragma 是根据不同厂商编译器而异,为了防止不同的厂商编译器给 出的相同的#pragma 指令意思却不同而造成错误,一般都用到宏来防止,例 如: #ifdef _hpux #pragma FLOAT_TRAPS_ON _ALL #endif来实现只有定义了” _hpux”的宏的编译器才能看到,其他的都无 视。 (3) 、而当编译器看到了不认识的#pragma 指令不会报错,只会忽略掉。 (4) 、用法区别:#pragma xxx = _Pragma(“xxx”)(注意都没有分号。 ) (5) 、_Pragma 的作用在于可以进行宏定义来减少工作量(#pragma 因为有 #而不行) ,例如:#define OPT(x) PRAGMA(OPT_LEVEL x) #define PRAGMA(x) _Pragma(#x),这时,OPT(2)_Pragma(“OPT_LEVEL 2”)即 #pragma OPT_LEVEL 2 二十、_Bool 的加入:(1) 、在 C99 中也加入了布尔类型,关键字为“_Bool”:例如 _Bool b; (2) 、布尔变量只占有 1 个 byte,取值只是 0 和 1,可以看做一个特殊的整型 变量。 (3) 、头文件 stdbool.h,用以增强代码的可移植性。在纯 C 代码中,不需要 包含它进来,并且,使用了 bool、true、false 用作标识符
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号