预处理分为以下几部分
* 宏定义
* 条件编译
* 头文件包含
* #运算符
* ##预算符
宏定义
**宏定义常量**#include<stdio.h>
#define num 3.1415926
int main()
{
printf("%.7f",num);
}
宏定义字符串
在宏定义字符串中,字符串要用双引号括起来,也可以用’\‘来续行字符串,如果想输入’\‘的话需要用两个’\’
#include<stdio.h>
#define str "c\\输入字符串\
宏定义字符串\
续行"
int main()
{
printf("%s", str);
}
用宏定义充当注释符号
在这之前我们先了解一下程序翻译的过程
- 预处理 -E :头文件展开,去注释,宏替换,条件编译
- 编译 -S :将干净的C语言,编译成汇编语言
- 汇编 -c :将汇编翻译成为目标二进制文件(可被链接的)
- 链接 :将目标二进制文件与相关库链接,形成可执行文件
(库的优点:1、高效性2、健壮性or鲁棒性)
#define BSC //
int main()
{
BSC printf("hello");//BSC表示空
}
#define BMC /*
#define EMC */
int main()
{
BMC printf("hello"); EMC
}
两段代码均不能将代码注释,在程序编译中也说明了是先去注释,在宏替换
用define宏定义表达式
#define sum(x) (x)+(x)
int main()
{
printf("%d\n",sum(10));
printf("sum(20)");
}
#define INIT_VAL(a,b) \
a=0; \
b=0;
int main()
{
int x = 10;
int y = 20;
printf("before:%d %d\n",x,y);
INIT_VAL(x, y);
printf("after:%d %d", x, y);
}
如果想要定义多条宏语句可以去使用do{}while语句
#define INIT_VAL(a,b) \
do{\
a=0;\
b=0;\
}while(0);
int main()
{
int flag = 0;
scanf_s("%d",&flag);
int x = 10;
int y = 20;
printf("before:%d %d\n",x,y);
if (flag) {
INIT_VAL(x,y);//宏定义
}
else
{
printf("error!\n");
}
printf("after:%d %d\n",x,y);
}
#undef(取消宏定义,也可以叫为限定宏的有效范围)
首先我们先了解一下宏定义的范围
源文件的任何地方,宏都是可以定义,无论是在函数内外,无关
宏的定义范围:从定义开始,往后都是有效的
void show()
{
#define M 100
printf("1%d\n",M);//ture
}
int main()
{
show();
printf("2%d\n", M);//ture
}
void show()
{
printf("1%d\n",M);//error未定义
}
int main()
{
#define M 100
show();
printf("2%d\n", M);//ture
}
int main()
{
#define M 10
printf("%d", M);//ture
#undef M //取消宏定义
printf("%d", M);//显示未定义
}
int main()
{
#define X 3
#define Y X*2
#undef X //取消宏定义
#define X 2//从新定义X
int z = Y;
printf("%d",z);//最后打印的是4
}
#define和#undef最好别在代码块中使用,容易以为是由作用域的
#define M 10
void show()
{
printf("%d",M);//可以输出
}
int main()
{
#undef M
show();
}
原因是宏替换在函数调用之前
条件编译
格式:#ifdef 标识符 (是用来判断标识符是否被定义) 本质就是一个代码裁剪的工具 条件编译的作用:通过裁剪代码,快速实现某种目的(版本维护(免费,收费),功能裁剪,跨平台性)#define INIT
int main()
{
#ifdef INIT
{
printf("ture");
}
#else
{
printf("error");
}
#endif
}
#ifndef//(没有被定义)的用法是和#ifdef一样的,
#if和#ifdef的区别在于#if是来判断宏定义的真假,而#ifdef是判断是否定义的
#define INIT 1
int main()
{
#if INIT
printf("ture");
#else
printf("error");
#endif
return 0;
}
也可以在#if 后面定义加上条件,多分支用法
#define INIT 1
int main()
{
#if INIT<1
printf("1");
#elif INIT<2
printf("2");
#elif INIT<3
printf("3");
#else
printf("0");
#endif
return 0;
}
用#if 代替#ifdef
#define INIT
int main()
{
#if defined(INIT)
printf("ture");
#else
printf("error");
#endif
return 0;
}
用#if 代替#ifndef
#define INIT
int main()
{
#if !defined(INIT)
printf("ture");
#else
printf("error");
#endif
return 0;
}
#if 还有以下用法:#if defined()&&defined() #if defined()||defined()
条件编译也是支持嵌套的
#define INIT
#define C
int main()
{
#if defined(INIT)
printf("ture");
#if defined(C)
printf("hello");
#endif
printf("hi");
#else
printf("error");
#endif
return 0;
}
条件编译所用的地方
头文件包含
防止头文件被重复定义,也可以选择用#pragma once#ifndef INIT
#define INIT
#include<stdio.h>
#endif
重复包含不一定会报错,会引起多次拷贝,主要会影响编译效率,同时也可能引起一些未定义的错误,但是特别少
头文件展开就是把头文件的内容拷贝到目标文件中
#运算符
#include<stdio.h>
int main()
{
printf("hello world\n");
printf("hello""world\n");
const char* str = "hello world";
printf(str);
return 0;
}
相邻的字符串(" ")具有自动连接特性
printf(str);//是成立的
|
|
#define STR(s) #s
int main()
{
printf("PI:"STR(3.1415926)"\n");
return 0;
}
由上面可知相邻字符串具有自动连接性,因为能打印出来,也就说明了,#s将3.1415926变为字符串了
再次证明#将内容转换为字符串
#pragma warning(disable:4996)
#define STR(s) #s
int main()
{
char str[64] = {0};
strcpy(str, STR(abc));
printf("%s",str);
return 0;
}
##预算符
例子: