预处理,宏,条件编译,小结
预处理
发生时机
预处理操作,不是 c 语言语句,故语句末尾没有分号,在预处理阶段完成,本质是替 换操作。
发生时段:
宏
不带参宏
宏常量
#define 定义的宏,只能在一行内表达(换行符表示结束而非空格),如果想多行表达,则需要加续行符。
#define PI 3.14\
15926
int main(void)
{
printf("%f",PI);
return 0;
}
宏常量,常被 const/ enum 变量取代,用于定义文件路径则被常用
#define FILEPATH "E:/English*listen_to_this/listen_to_this_3"
宏常量的缺陷
#include <stdio.h>
#define N 2+3 // #define N (2+3)
int main()
{
printf("%d\n", N);
printf("%d\n", N * 2); //printf("%d\n", 2+3 * 2);
return 0;
}
执行结果为:
这里我们要记得带上括号来解决:
#include <stdio.h>
#define N (2+3) // #define N (2+3)
int main()
{
printf("%d\n", N);
printf("%d\n", N * 2); //printf("%d\n", (2+3) * 2);
return 0;
}
执行结果为:
宏类型
宏可以给类型起别名,因其缺点,常被 typedef 取代
#include <stdio.h>
#define CHARP char *
int main(void)
{
CHARP p, q;
printf("p = %d q = %d\n", sizeof(p), sizeof(q));
return 0;
}
执行结果为:
但是如果使用typedef
#include <stdio.h>
typedef char* CHARP;
int main(void)
{
CHARP p, q;
printf("p = %d q = %d\n", sizeof(p), sizeof(q));
return 0;
}
执行结果为:
读者注意区分理解上面两种形式。
带参宏(宏函数)
#include <stdio.h>
#define S(a,b) a*b
int main()
{
printf("%d\n",S(3, 2));
//宏展开: 3 * 2;
return 0;
}
执行结果为:
宏名和参数间不能用空格
我们对于代码进行修改:
#include <stdio.h>
#define S(a,b) a*b
int main()
{
printf("%d\n",S(3, 2));
printf("%d\n", S(1+1, 2+2));
//宏展开:area = 3 * 2;
//注:宏名和参数间不能用空格
return 0;
}
执行结果为:
我们可以看到第二行结果为5
那么当宏定义执行之后,第二行代码计算过程变成:
1+1*2+2
所以执行结果为 5
所以我们还是需要带上括号:
#include <stdio.h>
#define S(a,b) ((a)*(b))
int main()
{
printf("%d\n",S(3, 2));
printf("%d\n", S(1+1, 2+2));
//宏展开:area = 3 * 2;
//注:宏名和参数间不能用空格
return 0;
}
执行结果为:
这样就不会出现问题。
常见宏函数
判断函数
#define MAX(a,b) ((a>b)?(a):(b))
宏函数与普通函数的区别;
使用宏定义使用函数可以直接嵌入代码段,减少调用函数的开销。直接编译到目标代码段。
例如:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define MAX(a,b) ((a>b)?(a):(b))
int main()
{
printf("%d",MAX(3,5));
return 0;
}
执行结果为:
上面的代码中MAX(3,5) 并没有使用函数调用而是使用宏定义将代码嵌入。
尽量少用宏函数,能看的懂别人写的宏函数即可。C++中的 inline 函数己经取代了宏函数作用。
宏出错处理函数
#define ERR_EXIT(m)\
do\
{\
printf("Err:%s",m);\
exit(-1);\
}while(0) //此处的分号,可有可无
以上代码,C语言在宏定义替换之后,所有的代码都处于一行是没有没有问题的编译器是不会在意空白字符的。但是宏不能写成多行。
取消宏
取消宏常量
#include <stdio.h>
#define MAX 23
int main()
{
printf("%d\n", MAX);
printf("%d\n", MAX);
printf("%d\n", MAX);
#undef MAX
printf("%d\n", MAX);
return 0;
}
这段代码无法编译,会提示MAX是未声明的标识符。
取消宏函数
#include <stdio.h>
#define MIN(x,y) x+y
int main()
{
printf("%d\n",MAX);
printf("%d\n",MAX);
printf("%d\n",MAX);
printf("%d\n",MIN(2,3));
#undef MIN //权需要指定宏函数名即可
printf("%d\n",MIN(2,3));
return 0;
}
条件编译
依据条件,依据条件决定是否参与编译。
例如我们之前用条件编译进行注释:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
FILE* pf = fopen("qq.txt","w+");
fputs("abcdefg",pf);
int n = ftell(pf);
printf("%d\n", n);
rewind(pf);
n = ftell(pf);
printf("%d\n", n);
fseek(pf,0,SEEK_END);
n = ftell(pf);
#if 0
printf("%d\n", n);
fseek(pf, 2, SEEK_SET);
#endif // 0
n = ftell(pf);
fseek(pf, -4, SEEK_END);
n = ftell(pf);
printf("%d\n", n);
return 0;
}
上面代码中
#if 0
printf("%d\n", n);
fseek(pf, 2, SEEK_SET);
#endif // 0
不参与编译,因为if 0 条件为假
单双路(#ifdef / #ifndef #else #endif)
#define X86
void main()
{
#ifdef X86 // #ifndef
printf("xxxxxxx\n");
printf("xxxxxxx\n");
printf("xxxxxxx\n");
printf("xxxxxxx\n");
printf("xxxxxxx\n");
#else // #else
printf("oooooooo\n");
#endif
}
单双多路(#if #elif #endif)
在写编译跨平台程序时,经常见到这样的语句。
多路条件编译:
#define X86 100
#define MIPS 200
#define POWERPC 300
#define MACHINE POWERPC
void main()
{
#if MACHINE == X86
printf("xxxxxxx\n");
printf("xxxxxxx\n");
printf("xxxxxxx\n");
#elif MACHINE == MIPS
printf("oooooooo\n");
#elif MACHINE == POWERPC
printf("xxxoooo\n");
printf("xxxoooo\n");
#endif
}
编译期指定宏 gcc -D
这里我们只是简单的说明,可以在编译的过程指定宏定义,而不用写在代码段。
小结
我们在条件编译中构成的单双路选择编译有两种:
第一种:#if #else #endif
第二种: #ifdef #else #endif
#ifndef #else #endif
多路选择编译:
#if #elif #elif #elif ………… #endif
来源:CSDN
作者:熟练的初学者
链接:https://blog.csdn.net/qq_43648751/article/details/104215379