-
程序的翻译环境和执行环境
第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。
第2种是执行环境,它用于实际执行代码。
- 详解:C语言程序的编译 + 链接(有一本书里面有详讲《程序员的自我修养》)
-
预定义符号介绍
__FILE__//进行编译的源文件
__LINE__//文件当前的行号
__DATE__//文件被编译的日期
__TIME__//文件被编译的时间
__STDC__//如果编译器遵循ANSI C,其值为1,否则未定义
int main()
{
printf("%s\n", __FILE__);
printf("%d\n", __LINE__);
printf("%s\n", __DATE__);
printf("%s\n", __TIME__);
//printf("%s\n", __STDC__);//如果编译器遵循ANSI C,其值为1,否则未定义。但是当前的VS是不支持标准C的
return 0;
}
-
预处理指令#define
#define 不仅仅可以定义一个标识符
还可以定义一段的代码语句
eg.
//这一段代码就形成了死循环打印M
#define M 100
#define FOR for(;;)
int main()
{
FOR
{
printf("%d\n",M);
}
return 0;
}
换行符的作用
使用宏的小细节
#define 替换规则
在程序中扩展#define定义符号和宏时,需要涉及几个步骤。
1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先
被替换。
2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上
述处理过程。
注意:
1. 宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。
2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。
#和##(只能在宏里面使用)
- 如何把参数插入到字符串中?
1.# 的作用
把printf("The value of a is %d\n",a); 中的红字a,做到灵活替换呢
#define PRINTF(n,format) printf("The value of "#n" is "format"\n",n)
int main()
{
int a = 5;
PRINTF(a, "%d");
int b = 2;
PRINTF(b, "%d");
float f = 5.2;
PRINTF(f, "%f");
return 0;
}
2.## 的作用
##可以把位于它两边的符号合成一个符号。
它允许宏定义从分离的文本片段创建标识符。
#define ADD_TO_SUM(num, value) \
sum##num += value;
...
ADD_TO_SUM(5, 10);//作用是:给sum5增加10.
注:
这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。
-
宏和函数的对比
- 预处理操作符#和##的介绍
# 和 ## 只能在宏里面使用
#n <==> "n" #相当于“”的作用
#define PRINT(n,format) printf("The word of "#n" is "#format"\n",n)
int main()
{
int a = 0;
PRINT(a, %d);
return 0;
}
## 起链接标识符的作用
#define L(x,y) x##y
int main()
{
int qianzhuo520 = 520;
printf("%d\n", L(qianzhuo, 520));
qianzhuo##520 <==> qianzhuo520
return 0;
}
-
命令定义
在gcc上才能演示,下面用两张图片来说明
-
预处理指令#include
#include 是用来包含头文件的
头文件既可以用 <> 尖括号, 也可以用 "" 双引号
<> 尖括号所包含的头文件,在库的目录中去找,
"" 而双引号所包含的头文件,首先在谁包含这个头文件的.c文件的目录中去找,找不到再去库中找
所以我们字节写的头文件用"",而库里的头文件用<>.这样可以减少编译器的压力,也可以更好的区分自己写的头文件和库里的头文件
-
预处理指令#undef
当你想要移除宏定义的时候,可以用这个 #undef
#define M 100
int main()
{
printf("M=%d\n", M);
#undef M
printf("M=%d\n", M);//这里的M就已经无法在找到了
return 0;
}
-
条件编译
#define M 100
#define N 1
int main()
{
#if N//当#if 后面所跟的常量表达式为假时, #if和#endif 之间的代码在预编译阶段就会清理掉,不参与编译
printf("%d\n", M);
#endif
return 0;
}
多分枝条件编译
int main()
{
#if !2
printf("hehe\n");
#elif 2
printf("haha\n");
#else
printf("h h h \n");
#endif
return 0;
}
defined(MAX) 判断是否定义过标识符 MAX 等价于 #ifdef M
#define M 100
int main()
{
#if defined(M)
printf("定义过\n");
#endif
#ifdef M
printf("Loved\n");
#endif
return 0;
}
没有定义过标识符
!defined(M) <==> #ifndef
#if 这类条件编译可以运用到避免头文件的多次引用
需要创建一个头文件来演示
test.h
#ifndef __TEST_H__
definf __TEST_H__
int Add(int x, int y)
#endif
其实在 VS 里写头文件,它自己会加上一条语句 #pragma once,
和上面那段代码作用一样
是可以嵌套的
int main()
{
#if 1
printf("hehe\n");
#if 1
printf("haha\n");
#endif
#endif
return 0;
}