当前位置:网站首页>C语言编译预处理详情以及宏和函数的对比
C语言编译预处理详情以及宏和函数的对比
2022-07-20 09:09:00 【JDSZGLLL】
目录
引言
我们对于编译的过程有一定的了解,大致过程可以参考下面这张图:
预定义符号
__FILE__ //进行编译的源文件
__LINE__ //文件当前的行号
__DATE__ //文件被编译的日期
__TIME__ //文件被编译的时间
__STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义
#include<stdio.h>
#include<windows.h>
int main()
{
printf("file:%s line:%d date%s time:%s\n", __FILE__, __LINE__, __DATE__, __TIME__);
Sleep(10000);
printf("file:%s line:%d date%s time:%s\n", __FILE__, __LINE__, __DATE__, __TIME__);
return 0;
}
运行结果如下:
可以知道,预定义符号是记录编译过程中的信息,在执行过程中不会改变。
#define
#define有两个作用:
1.定义标识符
#define MAX 1000
#define reg register //为 register这个关键字,创建一个简短的名字
2.定义宏
#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义
宏(define macro)。
#define SQUARE(x) x * x
不管是定义标识符还是宏,都是一个替代的过程,只是宏会传递参数。
3.#define 替换规则
在程序中扩展#define定义符号和宏时,需要涉及几个步骤:
1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换。
2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。
3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
4 #和##
int i = 10;
#define PRINT(FORMAT, VALUE)\
printf("the value of " #VALUE "is "FORMAT "\n", VALUE);
PRINT("%d", i+3);//产生了什么效果?
输出为:
the value of i+3 is 13
可以了解到#VALUE可以把VALUE中的内容以字符串形式保留,而不转化。
##可以把位于它两边的符号合成一个符号。
它允许宏定义从分离的文本片段创建标识符。
#define ADD_TO_SUM(num, value) \
sum##num += value;
...
ADD_TO_SUM(5, 10);//作用是:给sum5增加10.
5.宏和函数对比
属 性 | #define定义宏 | 函数 |
代 码 长 度 | 每次使用时,宏代码都会被插入到程序中。除了非常 小的宏之外,程序的长度会大幅度增长 | 函数代码只出现于一个地方;每 次使用这个函数时,都调用那个 地方的同一份代码 |
执 行 速 度 | 更快 | 存在函数的调用和返回的额外开 销,所以相对慢一些 |
操 作 符 优 先 级 | 宏参数的求值是在所有周围表达式的上下文环境里, 除非加上括号,否则邻近操作符的优先级可能会产生 不可预料的后果,所以建议宏在书写的时候多些括 号。 | 函数参数只在函数调用的时候求 值一次,它的结果值传递给函 数。表达式的求值结果更容易预 测。 |
带 有 副 作 用 的 参 数 | 参数可能被替换到宏体中的多个位置,所以带有副作 用的参数求值可能会产生不可预料的结果。 | 函数参数只在传参的时候求值一 次,结果更容易控制。 |
参 数 类 型 | 宏的参数与类型无关,只要对参数的操作是合法的, 它就可以使用于任何参数类型。 | 函数的参数是与类型有关的,如 果参数的类型不同,就需要不同 的函数,即使他们执行的任务是 不同的。 |
调 试 | 宏是不方便调试的 | 函数是可以逐语句调试的 |
递 归 | 宏是不能递归的 | 函数是可以递归的 |
简而言之,宏相比于函数更加灵活。
条件编译
1.
#if 常量表达式
//...
#endif
//常量表达式由预处理器求值。
如:
#define __DEBUG__ 1
#if __DEBUG__
//..
#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
#endif
文件包含
头文件在预处理之后会展开,为了防止空间浪费,要预防多次引用头文件,就有了两种方法:
#ifndef __HEAD_H__
#define __HEAD_H__
......
......
#endif
以及
#pragma once
边栏推荐
- 暑假打工 2 个 月,让我明白了 Keepalived 高可用的三种路由方案
- File文件改名字
- Network layer protocol -- IP protocol
- [C language brush leetcode] 729 My schedule I (m)
- php 生成sitemap
- SQL语句问题,不知道是否正确,求指导
- 大佬们,这个cdc采集Oracle的数据,为啥number类型采过来就变成了对象?
- Tp5.1 open the web address and output the web page code without transformation and rendering (template return $this- & gt; fetch() return view();)
- Spss-kmeans聚类实操
- string类
猜你喜欢
链表的应用
Network layer protocol -- IP protocol
SPSS kmeans clustering practice
Tp5.1 controller initialization initialize (inherit public file initialization)
【考研词汇训练营】Day 8 —— complete,traditional,extra,afford,professional,require
MySQL之知识点(十一)
C Entry series (XXV) -- Interface
字节跳动(抖音)软件测试月薪23K岗、技术总监三面面试题最新出炉
永久挂载镜像步骤
[postgraduate entrance examination vocabulary training camp] day 9 - vital, dynamity, previous, pray, transit, virile, invent
随机推荐
读大明王朝1566
php 收藏功能
Explanation of new basic surveying and mapping terms
「接口测试入门课」打卡学习 day09:微服务接口:怎么用Mock解决混乱的调用关系
Theoretical basis of multithreading
刚入门软件测试行业的女生就能月薪过万骗局解秘
PHP generates Sitemap
分类中ICO对象
大佬们,请问 PostgreSQL CDC ,PostgreSQL 必须配置逻辑复制吗? 目前部署的
Application of linked list
flv封装解析
redis 'module' 不是内部或外部命令?
试着换个角度理解低代码平台设计的本质
换个姿势做运维!GOPS 2022 · 深圳站精彩内容抢先看!
C语言:结构体——关于内存字节对齐图文详解
Linear table with sequential storage structure
SPSS kmeans cluster analysis operation
「接口测试入门课」打卡学习 day08:测试数据,是不是可以把所有的参数都保存到Excel中?
Usage of mappartitions in pyspark
Leetcode-152- maximum array of products