当前位置: 首页 > news >正文

C的预编译指令

预编译指令

  • #include
    • 对于形如 ``#include "demo.h"`` 的指令:
    • 对于形如 ``#include <demo.h>`` 的指令:
  • #define
    • 简单宏替换
    • 带参数的宏
  • #ifdef, #ifndef, #if
  • #pragma
  • #error
  • #line

在C语言中,预编译指令用于在编译之前进行代码的预处理。

# 预编译
gcc -Wall -E hello.c -o hello.i 

#include

用于包含头文件

对于形如 #include "demo.h" 的指令:

  • step1: 编译器首先在当前目录中查找demo.h
  • step2: 未找到,编译器会检查通过-I选项指定的目录
  • step3:仍然未找到,编译器会继续在/usr/include/usr/local/include等标准系统路径中查找。

对于形如 #include <demo.h> 的指令:

编译器会跳过当前目录

  • step1:直接从-I选项指定的目录
  • step2:未找到,在标准系统路径下开始查找
    如果在所有指定的路径中都没有找到头文件,编译器会报错,指出无法打开包含文件。

#define

定义宏

本质就是预处理时,进行文本的匹配替换

简单宏替换

#define PI 3.14159
#include <stdio.h>
int main() {double radius = 5.0;double area = PI * radius * radius;printf("The area of the circle is: %f\\n", area);return 0;
}

带参数的宏

这种形式的宏类似于函数,可以接受参数并进行替换。

#define MACRO_NAME(PARAM1, PARAM2, ...)  replacement_text
#include <stdio.h>
#define PRINT_STRING(str) printf("%s\n", str)
int main() {char * msg="Hello, World!\n";PRINT_STRING(msg); // 展开为 printf("%s\n", msg);return 0;
}

在宏定义中使用参数的字符串表示,可以使用字符串化操作符 #

#include <stdio.h>
#define PRINT_MACRO(str) printf("The macro argument is str : %s\n", #str)int main() {PRINT_MACRO(Hello World); // 展开为printf("The macro argument is str : %s\n", "Hello World");return 0;
}

#ifdef, #ifndef, #if

进行条件编译

#ifdef#ifndef 仅检查一个宏是否已经定义,而不考虑宏的值
#if 可以检查任何常量表达式,后面跟宏的时候需要考虑宏的值。
常和#elif#else#endif结合使用

#ifdef MY_MACRO
// 如果 MY_MACRO 被定义,执行这里的代码
#elif defined(OTHER_MACRO)
// 如果 MY_MACRO 未被定义,但 OTHER_MACRO 被定义,执行这里的代码
#else
// 如果 MY_MACRO 和 OTHER_MACRO 都未被定义,执行这里的代码
#endif
#define FEATURE_A 1
#define FEATURE_B 0#if FEATURE_A && !FEATURE_B
// 如果 FEATURE_A 被定义并且其值不为零,且 FEATURE_B 未定义或其值为零,则编译这段代码
printf("Feature A is enabled, but Feature B is not.\n");
#endif

可以使用#undef取消宏定义

#pragma

向编译器发出特殊指令

#pragma pack 是一个非常有用的指令,用于控制结构体、联合体或类在内存中的对齐方式。通过调整对齐方式,可以优化内存使用,特别是在需要与硬件设备或特定协议进行交互时。

#pragma pack(push, 1)  // 设置对齐方式为 1 字节
struct MyStruct {char a;int b;
};
#pragma pack(pop)  // 恢复之前的对齐方式

#error

在编译时生成错误信息。

#line

改变编译器内部的行号和文件名。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • LabVIEW和Alicat Scientific质量流量计实现精确流量控制
  • 2024 React 和 Vue 的生态工具
  • STM32之八:IIC通信协议
  • 【数据分享】2013-2022年我国省市县三级的逐年SO2数据(excel\shp格式\免费获取)
  • websocket状态机
  • 关于正运动学解机器人手臂算法
  • 【学习笔记】无人机系统(UAS)的连接、识别和跟踪(六)-无人机直接C2通信
  • 海外社媒矩阵为何会被关联?如何IP隔离?
  • 学懂C语言(十五):C语言递归函数在实际应用中的要点,关键点
  • Diffusion大模型
  • 生成式 AI 的发展方向:Chat 和 Agent 的有机结合
  • 【Docker】Docker Desktop - WSL update failed
  • 粘包问题、mmap和分片上传
  • spring整合mybatis,junit纯注解开发(包括连接druid报错的所有解决方法)
  • [web]-反序列化-base64
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • 3.7、@ResponseBody 和 @RestController
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • CSS选择器——伪元素选择器之处理父元素高度及外边距溢出
  • Druid 在有赞的实践
  • golang中接口赋值与方法集
  • iOS动画编程-View动画[ 1 ] 基础View动画
  • LeetCode541. Reverse String II -- 按步长反转字符串
  • react-native 安卓真机环境搭建
  • SpringBoot 实战 (三) | 配置文件详解
  • spring学习第二天
  • Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比...
  • 爬虫进阶 -- 神级程序员:让你的爬虫就像人类的用户行为!
  • 前端工程化(Gulp、Webpack)-webpack
  • 学习ES6 变量的解构赋值
  • ​字​节​一​面​
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • $NOIp2018$劝退记
  • (04)odoo视图操作
  • (Java)【深基9.例1】选举学生会
  • (python)数据结构---字典
  • (个人笔记质量不佳)SQL 左连接、右连接、内连接的区别
  • (离散数学)逻辑连接词
  • (转)MVC3 类型“System.Web.Mvc.ModelClientValidationRule”同时存在
  • .halo勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET Core 和 .NET Framework 中的 MEF2
  • .NET CORE使用Redis分布式锁续命(续期)问题
  • .NET MVC、 WebAPI、 WebService【ws】、NVVM、WCF、Remoting
  • .net 打包工具_pyinstaller打包的exe太大?你需要站在巨人的肩膀上-VC++才是王道
  • .net 开发怎么实现前后端分离_前后端分离:分离式开发和一体式发布
  • .NET 线程 Thread 进程 Process、线程池 pool、Invoke、begininvoke、异步回调
  • .netcore 如何获取系统中所有session_ASP.NET Core如何解决分布式Session一致性问题
  • .NET关于 跳过SSL中遇到的问题
  • .NET实现之(自动更新)
  • @RequestParam @RequestBody @PathVariable 等参数绑定注解详解
  • @vueup/vue-quill使用quill-better-table报moduleClass is not a constructor
  • [ vulhub漏洞复现篇 ] Grafana任意文件读取漏洞CVE-2021-43798
  • [20190401]关于semtimedop函数调用.txt
  • [AAuto]给百宝箱增加娱乐功能
  • [android] 切换界面的通用处理