尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

预编译命令

预编译命令
📅 发布时间:2026/6/22 22:53:04
本文介绍了C/C++中的预编译命令,重点讲解了`#include`、`#define`、`#if`和`#pragma`的使用方法与注意事项。`#include`用于文件包含,支持尖括号和双引号两种查找方式,并可嵌套包含;通过条件编译或`#pragma once`避免重复包含。`#define`定义无参和带参宏,实现字符串替换,需注意加括号防止优先级错误,并区分其与`typedef`的不同。带参宏展开时不求值,影响运行结果。`#if`、`#ifdef`、`#ifndef`实现条件编译,控制代码段的编译与否。`#pragma`提供编译器指令,如`message`输出提示、`once`防重包含、`warning`控制警告、`comment`链接库文件、`pack`设置内存对齐。

预编译命令

#include

#include<文件名> 或者 #include"文件名"

功能:

先由预处理器删除这条指令,然后把指定的文件插入该命令行位置,使指定文件和当前的源程序文件连成一个文件。

注意:

  1. 一个include命令只能指定一个被包含文件。

  2. 使用尖括号:在包含文件目录中查找(即由用户事先在设置环境时设置的);使用双引号:首先在当前的源文件的目录中查找,若未找到才去包含目录中查找。

  3. 文件包含允许嵌套,即在一个被包含的文件中又可以包含另一个文件。

  4. 若在file1.c文件中写入:(注意前后顺序!)

    #include<file2.c>
    #include<file3.c>
    

    则file1.c和file3.c都可以使用file2.c的内容,而不必在file3.c中重复包含。为防止文件内容重复被包含就要合理使用条件编译。

  5. 被包含文件(file2.c)与其所在的文件(即用#include命令的源文件file1.c)在预编译后已成为同一个文件。
    因此如果file2.c中有全局静态变量,它也在file1.c文件中有效,不必用extern声明。

重复包含的解决方案:

1.如果头文件首尾均加上条件编译语句,就不会出现重复定义的编译错误。

这三行语句也可用一行 #pragma once 语句替代。详情

"head1.h"

#ifndef _HEAD1_H_
#define _HEAD1_H_
struct Stu{string name;int age;
};
#endif

"main.cpp"

#include "head1.h"
#include "head1.h"
int main(){return 0;
}

2.给可能重复在不同头文件中定义的结构体使用条件编译,就不会出现重复定义的编译错误。

"head1.h"

#ifndef _HEAD1_H_
#define _HEAD1_H_#ifndef _Stu
#define _Stu
struct Stu{string name;int age;
};
#endif#endif

"head2.h"

#ifndef _HEAD2_H_
#define _HEAD2_H_#ifndef _Stu
#define _Stu
struct Stu{string name;int age;
};
#endif#endif

"main.cpp"

#include "head1.h"
#include "head2.h"
int main(){return 0;
}

#define

无参宏定义

形式:

#define 标识符 字符串

功能:

用于指定标识符(宏名)代替字符序列(宏体)

#表示这是一条预处理命令,define为宏定义命令,“标识符”为所定义的宏名,“字符串”可以是常数、表达式、格式串等。

对源程序进行编译时,先由预处理程序进行宏置换,即用表达式代换所有宏名,然后再进行编译

注意:

1.宏定义的位置为任意,但一般情况下放在函数外面。

2.习惯上宏名用大写字母表示,以便与变量区别。但也可以用小写。

3.宏名的有效范围为从定义命令开始到 #undef PI 语句 或者 本源文件结束(如果没有#undef语句)

4.宏定义是用宏名表示一个字符串,只是进行简单的代换,不做任何正确性检查。如有错误,只能在编译已被宏展开之后的源程序时发现。

5.宏定义不是说明或语句,行末不必加分号;如加,一起置换。例:#define P printf("\n");

6.宏名在源程序中被引号括起来,则预处理程序不对其进行宏置换。例:printf("PI"); 输出:PI

7.宏定义允许嵌套但不允许递归。#define max max+10 是错误的

#define width 40         //长方形的宽 
#define length width+20  //长加宽,这里运用了嵌套 
var = length*2;          //计算周长

8.宏定义必要时要加圆括号,例如上例中宏展开为 var = 40+20 * 2 计算错误
应改为 #define length (width+20) 其宏展开为 var = (40+20) * 2 计算正确

9.宏定义可表示数据类型 #define LL long long ,但与用typedef定义数据说明符有区别:

宏定义只是简单的字符串代换,在预处理时完成;

typedef定义的数据说明符是在编译时处理的,它不是进行简单的代换,而是对类型说明符重新命名。

#define STU1 int *
typedef (int *) STU2
STU1 a, b;

宏代换后变成 int *a, b; a 是指向整型的指针变量,b 是整型变量。

STU2 a, b;

由于STU2是一个类型说明符,所以此时 a 和 b 都是指向整型的指针变量。

10.对“输出格式”进行宏定义可以减少书写工作量。

 #define P printf#define D "%d\n"#define F "%f\n"int a = 3;float b = 2.1;P(D F,a,b); 

含参宏定义

形式:

#define 宏名(形参表) 字符串

功能:

宏展开:形参用实参替换,其他字符保持不变。字符串中包含括号中的形参。

注意:

1.宏体及各形参外一般应加圆括号,避免宏展开后运算优先级发生改变。

#define POWER(x) ((x)*(x))

2.宏名和形参表间不能加空格。

3.宏定义可以实现某些函数的功能。

4.宏定义中的形参是标识符,而宏调用中的实参可以是表达式。

5.含参宏定义和函数的区别:

(1) 函数调用先求表达式的值,再带入形参。宏调用先进行宏展开,即字符串的替换。
如 POWER(i++) 会运行 (i++) * (i++) ,平方后 i 会自加 2 次而不是一次。

(2) 宏调用是通过宏展开完成的,在编译阶段进行,不占运行时间,只占编译时间。
函数调用是在程序运行时进行的,占运行时间(包括分配内存单元,保留现场,值传递和返回)

(3) 带参宏定义不存在类型问题,宏名无类型,参数也无类型,也不需要分配内存空间。
而函数却要求形参和实参类型必须保持一致,调用时也需要给形参分配临时的储存空间。

(4) 多次宏调用会使程序变长,而函数调用多次也不会使程序加长。

(5) 调用函数只能得到一个返回值,而用宏则可以设法得到多个结果。

连接符

字符串化操作符#
功能:

用于宏定义中,表示把参数字符串化,即把一个参数转换成字符串。

实例:
#include<iostream>
using namespace std;
#define PASTE(n) "abcdef"#n
int main() {printf("%s\n", PASTE(15));			//输出:abcdef15return 0;
}
符号连接操作符##
功能:

连接符,连接两个参数作为一个标识。

实例:

1.连接

#include<iostream>
using namespace std;
#define NUM(a,b,c) a##b##c				//连接
#define STR(a,b,c) a##b##c
int main() {printf("%d\n", NUM(1, 2, 3));		//输出:123
//	printf("%s\n", STR(aa, bb, cc));	//一些编译器会报错return 0;
}

2.变量的命名

#include <iostream>
using namespace std;
#define VAR(v) num##v				//变量的命名
int main() {int VAR(First) = 1;int VAR(Tail) = 2;int VAR(Cur) = 3;printf("%d %d %d", numFirst, numTail, numCur);	//输出:1 2 3return 0;
}

注意:

下面是一个错误示例:

#include <iostream>#define TRR1T 1
#define TRR2T 2#define MM(x) TRR##x##T * 10using namespace std;int main() {int i;cin >> i;cout << MM(2);			//正确输出 20 
//	cout << MM(i);			//[错误]'TRRiT' was not declared in this scope; did you mean 'TRR1T'?return 0;
}

