详解:C语言程序的编译+链接
一个源文件程序到可执行程序,需要经过----预编译+编译+汇编+链接
预编译:只要是对头文件进行包含,define定义符号的替换,注释的删除
编译:把c语言代码变成汇编代码。包括:语法分析,词法分析,语义分析,符号汇总
汇编:把汇编代码转换成二进制代码,形成符号表。
链接:符号表的合并和重定位
预定义符号介绍
__FILE__
进行编译的源文件
__LINE__
文件当前的行号
__DATE__
文件被编译的日期
__TIME__
文件被编译的时间
__STDC__
如果编译器遵循ANSI C,其值为1,否则未定义
例:
#include <stdio.h> int main() { printf("%s %d %s %s\n", __FILE__, __LINE__, __DATE__, __TIME__); return 0; }
运行结果:
预处理指令 #define
#define定义标识符
基本形式 #define + 名字 + 替换的数据
它是在预编译阶段进行替换的。记住本质是替换
#define MAX 100 #define PRINT printf("hahaha\n") int main() { printf("%d\n", MAX); PRINT; return 0; }
#define定义的宏
基本形式:#define+名字(符号)+替换的内容
例如:
#define MAX(x,y) x>y?x:y int main() { printf("%d\n", MAX(1, 3)); return 0; }
因为只是替换,所以有时候会出现问题
比如:下面这个算的不是10,而是7,因为
*
号的优先级高于+
最好都用上括号,如:
((x)*(y))
#define mul(x,y) x*y int mian() { mul(2,2+3); return 0; }
#define的使用规则
在调用宏的时候,如果有#define定义的标识符,那么先对他进行替换。
然后再对宏进行替换
宏和函数的对比
宏 | 函数 |
代码插入到程序中,会使代码的长度变长 | 每次使用,只需要调用即可 |
执行速度快 | 有函数调用和返回的开销 |
存在优先级的问题,结果可能不是我们想要的 | 不存在这个问题 |
参数与类型无关 | 参数与类型有关 |
不能调试 | 可以调试 |
不能递归 | 可以递归 |
预处理操作符#和##的介绍
#可以把宏参数转换成串
#define print(a) printf(#a" is %d\n",a) int main() { int a = 6; int b = 0; print(a); print(b); return 0; }
##可以连接位于它两边的符号
看下面的例子:
#define line(x,y) x##y int main() { int ac = 20; printf("%d\n", line(a, c)); return 0; }
预处理指令 #include
在使用#include进行引用头文件的时候,我们有两种方式
<>
," "
<>
,这是从标准位置查找头文件
" "
,这个是先在本地目录下进行查找,如果没有查找到,再去标准目录下进行查找。
预处理指令 #undef
这个指令用于移除一个宏定义
条件编译
常见的条件编译
#if+常量表达式 #endif #if+常量表达式 #elif+常量表达式 #else+常量表达式 #endif 判断是否被定义 1.#if defined(符号) 2.#if !defined(符号) 3.#ifdef 符号 4.#ifndef 符号 #ifndef 符号 #define 符号 //..... #endif #pragma once
例:
#define add(x,y) x+y #define A int main() { #if defined(A) printf("%d\n", add(1, 2)); #endif #ifdef A printf("%d\n", add(1, 2)); #endif return 0; }