您现在的位置是:首页 >学无止境 >C-预处理网站首页学无止境
C-预处理
简介C-预处理
文章目录
预处理
宏定义
数值宏常量
define PI 3.14
字符串宏常量
define PATH "C:\Users\yuanwei\Desktop"
结论:宏定义代表字符串的时候,一定要带上双引号,可以用续行 ,双\
避免转义字符的存在.
使用宏充当注释
//程序翻译过程:
//预处理-E :头文件展开,去注释,宏替换->.i
//编译-S : 将干净的C语言,编译成为汇编语言->.s
//汇编-c :将汇编翻译成为目标二进制文件->.o
//链接 :将目标二进制文件与相关库链接,形成可执行程序
去注释和宏替换谁先进行
- 先进行去注释然后宏替换.
用define宏定义表达式
在if判断语句之后多条语句没有{}导致出错
- 简单宏替换出现编译报错
- 宏替换多条语句封装进
do{}while(0)
句式之中(先执行再判断,执行一次就行)
#include<stdio.h>
#define INIT_VAL(a,b) do{a=0;b=1;}while(0)
int main()
{
int x=10;
int y=20;
int flag=0;
scanf("%d",&flag);
if(flag)
INIT_VAL(x,y);
else
{
x=100;
y=200;
}
printf("%d-%d
",x,y);
return 0;
}
定义不能带空格
#include <stdio.h>
#define INC(a) ((a)++) //定义不能带空格
# define NUM 10 //define前面可以加空格(但是不建议)
int main()
{
int i = 0;
INC (i); //使用可以带空格,但是严重不推荐(不要处处显得自己不一样哦)
printf("%d
", i);
}
#undef
宏可以在代码的任何地方定义.作用范围是从定义处往后都可.
- 源文件的任何地方,宏都可以定义,与是否在函数内外没关系.
- 宏替换是在函数调用之前的.
after #undef
,取消宏或者宏的作用范围限制结尾处.
int main()
{
#define X 3
#define Y X*2
#undef X
#define X 2
int z = Y;
printf("%d
", z);//4
return 0;
}
条件编译
宏是否被定义 VS 宏是否为真or假
#define DEBUG
#define DEBUG 1
#define DEBUG 0
#ifdef
ifndef
:判定的是宏是否被定义
#if-#endif
:宏定义是否为真
宏定义进行多条件筛选
#include<stdio.h>
2 int main()
3 {
4 #if VERSION==1
5 printf("hello VERSION==1
");
6 #elif VERSION==2
7 printf("hello VERSION==2
");
8 #elif VERSION==3
9 printf("hello VERSION==3
");
10 #else
11 printf("hello default version
");
12 #endif
13 return 0;
14 }
#ifdef <==>#if defined() #ifndef <==>#if !defined()
#include <stdio.h>
#define DEBUG
int main()
{
#if defined(DEBUG)
printf("hello debug
");
#else
printf("hello release
");
#endif
return 0;
}
//演示#if模拟#ifndef
#include <stdio.h>
//#define DEBUG
int main()
{
#if !defined(DEBUG)
printf("hello debug
");
#else
printf("hello release
");
#endif
return 0;
}
//code1
#include <stdio.h>
#define C
#define CPP
int main()
{
#if defined(C) && defined(CPP)
//#if (defined(C) && defined(CPP))
printf("hello c&&cpp
");
#else
printf("hello other
");
#endif
return 0;
}
//Code 2
#include <stdio.h>
#define C
#define CPP
int main()
{
#if defined(C) || defined(CPP)
//#if (defined(C) || defined(CPP))
//#if !(defined(C) && defined(CPP))
printf("hello c&&cpp
");
#else
printf("hello other
");
#endif
return 0;
}
条件编译支持嵌套
int main()
{
#if defined(C)
#if defined (CPP)
printf("hello CPP
");
#endif
printf("hello C
");
#else
printf("hello other
");
#endif
return 0;
}
多条件检测宏是否被定义
#include <stdio.h>
//#define C
//#define CPP
int main()
{
#if defined(C)
printf("hello C
");
#elif defined (CPP)
printf("hello CPP
");
#else
printf("hello other
");
#endif
return 0;
}
为什么要有条件编译
- 通过裁剪代码,快速实现某种目的(版本维护),功能裁剪,跨平台性.
本质认识:条件编译,其实就是编译器根据实际情况,对代码进行裁剪。而这里“实际情况”,取决于运行平台,代码本身的业务逻辑等。可以认为有两个好处:
- 可以只保留当前最需要的代码逻辑,其他去掉。可以减少生成的代码大小
- 可以写出跨平台的代码,让一个具体的业务,在不同平台编译的时候,可以有同样的表现
举一个例子吧
我们经常听说过,某某版代码是完全版/精简版,某某版代码是商用版/校园版,某某软件是基础版/扩展版等。其实这些软件在公司内部都是项目,而项目本质是有多个源文件构成的。所以,所谓的不同版本,本质其实就是功能的有无,在技术层面上,公司为了好维护,可以维护多种版本,当然,也可以使用条件编译,你想用哪个版本,就使用哪种条件进行裁剪就行。
著名的Linux内核,功能上,其实也是使用条件编译进行功能裁剪的,来满足不同平台的软件。
文件包含
#pragma once
& 条件编译的方式
第一次宏未定义,会立即定义.第二次之后因为#ifndef
不再执行.
什么叫头文件展开?
将头文件的内容拷贝到目标文件可用过test.i中的内容对比发现.
如果源文件包含了很多次头文件,如果不做条件编译就会包含很多次冗余的代码.
重复包含是错误吗?
主要是编译的效率问题.那么,重复包含一定报错吗??不会!
重复包含,会引起多次拷贝,主要会影响编译效率!同时,也可能引起一些未定义错误,但是特别少。
#error
核心作用是可以进行自定义编译报错.编译时直接中止.
#include <stdio.h>
//#define __cplusplus
int main()
{
//#error 你好啊
#ifndef __cplusplus
#error 老铁,你用的不是C++的编译器哦
#endif
system("pause");
return 0;
}
#line
本质其实是可以定制化你的文件名称和代码行号,很少使用.
#pragma
以编译通过的方式让编译器打出信息.
//#pragma message()作用:可以用来进行对代码中特定的符号(比如其他宏定义)进行是否存在进行编译时消息提醒
#include <stdio.h>
#define M 10
int main()
{
#ifdef M
#pragma message("M宏已经被定义了")
#endif
system("pause");
return 0;
}
#运算符
- 将参数符号s对应的文本内容转化为字符串.
- 相邻字符串(“”)具有自动连接特性.
//利用特性实现int->const char*
#define TOSTRING(x) #x
int main()
{
char* str[1024] = {0};
strcpy(str,TOSTRING(123456));//是预处理阶段处理
int a=123;
strcpy(str,TOSTRING(a));//a
//变量已经是运行之后才知道是啥数,所以只能打印出a
printf("%s
",str);
return 0;
}
##运算符
将左侧符号和右侧符号链接起来构成一个新符号.
- 无效符号
- 有效符号
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。