C语言 预处理详情笔记(剖析)分享
C语言 预处理详情笔记(剖析)分享
C语言的预处理
预处理分为两环境
1.第1种是翻译环境, 在这个环境中源代码被转换为可执行的机器指令。
2.第2种是执行环境, 它用于实际执行代码
文章目录C语言的预处理
编译过程图例
编译流程预编译(预处理)阶段
编译阶段
汇编阶段
形成可执行文件
预定义符号(c语言内置)使用
预处理指令
define和宏定义宏
宏的注意事项
宏和函数
宏的传参和移除
#和##的作用
预处理指令条件编译1
条件编译2
条件编译3(多分支的条件编译)
条件编译4和ifedef原理相同
条件编译5(嵌套编译)解决头文件重复包含
完
编译过程
[var1]
链接器是负责链接其它的目标文件(每个源文件都会经过下面的操作)
编译流程
预编译->编译->汇编->目标文件
[var1]
1,这个阶段的includ,包含的头文件,会将头文件的内容包含到源文件(就是复制到源文件)
2,删除注释.使用 空格和代替,注释
3, define,全部替换
[var1]
1.c代码翻译->成汇编代码
形成汇编代码的阶段
编译器根据编译原理:如词法分析,语法分析,和符号汇总(函数名字,变量)
->汇编代码
[var1]
汇编代码->二进制代码(二进制指令)
这个阶段(函数名,变量)进行符号汇总->形成符号表[符号,地址]
根据地址找到对应的函数,变量
[var1]
1, 合并段表->把目标文件合并,链接一起
2,符号表的合并和重定位
最终形成->可执行文件.exe
预定义符号(c语言内置)
__FILE__//进行编译的源文件
__LINEL__文件当前的行号
__DATE__文件被编译的日期
__TIME___文件被编译的时间
__STDC__如果编译器遵循ANSI C(标准) ,其值为1 ,否则未定义
[var1]
int i = 0;
int arr[10] = { 0 };
FILE* pf = fopen("1og.txt", "w");
for (i = 0;i < 10;i++)
{
arr[i] = i;
fprintf(pf, "file:%s line:%d date:%s time:%s i=%d\n",
__FILE__, __LINE__, __DATE__ ,__TIME__, i);
}
fclose(pf);
pf = NULL;
for (i = 0;i < 10;i++)
{
printf("%d ",arr[i]);
}
预处理指令
#define
#include
#pragma pack(4)
#pragma
#if
#endif
#ifdef
#line
define和宏
//(右边是符号内容)都是替换
#define Max 1000//定义标识符,不能加分号因为分号也会替换
#define arr "heesfjio"//定义字符串
#define reg register//定义类型 /*reg int a;=> register reg*/
#define do_forever for(;;)//死循环代码//定义一个循环代码
定义宏
#define机制包括了一个规定, 允许把参数替换到文本中, 这种实现通常称为宏(macro)或定义宏(define
macro)
下面是宏的申明方式:
#define name( parament-list ) stuff 其中的parament-list是一一个由逗号隔开的符号表,
它们可能出现在stuff中。
注意 : 参数列表的左括号必须与name紧邻。如果两者之间有任何空白存在, 参数列表就会被解释为stuff的一部分。
所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号, 避免在使用宏时由于参数中的操作符或
邻近操作符之间不可预料的相互作用。
**//***********写宏一定要注意号括号,不能出现递归
例
#define SQUARE(X) X*X
//改进
//#define SQUARE(X)(X)*(X)//括号优先级高
int main()
{
/*int ret = SQUARE(5);*///int ret = X* X;=>%*5
int ret = SQUARE(5+1);//宏是替换的所以变成5+1*5+1=11//乘法优先级高
printf("%d", ret);
return 0;
宏的注意事项
由于是替换的原因导致一些计算是不尽人意的
(x++)这种是附带副作用的参数对于宏来说
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
int main()
{
int a = 10;
int b = 11;
int max = MAX(a++, b++);
printf("%d\n", max);//12
printf("%d\n", a);//11
printf("%d\n", b);//13
return 0;
}
宏和函数
1.用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序
的规模和速度方面更胜一筹。
2.更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可
以适用于整形、长整型、浮点型等可以用于 > 来比较的类型。宏是类型无关的。
当然和宏相比函数也有劣势的地方 :
1.每次使用宏的时候, --份宏定义的代码将插入到程序中。除非宏比较短, 否则可能大幅度增加程序的长度。
2.宏是没法调试的。
3.宏由于类型无关, 也就不够严谨。
4.宏可能会带来运算符优先级的问题, 导致程容易出现错。
int Max(int x, int y)
{
return (x > y ? x : y);
}
#define MAX(X,Y) ((X)>(Y)?(X):(Y))
int main()
{
int a = 10;
int b = 20;
int max = Max(a, b);
printf("max = %d\n", max);
max = Max(a, b);
//函数在调用的时候
//会有函数调用和返回的开销
//
max = MAX(a, b);
//预处理阶段就完成了替换
//没有函数的调用和返回的开销
printf("max = %d\n", max);
}
宏的传参和移除
#define SIZEOF (type) sizeof(type)
int main()
{
int ret = SIZEOF (int);
printf("%d\n",ret);
return 0;
}
#define MALLOC(num, type) (type* )malloc (num* sizeof(type))//开辟空间
int main(){
int* p = (int*)malloc(10 * sizeof(int));//=>int* p = MALLOC(10, int);
return 0;
}
#define MAX 1000
int main()
{
printf("MAX = %d\n", MAX);
#undef MAX
//printf("MAX = %d\n", MAX);//这个移除一个宏定义
return 0;
}
[var1]
#define SIZEOF (type) sizeof(type)//返回大小
int main()
{
int ret = SIZEOF (int);
printf("%d\n",ret);
return 0;
}
#define MALLOC(num, type) (type* )malloc (num* sizeof(type))//开辟空间
int main(){
int* p = (int*)malloc(10 * sizeof(int));//=>int* p = MALLOC(10, int);
return 0;
}
//#和在字符串 中嵌套参数
#define PRINT(X) printf("the value of "#X" is %d\n", X)
int main(){
//printf("hello world\n");
//printf("hello""world\n");
//printf("hel" "lo”"world\n");
int a = Alice;
int b = sa;
PRINT(a);
//printf("the value of ")
PRINT(b);
//##的作用
//##可以把位于它两边的符号合成一个符号。 它允许宏定义从分离的文本片段创建标识符。
#define CAT(X, Y) X##Y
int main()
{
int Alice = sa;
//printf( "%d\n", Alice);
printf("%d\n", CAT(Ali, ce));
//printf( "%d\n", Ali##ce);
//printf("%d\n", Alice);结果是一样的
return 0;
}
[var1]
条件编译1
#define DEBUG
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
int i = 0;
for (i = 0;i < 10;i++)
{
arr[i] = 0;
#ifdef DEBUG
prlintf("%d",arr[i]);//如果DEBUG没有定义这条语句不编译
条件编译2
#endif
#if 1//如果这语句为真这条语句参与编译,反之不参与
printf("%d ",arr[i]);
#endif
条件编译3(多分支的条件编译)
//条件编译3(多分支的条件编译)
#if 1==1
printf("haha\n");
#elif 2==1
printf("hehe\n");
#else
printf("嘿嘿\n");
#endif
return 0;
}
条件编译4和ifedef原理相同
#if defined(DEBUG)//如果DEBUG没有定义这条语句不编译
printf("嘿嘿\n");
#endif
[var1]
///嵌套指令
#if defined(DEBUG)
#ifdef OPTION1
unix_ version_ option1();
#endif
#ifdef OPTION2
unix_ _version_ opti on20);
#endif
#elif defined(DEBUG2)
#ifdef OPT ION2
msdos_ _version_ option2();
#endif
#endif
解决头文件重复包含
//解决一个文件重复包含
#ifndef __TEST_H__
#define __TEST_H__
int Add(int x,int y);
#endif
//解决方法二
#pragma once
int Add(int x,int y);
}
完
C语言 预处理详情笔记(剖析)分享相关教程