当前位置:网站首页>预处理指令
预处理指令
2022-07-25 20:32:00 【聪明的骑士】
目录
2.#include "filename"与#include
一、预定义符号#define
1.内置符号
这些预定义符号都是语言内置的。
__FILE__ | 进行编译的源文件 |
__LINE__ | 文件当前的行号 |
__DATE__ | 文件被编译的日期 |
__TIME__ | 文件被编译的时间 |
__STDC__ | 如果编译器遵循ANSI C,其值为1,否则未定义 |
举个栗子:
#include<stdio.h>
int main()
{
printf("file:%s line:%d\n", __FILE__, __LINE__);
return 0;
}
//结果:file:D:\代码\预处理指令与宏\源.c line : 122.#define 定义标识符
//标识符和我们下面讲到的宏都只做文本的替换
#define MAX 1000
//标识符常量
#define MAX 1000;
//定义标识符时,后面不要写;可能会出现语法错误
#define MAX 1000
#define condition MAX>0;
if (condition)
max = MAX;
else
max = 0;
//在这里由于替换的部分包含;就变成了如下代码,这时语法也就错误了
if (1000>0;)
max = 1000;
else
max = 0;
#define reg register
//为 register这个关键字,创建一个简短的名字
#define do_forever for(;;)
//用更形象的符号来替换一种实现
#define CASE break;case
//在写case语句的时候自动把 break写上。
#define DEBUG_PRINT printf("file:%s\tline:%d\t \
date:%s\ttime:%s\n" ,\
__FILE__,__LINE__ , \
__DATE__,__TIME__ )
//如果定义的 stuff过长,可以分成几行写
//除了最后一行外,每行的后面都加一个反斜杠(续行符)
//这个符号只做换行使用,不会被读取为字符。3.#define定义宏
#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)。
下面是宏的申明方式:#define name( parament-list ) stuff
其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中。
注意:参数列表的左括号必须与name紧邻。如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。
#include<stdio.h>
#define MULTIPLE(X) X*X
//宏先传递参数10,然后将原来宏部分替换为10*10
//宏不会进行计算,表达式结果最后由程序计算
int main()
{
int a = 10;
printf("%d", MULTIPLE(a));
return 0;
}
//结果:100然而这样的定义是有问题的
#include<stdio.h>
#define MULTIPLE(X) X*X
int main()
{
printf("%d", MULTIPLE(5+1));
return 0;
}
//结果:11我们想要计算6的平方,结果却不对。这是因为宏只会替换,MULTIPLE(5+1)被替换为5+1*5+1,计算后结果当然等于11了
所以我们在定义宏时,各个部分和整体都要加上括号,总之在宏定义上不要吝啬括号
#include<stdio.h>
#define MULTIPLE(X) ((X)*(X))
int main()
{
printf("%d", MULTIPLE(5 + 1));
return 0;
}
//结果:36二、#与##
1.#
#include<stdio.h>
#define VALUE(A) printf("the value of "#A" is %d\n",A)
int main()
{
//printf这个函数可以打印多个字符串
//实现一个宏打印the value of 变量名 is 变量值
int a = 1;
VALUE(a);
int b = 2;
VALUE(b);
VALUE(b+1);
return 0;
}
//printf("the value of "#A" is %d\n", A)
//#A表示把A这个变量名转换为一个字符串
//VALUE(a);经过替换后:printf("the value of ""a"" is %d\n",a);也就能完成任务
//结果:the value of a is 1
//the value of b is 2
//the value of b+1 is 32.##
#define ADD_TO_SUM(num, value) \
sum##num += value;
int main()
{
int sum5 = ADD_TO_SUM(5, 10);//作用是:给sum5增加10.
printf("%d", sum5);
return 0;
}
//ADD_TO_SUM(num, value) sum##num += value;
//这里的num和value先进行替换,变为sum##5 += 10;
//然后##将sum和5合并起来,变为sum5 += 10;这两个指令符号基本上不会用到,看到认识就行
三、宏和函数
1.带有副作用的宏参数
#include<stdio.h>
#define MAX(a,b) ((a)>(b)?(a):(b))
int main()
{
int x = 5;
int y = 8;
int z = MAX(x, y);
printf("x=%d y=%d z=%d\n", x, y, z);
//替换:int z = ((5)>(8)?(5):(8))
//结果:x=5 y=8 z=8
z = MAX(x++, y++);
printf("x=%d y=%d z=%d\n", x, y, z);
//替换:int z = ((5++)>(8++)?(5++):(8++))
//第一步比较大小:5<8,结果为假,同时5和8加一,((6)>(9)?(6++):(9++))
//取后值9++,先使用赋值z为9,原数据后加一为10
//结果:x=6 y=10 z=9
return 0;
}2.宏的优势和缺点
宏的优点:
- 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹。
- 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可以适用于整形、长整型、浮点型等可以用于>来比较的类型。宏是类型无关的。
宏的缺点:
- 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
- 宏是没法调试的。
- 宏由于类型无关,也就不够严谨。
- 宏可能会带来运算符优先级的问题,导致程容易出现错。
3.宏和函数的对比
属 性 | #define 定义宏 | 函数 |
代 码 长 度 | 每次使用时,宏代码都会被插入到程序中。除了非常小的宏之外,程序的长度会大幅度增长 | 函数代码只出现于一个地方;每次使用这个函数时,都调用那个地方的同一份代码 |
执 行 速 度 | 更快 | 存在函数的调用和返回的额外开销,所以相对慢一些 |
操 作 符 优 先 级 | 宏参数的求值是在所有周围表达式的上下文环境里,除非加上括号,否则邻近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写的时候多些括号。 | 函数参数只在函数调用的时候求值一次,它的结果值传递给函数。表达式的求值结果更容易预测。 |
带 有 副 作 用 的 参 数 | 参数可能被替换到宏体中的多个位置,所以带有副作用的参数求值可能会产生不可预料的结果。 | 函数参数只在传参的时候求值一次,结果更容易控制。 |
参 数 类 型 | 宏的参数与类型无关,只要对参数的操作是合法的,它就可以使用于任何参数类型。 | 函数的参数是与类型有关的,如果参数的类型不同,就需要不同的函数,即使他们执行的任务是不同的。 |
调 试 | 宏是不方便调试的 | 函数是可以逐语句调试的 |
递 归 | 宏是不能递归的 | 函数是可以递归的 |
命名约定 | 宏所有字母都是大写 | 函数不要所有字母都是大写 |
四、条件编译
1.条件编译指令
1.基本条件编译
#if 常量表达式
//...
#endif//常量表达式由预处理器求值。
2.多个分支的条件编译
#if 常量表达式
//...
#elif 常量表达式
//...
#else
//...
#endif
3.判断是否被定义
#if defined(symbol)
#ifdef symbol
#if !defined(symbol)
#ifndef symbol
4.嵌套指令
#if defined(OS_UNIX)
#ifdef OPTION1
unix_version_option1();
#endif
#ifdef OPTION2
unix_version_option2();
#endif
#elif defined(OS_MSDOS)
#ifdef OPTION2
msdos_version_option2();
#endif
#endif2.举例
#include<stdio.h>
#define DEBUG
#define A
#define B 1
int main()
{
#ifdef DEBUG
printf("hello world\n");
#endif // DEBUG
//如果DEBUG被定义就进行编译
#undef A
//移除定义的A
#ifndef A
printf("haha\n");
#endif // !A
//如果A没被定义就进行编译
#if B == 1
printf("hhhhh\n");
#elif B == 2
printf("wwwww\n");
#else
printf("rrrrr\n");
#endif
//类似于if、else语句,表达式判断为真的时候就会编译内部的内容
return 0;
}五、文件包含
1.#include
我们已经知道, #include 指令可以使另外一个文件被编译。就像它实际出现于 #include 指令的地方一样。这种替换的方式很简单:预处理器先删除这条指令,并用包含文件的内容替换。这样一个源文件被包含10次,那就实际被编译10次
在前面加上#pragma once就会对重复的头文件只包含一次
#ifndef A
define A
include<stdio.h>
#endif
//这样也可以2.#include "filename"与#include
查找头文件直接去标准路径下去查找,如果找不到就提示编译错误。
#include "filename"程序查找头文件会先去程序的默认文件夹下寻找,然后去C语言内置的库中寻找。
#include 会直接去C语言内置的库中寻找。
其实,对于库文件也可以使用 ""的形式包含。但是这样做查找的效率就低些,当然这样也不容易区分是库文件还是本地文件。
总结:其实C语言还有很多的预处理指令,如#error、#pragma、#line等,我们可以去细细了解
C语言部分结束
边栏推荐
- 10. < tag dynamic programming and subsequence, subarray> lt.53. maximum subarray and + lt.392. Judge subsequence DBC
- Myormframeworkjdbc review and problem analysis of user-defined persistence layer framework, and thought analysis of user-defined persistence layer framework
- Technology cloud report: more than zero trust, the wild hope of Parra's "Digital Security Cloud strategy"
- PMP practice once a day | don't get lost in the exam -7.25
- Prescan quick start to master Lesson 19: prescan actuator configuration, track synchronization and non configuration of multiple tracks
- Advantages of network virtualization of various manufacturers
- QML combines qsqltablemodel to dynamically load data MVC "recommended collection"
- 【高等数学】【1】函数、极限、连续
- PreScan快速入门到精通第十八讲之PreScan轨迹编辑的特殊功能
- 股票软件开发
猜你喜欢