宏定义的原理是原样替换,并不会根据 \(i\) 的值替换成 TRR1T ,而是直接替换成 TRRiT 。

一个可以参考的修改方案是:

#include <iostream>#define TRR1T 1
#define TRR2T 2#define MM(x) TRR##x##T * 10using namespace std;int main() {int i;cin >> i;switch (i) {case 1:cout << MM(1);	break;case 2:cout << MM(2);break;default:cout << "ERROR";break;}return 0;
}
字符化操作符#@
功能:

只能用于有传入参数的宏定义中,且必须置于有宏体的参数名前。作用是将传入的单字符参数名转换成字符,以一对单引号括起来。

实例:
#include <iostream>
using namespace std;
#define ToChar(c) #@c
int main() {putchar(ToChar(2));			//输出:2return 0;
}

#if

功能:

条件编译在预编译中执行,可以实现某些语句正常编译或者完全忽略,而程序中的if语句依然会全文编译。

形式:

1.

#if 常数表达式1程序段1
#elif 常数表达式2	//(可不写)程序段2
#else          	   //(可不写)程序段3
#endif

2.

#ifdef 标识符    //如果此宏名已经被定义(#define)过程序段1
#else          //(可不写)程序段2
#endif

3.

#ifndef 标识符      //如果此宏名没有被定义(#define)过程序段1
#else         	   //(可不写)程序段2
#endif

