〇.写在前面
若读者朋友们发现问题,请不吝斧正。
一.编译过程
(1)有这样一个问题:我们写的c语言代码放在了.c文件里,最终它是怎么样变成一个可执行文件的呢?这就涉及到了编译过程的知识。
(2)编译过程分为预处理,编译,汇编和链接这几个过程。
(3)预处理一般有以下几个过程:展开头文件,宏替换,去掉注释和条件编译。(从.c文件变为.i文件)
(4)编译则会检查语法,生成汇编代码。(从.i文件变为.s文件)
(5)汇编把汇编代码转变为机器码。(从.s文件变为.o文件)
(6)链接会生成符号表,把各个.o文件链接起来生成.out可执行文件。
二.预定义符号
__FILE__ //进行编译的源文件
__LINE__ //文件当前的行号
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
三.#define的替换操作
(1)#define用来定义标识符或者宏,其本质上都是一种替换操作。
(2)#define定义标识符:(注意最后不要加 ; )#define N 1000
(3)#define定义宏:
#define name( parament-list ) stuff
其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中,例如:#define ADD(x,y) ((x)+(y))
注意:括号是必不可少的,这可以有效避免类似如下这种问题:
#define ADD1(x,y) x+y #define ADD2(x,y) ((x)+(y)) int main() { printf("%d\n",ADD1(1 + 2) * 3); printf("%d\n",ADD2(1 + 2) * 3); }
四.#与##
(1)a和b的打印结果是一样的,这说明字符串有自动连接的特点。
int main() { char* a = "hello " "world"; char* b = "hello world"; printf("%p\n", a); printf("%p", b); }
(2)所以我们可以定义这样的宏:
#define PRINT(FORMAT, VALUE)\ printf("the value is "FORMAT"\n", VALUE);
(3)#的作用是把一个宏参数变成对应的字符串,例如:
#define PRINT(FORMAT, VALUE)\ printf("the value of " #VALUE " is " FORMAT "\n",VALUE); int main() { int a = 0; int b = 1; PRINT("%d",a+b); } // 输出: the value of a+b is 1
(4)##可以把位于它两边的符号合成一个符号,例如:
#define ADD_TO_SUM(num, value) \ sum##num += value; ... ADD_TO_SUM(5, 10);//作用是:给sum5增加10.
五.条件编译
(1)#undef 用来移除一个宏定义:
#define N 10; #undef N;
(2)#if … #endif 条件编译,我们如果不想让代码中的codes运行,除了注释之外,还可以用下面这样的方法。如果再想要codes加入运行,就可以把DEBUG改成1:
#define DEBUG 0 #if DEBUG //codes #endif
(3)#ifdef … #endif 用来判断一个宏是否被定义,此时图中的codes会被执行,如果没有定义N,codes就不会执行。
#define N 10 #ifdef N //codes #endif
(4)注意,#if 和 #ifdef 后都只能加常量表达式。
六.防止头文件被重复包含
在每个头文件的开头写:
#pragma once