预处理器宏

预处理——宏定义 有些时候,宏参数中的符号并非用来传递数据,而是用来形成多种不同的字串,例如在某些系统函数中,系统本身规范了函数接口的部分标准,形如// demo// 向用户提供一个方便整合字串的宏定义;定义粘贴宏printf("切换到wifi模式\n");printf("切换到飞行模式\n");printf("切换到5g模式\n");printf("切换到4g模式\n");int main()// 编译出错的时候查找问题,需要观察预编译的结果// gcc 4_粘贴宏.c -o a.i -E。 阅读详情

预处理器宏是C语言中的一个强大工具,它允许你定义符号和宏,用于代码替换和简化代码。宏是在预处理阶段处理的,即在实际编译代码之前。理解宏的语法和使用方式,可以使你的代码更加灵活和易维护。

基本语法

宏定义

宏定义使用 #define 指令,格式如下:

#define NAME replacement

其中,NAME 是宏名,replacement 是宏的替换文本。

示例

#define PI 3.14

#define MAX_LENGTH 100

这些定义告诉预处理器在源代码中将所有出现的 PI 替换为 3.14,将 MAX_LENGTH 替换为 100。

参数化宏

宏也可以带有参数,这使得它们更像函数。参数化宏的定义格式如下:

#define NAME(param1, param2, ...) replacement

其中,param1, param2, ... 是宏的参数,replacement 是使用这些参数的替换文本。

示例

#define SQUARE(x) ((x) * (x))

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

这些宏可以像函数一样使用:

int y = SQUARE(5); // 展开为:int y = ((5) * (5));

int max = MAX(3, 7); // 展开为:int max = ((3) > (7) ? (3) : (7));

可变参数宏

宏还可以定义可变参数,这类似于函数的可变参数。使用 ... 表示可变参数,并使用特殊标识符 __VA_ARGS__ 引用这些参数。

示例

#define PRINT(fmt, ...) printf(fmt, __VA_ARGS__)

使用时,可以传递任意数量的参数:

PRINT("Hello, %s!\n", "world"); // 展开为:printf("Hello, %s!\n", "world");

条件编译

预处理器还支持条件编译,用于根据条件包含或排除代码。

#if、#ifdef、#ifndef、#else、#elif、#endif

#define DEBUG

#ifdef DEBUG

    #define DEBUG_PRINT(fmt, args...) printf(fmt, ##args)

#else

    #define DEBUG_PRINT(fmt, args...)

#endif

预处理器宏示例详解

以下是一些更详细的宏使用示例及其解释:

示例 1:基本宏

#define PI 3.14159

#define MAX_LENGTH 1024

  • #define PI 3.14159:定义了一个宏 PI,它将在代码中替换为 3.14159。
  • #define MAX_LENGTH 1024:定义了一个宏 MAX_LENGTH,它将在代码中替换为 1024。
示例 2:参数化宏

#define SQUARE(x) ((x) * (x))

  • #define SQUARE(x) ((x) * (x)):定义了一个参数化宏 SQUARE,它将在代码中替换为 ((x) * (x))。例如,SQUARE(5) 将被替换为 ((5) * (5))。
示例 3:条件编译

#define DEBUG

#ifdef DEBUG

    #define DEBUG_PRINT(fmt, args...) printf(fmt, ##args)

#else

    #define DEBUG_PRINT(fmt, args...)

#endif

  • #define DEBUG:定义了一个宏 DEBUG。
  • #ifdef DEBUG:检查 DEBUG 是否被定义。
  • #define DEBUG_PRINT(fmt, args...) printf(fmt, ##args):如果定义了 DEBUG,定义 DEBUG_PRINT 为一个打印调试信息的宏。
  • #else:否则,
  • #define DEBUG_PRINT(fmt, args...):定义 DEBUG_PRINT 为一个空宏,不执行任何操作。
  • #endif:结束条件编译。

宏展开中的 ## 运算符

