您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > C/C++/C#

c语言的预处理/条件编译

时间:2019-08-02 12:07:32  来源:  作者:
c语言的预处理/条件编译,最全整理看这里

 

语言的编译过程中第一步进行的就是预编译了,预编译中就是执行#开头的语句,这些处理就是本篇总结的知识点,预处理和条件编译。

通俗的讲预处理就是编译器自动的帮我们上去整理一遍代码,它依据的规则(我们交代给他的嘱托)就是预处理指令和条件编译的指令。

编译器根据指令,将需要包含的代码整体复制放到要包含的文件中,检查条件编译的条件是否成立,删除用不到的代码,留下有用的代码,预处理的过程仅此而已。

要让编译器准确的完成我们交给他的任务,我们就必须准确的给它下达正确的命令,这些命令就是下面总结的内容了。只是常用到的知识点的总结,水平有限有错误在所难免欢迎指正。

1.预处理是c文件在编译前的处理过程。

这个过程包括如下几个内容:

  1. 删除注释
  2. 插入被#include包含的文件的内容
  3. 替换有#define定义的符号
  4. 确认条件编译具体该进行编译的部分

2.预定义器定义的符号(现成的)

这些符号是编译器自带的,不用我们自己定义,直接使用就可以。

一般在我们调试程序时,打印这些信息时使用它们。

  • __FILE__ :要进行编译的文件的文件名
  • __LINE__:文件该符号所在行得行号
  • __DATE__:文件被编译的日期
  • __TIME__:文件被编译的时间

3.#define 定义符号名的用法

  1. 为数值命名一个符号。

Eg: #define name stuff (很容易跟typedef搞混前后顺序)

用法:

  • 一般在程序的头部定义该语句,之后就可以用name去代替stuff写代码了。编译时语句中如果出现name,就会被预编译器替换成stuff。

b. 文本替换

Eg1:

#define Ret returnval 为简化名字的书写和阅读方便

Eg2:

#define Loop while(1); 可以替换一个语句,替换语句时注意“;”的问题

4.宏的使用

所谓的宏,其实是#define的文本替换的活用。

本质是是在文本替换的基础上,再追加一步,参数的替换。

Eg 1:

#define MAX(a,b) ( (a)>(b)?(a):(b))

在代码中的使用过程是这样的:

第一步:文本替换

maxnum=MAX(2,4); —> ( (a)>(b)?(a):(b));

第二步:参数代入

maxnum=( (2)>(4)?(2):(4));

到此预处理器的宏处理阶段完成。

5.宏的参数代入过程看起来很像是与函数的参数传递过程,有什么不一样呢?

  • 1.宏的参数不限制类型使用参数时也不需要声明类型,但是函数的参数必须声明(规定)参数类型。

宏的这个特点有时可以带入函数无法带入的参数类型,进行运算。

Eg :

#define MALLOC(n,type) ( (type)*) malloc( (n) * sizeof(type) ) )

带个数的结果:MALLOC(5,int ) —>(int*)malloc( (5)*sizeof(int) )

这里的参数type,函数是无法用参数进行传递的。

  • 2.实现机制不同,宏是通过预处理时文本替换实现,函数是通过运行时临时调用和返回,这就带来他们的优缺点:
  • 宏:不需要调用开销,执行频繁的简单计算,缺点会增加代码体积。
  • 函数:比较耗费系统资源,但不增加代码体积。
  •  

6.#运算符和##运算符

#:将将宏参数插入字符串中。

Eg :

#define PRINT(a) pirntf("the value of a is %d.n",(a) )

int b=2;

PRINT(b); => the value of a is 2.

#define PRINT(a) pronrf("the calue of "#a"is %d.n",(a) )

int b=2;

PRINT(b); => the value of b is 2.

  • ##:粘合剂 字符合并

Eg :

#define RENAME(A) NewName ## A

RENAME(3); => NewName3

7.宏的注意点

  • 宏名全大写字母表示
  • 每个参数必须加()
  • 宏的整体外面加一层括号
  • 不要在宏的末尾加分号
  • 替换文本(stuff)的内容太多可以用“”连接换行
  • 宏定义时:宏的参数列表(括号的左边)与宏名(name)之间不能有空格。在代码中使用无此规定
  • 宏的参数不能用 自增、自减等运算符,会有副作用

