预处理,宏,条件编译,小结【C】(zi)

徘徊边缘 提交于 2020-02-08 01:35:04

预处理

发生时机

预处理操作,不是 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!