## 运算符用于连接两个符号,是一种预处理器宏的语法,用于处理可变参数宏,在宏定义中非常有用。## 用于表示可变参数列表,并且在参数为空时,会自动去掉前面的逗号。这使得宏定义更加灵活和易用。

示例

#define CONCAT(a, b) a##b

  • #define CONCAT(a, b) a##b:定义了一个宏 CONCAT,它将在代码中替换为 a 和 b 的连接。例如,CONCAT(foo, bar) 将被替换为 foobar。

详细示例:使用 ##args

当使用宏定义可变参数时,可以使用省略号 ... 来表示可变参数。##args 用于表示这些参数,并且在宏展开时,处理参数为空的情况。具体来说,如果没有传递可变参数,##args 会移除前面的逗号,从而避免语法错误。

宏定义

#ifdef HELLO_DEBUG

   #define PDEBUG(fmt, args...) printk(KERN_DEBUG fmt, ##args)

#else

    #define PDEBUG(fmt, args...)

#endif

使用 PDEBUG

PDEBUG("Hello, world!\n");

PDEBUG("Value is %d\n", value);

解释
  • PDEBUG(fmt, args...):定义了一个可变参数宏,fmt 是固定参数,args 是可变参数列表。
  • printk(KERN_DEBUG fmt, ##args):如果定义了 HELLO_DEBUG,PDEBUG 宏会调用 printk 函数,fmt 和 args 被替换为传递给宏的实际参数。

当你调用 PDEBUG 而不传递可变参数时,例如:

PDEBUG("Hello, world!\n");

宏会展开为:

printk(KERN_DEBUG "Hello, world!\n");

如果传递可变参数,例如:

PDEBUG("Value is %d\n", value);

宏会展开为:

printk(KERN_DEBUG "Value is %d\n", value);

处理参数为空的情况

##args 的作用在于处理可变参数为空的情况。例如,如果没有传递可变参数,宏会自动移除前面的逗号,从而避免语法错误。

没有 ##args 的情况:

#define PDEBUG(fmt, args...) printk(KERN_DEBUG fmt, args)

如果你调用 PDEBUG 而不传递可变参数:

PDEBUG("Hello, world!\n");

宏会展开为:

printk(KERN_DEBUG "Hello, world!\n",);

这会导致语法错误,因为 printk 函数多了一个多余的逗号。

有 ##args 的情况:

#define PDEBUG(fmt, args...) printk(KERN_DEBUG fmt, ##args)

如果你调用 PDEBUG 而不传递可变参数:

PDEBUG("Hello, world!\n");

宏会正确地展开为:

printk(KERN_DEBUG "Hello, world!\n");

总结

预处理器宏是C语言中一个非常灵活和强大的工具,适用于代码替换、参数化和条件编译。理解并正确使用宏可以使代码更简洁、更易维护。可变参数宏和条件编译特别有用,允许根据不同的编译条件生成不同的代码,从而使代码更具适应性和可调试性。

掌握C++预处理器与宏的奥秘 本文深入探讨了C++中预处理器和宏的使用,包括带参数的宏、#和##预处理器操作符、条件编译指令以及#define和#undef指令等。文章通过实例展示了宏的便捷性和潜在问题,同时指出了现代C++中推荐的替代方法,如内联函数和模板。 阅读详情

相关推荐

深入探索C预处理器指令与宏

本文深入探讨了C语言中的预处理器指令及其使用方法,重点介绍了宏替换指令的定义、类型和常见陷阱。通过具体案例,展示了对象式宏和函数式宏的定义、扩展过程以及如何在编程中避免常见的错误,如魔术空白字符、运算符优先级问题、参数副作用等。文章还介绍了字符串化/标记替换的概念及其在宏定义中的应用。

weixin_30700095的博客 296

预处理详解(宏)

预处理详解(宏)

m0_74343467的博客 454

Evolution of Heuristics: Towards Efficient Automatic Algorithm Design Using Large Language Model

启发式算法广泛用于处理复杂的搜索和优化问题。然而,启发式算法的手动设计通常非常耗费人力,需要丰富的工作经验和知识。本文提出了启发式算法的进化 (EoH),这是一种新颖的进化范式,它利用大型语言模型 (LLM) 和进化计算 (EC) 方法进行自动启发式设计 (AHD)。EoH 代表自然语言中的启发式概念,称为思想。然后由 LLM 将它们转换为可执行代码。进化搜索框架中思想和代码的演变使其在生成高性能启发式算法方面非常有效和高效。

weixin_43961909的博客 2162

预处理详解以及宏定义详解

在C语言中还有些内置的符号:__FILE__进行编译的源文件__LINE__文件当前的行号__DATE__文件编译的日期__TIME__文件被编译的时间__STDC__查看编译器是否遵循ANSI C,遵守为1这样就能知道源文件在哪里了;当我们明白#define定义标识符后,接下来介绍一个#define定义的一个新功能——宏定义;当我们想了解宏定义,首先需要了解宏定义的声明方式name定义的宏的名字一个符号表,会在stuff中出现stuff宏的内容。...

m0_64028711的博客 1338

【ros2】ros2_control 全面解析与实战指南

ros2_control 是 ROS2 生态中用于机器人实时控制的核心框架,旨在统一硬件接入接口、复用控制算法,避免重复开发,实现仿真与实机硬件的无缝迁移。其核心目标是简化不同硬件(传感器、执行器、完整系统)的集成流程,让开发者专注于控制逻辑而非硬件适配。创建类型功能包,依赖rclcpp。实现on_initupdate在中声明控制器插件,编译生成动态库。在 YAML 配置文件中指定自定义控制器类型,加载测试。

EnHengNa的博客 1475

PMAC上位机通信原理(C#)

基础是引用 两个 ODT dll 原理是先注册到communication.AsyncDataAvailable事件中去 if (bSuccess1) { communication.AsyncDataAvailable += communication_AsyncDataAvailable; } bool bSuccess2 = communication1.GPAsciiConnect(strIP, iPort, strName, strPassword); i

weixin_45507349的博客 1087

【C语言】C预处理器(宏、文件包含、条件编译...)

C语言预处理器。

风高秋月白,雨霁晚霞红 1万+

C#实战:如何用HslCommunication快速搞定三菱FX5U PLC通讯(附完整代码)

本文详细介绍了如何利用HslCommunication库在C#环境中快速实现与三菱FX5U PLC的通讯。通过实战代码演示,从环境搭建、建立连接、核心数据读写到构建健壮的监控服务,系统讲解了如何高效完成数据采集与交互,大幅提升工业自动化项目的开发效率。

s4t5u6v的博客 1200

预处理过程:宏

本文学习编译器在预处理过程中对宏的处理。Hightec编译器版本是tricore v4.9.1.0。 文章目录1 宏定义2 对象宏2.1 一个简单的对象宏2.2 多行宏定义2.3 宏定义的位置2.4 嵌套宏定义 1 宏定义 在C语言中,宏定义随处可见。通常来说,在C文件的最上面定义一个宏,然后在后面的代码中如果遇到了同样的片段,预处理器就把这段名字替换成定义好的内容。 宏定义分为两种,对象宏和函数宏。后文会利用编译器来研究这两种宏的基本用法。宏定义用 #define 来定义,例如下面就是把一个名为 #def

u013288925的博客 1706

Codex 实战 Skills:用 Skill 自动识别并提取 PDF/图片表格数据,效率提升 10 倍

本文介绍如何构建一个多模态文件解析 Skill,用于自动识别和提取 PDF/图片中的表格数据,提升 AI 智能体处理非结构化文档的效率。文章分析了传统方法的局限性,提出分层解析架构(预处理、检测、提取推理、后处理),推荐技术栈包括 pdfplumber、OpenCV 和多模态大模型。详细说明了 Skill 的元数据定义、数据模型设计(使用 Pydantic)和核心实现流程,通过混合策略实现从复杂文档到结构化 JSON/Markdown 的转换,使 AI 代理具备"阅读"多模态文档的能力。

yueyeguzhuo的专栏 305

YOLOv11改进策略【卷积层】| CVPR 2024 可变形卷积 v4(DCNv4)无界权重提表达 + 线程合并降冗余,强化模型收敛速度

DCNv4(Deformable Convolution v4)是一种专为广泛视觉应用设计的高效算子,它对DCNv3进行了关键改进,有效解决了DCNv3存在的速度慢和表达能力受限等问题。

Limiiiing的博客 925

预处理器定义宏

预处理器定义宏 宏(C/C++) 预处理在非预处理指令的所有行(即第一个非空白字符不是 # 的行)中展开宏,并在指令的某些部分(没有作为条件编译的一部分跳过)中展开宏。利用“条件编译”指令,您可以通过测试一个常量表达式或标识符取消对源文件的某些部分的编译,以确定将哪些文本块传递给编译器以及在预处理期间将从源文件中删除哪些文本块。 #define指令通常用于将有用标识符与常量、关键字和常用语句...

《好好先生》专栏 3663

redhawk:使用rh_setup.pl产生gsr模板

必须加的option工具会在rh_setup.pl给出提示,按照要求填写即可,另外工具会把所有填写的输入文件和信息放到rh_setup.init文件中,拷贝这个文件可在任何平级运行目录下,直接rh_setup.pl产生gsr以及run sta/dyn/em的脚本。rhsetup.pl -top top_cell_name -vdd_nets VDD 1.2 VDD2 1.2 -vss_nets VSS -frequency 100e6 (100m是默认值)更多学习内容请关注「拾陆楼」知识星球。

m0_61544122的博客 1053

第九章 疯狂Caché 宏和宏预处理器(一)

文章目录第九章 Caché ObjectScript宏和宏预处理器(一)使用宏创建自定义宏宏命名约定。宏空白约定宏注释和Studio助手保存自定义宏调用宏引用外部宏(包括文件)预处理器指令参考`#;``#Def1Arg``#Define`带值的宏宏值的约定没有值的宏JSON转义反斜杠限制`#Dim``#Else` 第九章 Caché ObjectScript宏和宏预处理器(一) CachéObjectScript编译器包括预处理器,CachéObjectScript包括对预处理器指令的支持。这些指令允许创建

yaoxin521123的博客 1209

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

CMake如何传递预处理器宏

如何将宏传递给预处理器?例如,如果我想是因为用户想要编写单元测试编译我的代码一些部分,我这样做: #ifdef _COMPILE_UNIT_TESTS_ BLA BLA #endif //_COMPILE_UNIT_TESTS_ 现在我需要将此值从CMake传递给预处理器.设置变量不起作用,那么我该如何实现呢? add_definitions(-DCOMPILE_UNIT_TESTS)(参见CMake的doc)或修改其中一个标志变量(CMAKE_CXX_FLAGS,或CMAKE_CXX_F

whl0071的专栏 1403

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

宏预处理器的非直译解释备忘

宏,数据结构体

weixin_40220242的博客 977

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

宏和预处理器详述

Macro(宏)来源于希腊语,意思就是大,远.在计算机科学中指的是规则,这个规则指定了 输入和输出之间的关系(是不是优点类似于函数?).所有的宏都是一个概念,那就是输入 与输出之间的映射关系,这个和函数本质上是相同的.但是宏和函数处理方式基本上是不同 的,比如在C语言中,宏

小狼的窝 1662

C语言的宏和预处理器

预处理器在实际编译发生之前扮演着重要的角色,它处理各种预处理指令,这些指令包括宏定义(#define)、文件包含(#include)、条件编译(#ifdef、#ifndef、#if、#else、#elif、#endif),以及编译错误(#error)和行控制(#line)。在上述示例中,如果定义了DEBUG,那么Log宏将被替换为一个输出调试信息的printf调用;如果未定义DEBUG,则为一个空操作,这样可以轻松控制调试信息的输出。

STONE的博客 1371

宏之双刃剑:C/C++ 预处理器宏的威力、陷阱与现代化演进全解

本文系统梳理C/C++宏的七类核心用法:常量宏、函数式宏、条件编译、字符串化/拼接、可变参数宏、调试宏和防御性宏。深入分析各类宏的优势、典型陷阱及现代C++替代方案,指出宏在跨平台编译、调试开关等场景仍不可替代,但需警惕副作用、命名污染等问题。提出"能不用则不用,必须用则封装好"的黄金法则,帮助开发者在性能与安全间取得平衡,写出高效可靠的代码。

聚焦前沿科技与硬核技术底层拆解,深耕 AI、量子计算、WebAssembly 等核心领域,拒绝碎片化科普。以通俗语言讲透复杂原理,用干货内容拆解技术逻辑,助力从业者吃透核心、把握趋势,每篇都是可落地的深度技术沉淀。 1566

第九章 疯狂Caché 宏和宏预处理器(三)

文章目录 第九章 疯狂Caché 宏和宏预处理器(三)`#SQLCompile Select``#UnDef``##;``##Continue``##Expression``##Expression`和文字字符串`##Expression`嵌套`##Expression`、子类、`##SafeExpression``##Expression`如何工作的`##Function``##Quote``##SQL``##Unique`使用系统提供的宏可访问系统提供的宏系统支持的宏引用ADDSC(sc1, sc2)E

yaoxin521123的博客 1115

VS中添加预处理宏的方法 + 预处理器的预定义宏大全

VS中添加预处理宏的方法 原文地址:https://www.cnblogs.com/rainbow70626/p/6417928.html 除了在.c及.h中添加宏定义之外,还可以采用如下方法添加宏定义: 1、若只需要定义一个宏(如#define DEBUG),可以右键点击工程-->属性-->c/c++-->预处理器-->预处理器定义,点击下拉框中的编辑,输入想要定义...

weixin_41796049的博客 1万+

【C++】预处理器与宏及特殊类设计

C++ 预处理器是在编译之前对源程序进行处理的程序。它主要负责处理以开头的指令,如#include#define等。预处理器的操作可以对代码进行一些预处理,比如包含头文件、定义宏等,这些操作有助于代码的组织和编写。

Guiat的博客 1065

C语言系列10——预处理器与宏:代码的抽象化利器

在现代编程中,预处理器与宏是重要的工具,能够帮助程序员进行代码的抽象化和优化。本文将介绍define与const的区别与应用场景,条件编译的基本概念与应用,以及预定义宏的使用与实际场景。

theskylife的博客 1110

Unity中的预处理器宏

在这里,scriptingDefineSymbols属性包含要设置的预处理器宏的名称。可以使用逗号分隔多个预处理器宏。

qq_40454111的博客 473

C++ 预处理器、宏、#与##

参考:C++ 预处理器 | 菜鸟教程 一、预处理器 预处理器是一些指令,指示编译器在实际编译之前所需完成的预处理。 所有的预处理器指令都是以井号(#)开头,只有空格字符可以出现在预处理指令之前。预处理指令不是 C++ 语句,所以它们不会以分号(;)结尾。 我们已经看到,之前所有的实例中都有#include指令。这个宏用于把头文件包含到源文件中。 C++ 还支持很多预处理指令,比如 #include、#define、#if、#else、#line 等,让我们一起看看这些重要指令。 二、...

小橙子的博客 591
上一篇: ioctl操作实现的原理
下一篇: ## 运算符
Raymond430
博客等级 码龄7年 91粉丝 23原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值