8.条件编译

  • 用法1:

#if 常量表达式

statements

#endif

Eg :常用的调试语句

#define DEBUG 1 //1:打开 ,0:屏蔽

#if DEBUG

printf("File is %s,Line is %d",__FILE__,__LINE__);

#endif

这样debug语句不会 影响程序本身运行。

  • 用法2:选择编译

#if 常量表达式

Statements;

#elif 常量表达式

Statements;

#elif 常量表达式

Statements;

#else

Statements;

#endif

预处理器从第一条依次判断常量表达式的真假(0为假),

  • 从前往后当一个为真时,就编译该分支的语句,忽略之后的所有 分支的语句,当所有的常量表达式均为假,才编译“#else”分支的语句。
  • 注意:这里的常量表达式,一般用是一个用#define 声明的常量,不要错误使用全局变量,或是const 修饰的只读变量。

9.文件包含

  • a.你编写被包含文件(.h)时,在文件头部加上:

#ifndef _FILENAME_H

#define _FILENAME_H

XXXX(其他语句)

#endif

来防止重复包含

  • b.包含文件时的写法分两种:
  • #incldue <FileName.h>
  • 使用尖括号的,这是指包含的文件时自带的库函数头文件
  • #include“FileName.h”
  • 使用双引号的,这是包含用户自己编写的头文件
  • 这两种的区别就是编译器搜索文件的方式不同。

在结束的时候,还是再说一下学习过程中的感想,预编译这块很容易被我们忽视,初学起来感觉难度并没有很大,但是这里可以深究的地方还是很多的,多看一看这方面的例子,或者稍复杂些的宏定义,就会有很容易掉坑里的感觉,而且这里出现的Bug是很不容易被发现的。在程序编写时,恰当的使用宏和条件编译会让程序的结构得到优化,在uboot中大规模的使用宏定义条件编译相关的语句来实现配置选择和功能的选择,所以说这部分的知识很重要,需要取细细研究。争取做到准确,熟练,快速的看懂,看的对宏的意图!