Clickhouse notes 02 -- installation test clickvisual

【NOI模拟赛】字符串匹配(后缀自动机SAM,莫队,分块)

9. < tag dynamic programming and subsequence, subarray> lt.718. Longest repeated subarray + lt.1143. Longest common subsequence

Technology cloud report: more than zero trust, the wild hope of Parra's "Digital Security Cloud strategy"

test

JVM(二十三) -- JVM运行时参数
![[advanced mathematics] [4] indefinite integral](/img/4f/2aae654599fcc0ee85cb1ba46c9afd.png)
[advanced mathematics] [4] indefinite integral
![[paper reading] unpaired image to image translation using cycle consistent advantageous networks](/img/73/69651dd8ecfdddd1cae13a1d223d51.png)
[paper reading] unpaired image to image translation using cycle consistent advantageous networks
[today in history] June 30: von Neumann published the first draft; The semiconductor war in the late 1990s; CBS acquires CNET

103. (cesium chapter) cesium honeycomb diagram (square)
随机推荐
Prescan quick start to master the special functions of prescan track editing in lecture 18
[today in history] July 2: BitTorrent came out; The commercial system linspire was acquired; Sony deploys Playstation now
Why did I choose to become a network engineer after graduating from weak current for 3 months
各厂商网络虚拟化的优势
Redis source code -ziplist
[cloud native] use of Nacos taskmanager task management
CarSim仿真快速入门(十五)—CarSim传感器仿真之ADAS Sensor Objects (1)
Difference Between Accuracy and Precision
网络RTK无人机上机测试[通俗易懂]
Docker 搭建 Redis Cluster集群
securecrt乱码解决方法[通俗易懂]
Cloud native, Intel arch and cloud native secret computing three sig online sharing! See you today | issues 32-34
Kubernetes advanced part learning notes
CarSim simulation quick start (XIV) - CarSim Simulink joint simulation
[MCU] 51 MCU burning those things
JS作用域与作用域链
Google pixel 6A off screen fingerprint scanner has major security vulnerabilities
[today in history] June 28: musk was born; Microsoft launched office 365; The inventor of Chua's circuit was born
Jmeter——接口测试
Timing analysis and constraints based on xlinx (1) -- what is timing analysis? What are temporal constraints? What is temporal convergence?