实例:

#include<iostream>
using namespace std;
int main() {
#ifndef ONLINE_JUDGE			//在测评网站上一般都有定义的这个宏freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);
#endifint a, b;cin >> a >> b;cout << a + b;return 0;
}

#pragma

1.#pragma message("消息文本")

功能:

当编译器遇到这条指令时,在编译输出窗口中将消息文本打印出来。

实例:

#include <iostream>
using namespace std;
#pragma message("This is a test.")
int main() {return 0;
}

点击“编译”后,编译器窗口中提示:[说明] '#pragma message: This is a test.'

2.#pragma once

功能:

在头文件的最开始加入这条指令就能够保证头文件被编译一次。详情

3.#pragma warning(command:错误代码)

功能:

设置警告信息状态。

disable:4066 //屏蔽代码为4066的警告信息

once:4066 //仅报告一次代码为4066的警告信息

error:4066 //将代码为4066的警告信息作为一个错误

4.#pragma comment(comment-type,"commentString")

说明:

comment-type 是一个预定义的标识符,指定注释的类型,一般用来加载静态库。

commentString 是一个为 comment-type 提供附加信息的字符串。

5.#pragma pack()

说明:

指定对齐长度:用于结构体、联合中。

相关新闻

  • 本地环境自建的es重启,http和https访问es,nested数据类型及设置es别名
  • 迈向人机共育的文明语法:AI元人文理论体系深度阐释——内观照叙事模型
  • Intellij扩展列表

最新新闻

  • UniLaViRA/HumanoidMimicGen/VERA/Tabero/S-Cheetah/FGO六大具身SOTA全网独家复现|零样本跨体导航/人形数据扩增/视频动作映射/触觉柔顺控力/仿生四足
  • 毕业设计 深度学习yolo藻类细胞检测识别(科研辅助系统)(源码+论文)
  • 鸿蒙 NDK开发:使用命令行CMake构建工程(三)
  • Windows系统文件FM20.DLL丢失找不到问题解决
  • 为什么你越讨好别人,越没人把你当回事?
  • Shell脚本为何成为AI智能体视觉(TVA)的“反射弧”(7)

日新闻

  • Arduino-ESP32项目深度解析:解锁隐藏芯片支持与架构演进
  • 2026年 系统窗厂家/品牌推荐榜单:隔音系统窗+高端系统门窗的核心优势与选购指南 - 品牌发掘
  • NVBench:首个双语非言语发声语音合成评测基准详解与实践

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号