Tags:c语言   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
1.字符串数组+初始化char s1[]="array"; //字符数组char s2[6]="array"; //数组长度=字符串长度+1,因为字符串末尾会自动添&lsquo;\0&lsquo;printf("%s,%c\n",s1,s2[2]);...【详细内容】
2021-12-08  Tags: c语言  点击:(47)  评论:(0)  加入收藏
一、问题提出问题:把m个苹果放入n个盘子中,允许有的盘子为空,共有多少种方法?注:5,1,1和1 5 1属同一种方法m,n均小于10二、算法分析设f(m,n) 为m个苹果,n个盘子的放法数目,则先对...【详细内容】
2021-11-17  Tags: c语言  点击:(49)  评论:(0)  加入收藏
前言很多事不深入以为自己懂了,但真正用到项目上,才发现了问题。曾以为自己写C语言已经轻车熟路了,特别是对软件文件的工程管理上,因为心里对自己的代码编写风格还是有自信的。(...【详细内容】
2021-08-27  Tags: c语言  点击:(84)  评论:(0)  加入收藏
C语言作为高级语言,用其编写的程序指令机器并不能识别,因此需要有一个编译器将其转换为机器可识别的二进制指令。C语言已经出现50多年的时间,其相关的编译器种类众多,从最早先的...【详细内容】
2021-08-24  Tags: c语言  点击:(132)  评论:(0)  加入收藏
一 什么是ANSI控制码(ANSI escape sequences)维基百科给出的解释如下:ANSI escape sequences are a standard for in-band signaling to control cursor location, color, font...【详细内容】
2021-08-02  Tags: c语言  点击:(167)  评论:(0)  加入收藏
字符分类: 宽字符函数普通C函数描述 iswalnum() isalnum() 测试字符是否为数字或字母 iswalpha() isalpha() 测试字符是否是字母 iswcntrl() iscntrl() 测试字符是否是控制符...【详细内容】
2021-07-19  Tags: c语言  点击:(132)  评论:(0)  加入收藏
取消宏定义定义变量的时候,不能够重复定义同名变量;同理,定义宏的时候,不可以重复定义同名的宏。例如:#define MAX 1000#define MAX 50此时,重复定义MAX宏,是不合法的代码。但是,我...【详细内容】
2021-07-13  Tags: c语言  点击:(124)  评论:(0)  加入收藏
函数参数传递指针变量在函数的定义中,函数的参数可以是各种变量,就包括指针变量。首先,我们来看看一个函数的定义:void func(char* p);该函数的名称叫做func,参数定义为 char* p...【详细内容】
2021-07-09  Tags: c语言  点击:(135)  评论:(0)  加入收藏
8 函数嵌套调用我们学习了函数的定义和使用,那么,函数在被调用之前,必须先进行定义或者声明。如下是一个程序测试例子: 程序运行结果如下: 可以看到,在main函数中调用了func函数。...【详细内容】
2021-07-03  Tags: c语言  点击:(351)  评论:(0)  加入收藏
程序输入与输出当我们操作一个linux终端的时候,执行linux命令程序,可以看到命令的输出信息,或者要求输入数据。那么,这些操作就是linux命令程序与用户进行交互。程序与用户的交...【详细内容】
2021-06-23  Tags: c语言  点击:(163)  评论:(0)  加入收藏
▌简易百科推荐
一、简介很多时候我们都需要用到一些验证的方法,有时候需要用正则表达式校验数据时,往往需要到网上找很久,结果找到的还不是很符合自己想要的。所以我把自己整理的校验帮助类分...【详细内容】
2021-12-27  中年农码工    Tags:C#   点击:(2)  评论:(0)  加入收藏
引言在学习C语言或者其他编程语言的时候,我们编写的一个程序代码,基本都是在屏幕上打印出 hello world ,开始步入编程世(深)界(坑)的。C 语言版本的 hello world 代码:#include <std...【详细内容】
2021-12-21  一起学嵌入式    Tags:C 语言   点击:(11)  评论:(0)  加入收藏
读取SQLite数据库,就是读取一个路径\\192.168.100.**\position\db.sqlite下的文件<startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0"/...【详细内容】
2021-12-16  今朝我的奋斗    Tags:c#   点击:(21)  评论:(0)  加入收藏
什么是shellshell是c语言编写的程序,它在用户和操作系统之间架起了一座桥梁,用户可以通过这个桥梁访问操作系统内核服务。 它既是一种命令语言,同时也是一种程序设计语言,你可以...【详细内容】
2021-12-16  梦回故里归来    Tags:shell脚本   点击:(18)  评论:(0)  加入收藏
一、编程语言1.根据熟悉的语言,谈谈两种语言的区别?主要浅谈下C/C++和PHP语言的区别:1)PHP弱类型语言,一种脚本语言,对数据的类型不要求过多,较多的应用于Web应用开发,现在好多互...【详细内容】
2021-12-15  linux上的码农    Tags:c/c++   点击:(17)  评论:(0)  加入收藏
1.字符串数组+初始化char s1[]="array"; //字符数组char s2[6]="array"; //数组长度=字符串长度+1,因为字符串末尾会自动添&lsquo;\0&lsquo;printf("%s,%c\n",s1,s2[2]);...【详细内容】
2021-12-08  灯-灯灯    Tags:C语言   点击:(47)  评论:(0)  加入收藏
函数调用约定(Calling Convention),是一个重要的基础概念,用来规定调用者和被调用者是如何传递参数的,既调用者如何将参数按照什么样的规范传递给被调用者。在参数传递中,有两个很...【详细内容】
2021-11-30  小智雅汇    Tags:函数   点击:(19)  评论:(0)  加入收藏
一、问题提出问题:把m个苹果放入n个盘子中,允许有的盘子为空,共有多少种方法?注:5,1,1和1 5 1属同一种方法m,n均小于10二、算法分析设f(m,n) 为m个苹果,n个盘子的放法数目,则先对...【详细内容】
2021-11-17  C语言编程    Tags:C语言   点击:(49)  评论:(0)  加入收藏
一、为什么需要使用内存池在C/C++中我们通常使用malloc,free或new,delete来动态分配内存。一方面,因为这些函数涉及到了系统调用,所以频繁的调用必然会导致程序性能的损耗;另一...【详细内容】
2021-11-17  深度Linux    Tags:C++   点击:(38)  评论:(0)  加入收藏
OpenCV(Open Source Computer Vision Library)是一个(开源免费)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android、ios等操作系统上,它轻量级而且高效---由一系列...【详细内容】
2021-11-11  zls315    Tags:C#   点击:(50)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条