• 宏名称通常都是由大写英文字母构成的
  • 宏名称里不可以包含空格
  • 用宏给数字起名字的时候不可以使用赋值运算符,不要自增自减
  • 可以在编写程序的时候直接使用宏名称替代数字,编译器在编译的时候会把程序里的宏替换成它所代表的数字

1. 为什么要使用宏?

1.1 名称直观:

宏可以用有意义的名称,比如使用PI去替代抽象的数值3.14,让代码更易懂。开发者看到PI时能直接联想到“圆周率”,而无需记忆数字的含义,尤其是在复杂程序中,这种直观性能显著提高代码的可理解性。

1.2 便于更新:

当需要修改宏代表的值时,如PI的精度从3.14调整为3.14159,只需在宏定义处修改一次,编译器会在预处理阶段自动替换所有引用该宏的地方。如果不使用宏,直接在代码中多出写死数值,修改时需要逐个查找并替换,不仅繁琐,还容易遗漏,增加出错风险。

2. 无参宏(基本宏)

#include<stdio.h>// 定义无参宏PI,代表圆周率3.14159
// 宏的作用:用有意义的名称替代常量,提高代码可读性
// 后续若需调整精度(如改为3.1415926),只需修改此处即可,所有引用处会自动替换
#define PI (3.14159)int main(void){float r = 0;printf("请输入一个半径值:");scanf("%f",&r);// 计算圆的面积:使用宏PI替代3.14159,代码更直观printf("圆的面积是:%g\n", PI * r * r);// 计算圆的周长:同样使用宏PI,确保所有圆周率值一致printf("圆的周长是:%g\n", 2 * PI * r);return 0;
}

3. 带参宏(类似函数的宏)

带参宏的特性:仅在预处理阶段做文本替换,不进行参数类型检查,适用于多种数据类型

#include<stdio.h>// 定义带参宏SQUARE,用于计算参数的平方
// 宏参数x:表示要计算平方的数值或表达式
// 替换文本((x)*(x)):外层和内层都加括号是为了避免因运算符优先级导致的计算错误
#define SQUARE(x) ((x)*(x)) int main(void){// 调用带参宏SQUARE,参数为整数5// 预处理阶段会替换为:((5)*(5)),结果为25printf("%d\n", SQUARE(5));// 调用带参宏SQUARE,参数为浮点数5.5// 预处理阶段会替换为:((5.5)*(5.5)),结果为30.25// 体现宏不检查类型的特性,可同时处理整数和浮点数printf("%lg\n", SQUARE(5.5));// 调用带参宏SQUARE,参数为表达式2+3// 预处理阶段会替换为:((2+3)*(2+3)),结果为25// 因宏定义中参数x被括号包裹,避免了"2+3*2+3"的错误计算printf("%d\n", SQUARE(2+3));return 0;
}

4. 编译时定义宏(通过编译选项)

无需在代码中用#define定义,可通过编译器选项-D在编译时指定宏的值

适用于需要根据不同场景(如调试/发布版本、不同硬件配置)动态修改宏值的场景

语法:gcc -D 宏名=值 源文件 -0 输出文件

例如:gcc -DSIZE=10 test.c -o test(定义SIZE为10)

也可以gcc -D SIZE=10 test.c -o test(定义SIZE为10)

// 代码中无需定义SIZE,编译时通过-D指定
#include<stdio.h>
int main(void){int arr[SIZE] = {}; // SIZE由编译选项指定for(int i=0; i<SIZE; i++){arr[i] = i + 100;}for(int i=0; i<SIZE; i++){printf("%d ", arr[i]);}return 0;
}

5. 宏运算符

  • #:将宏的参数转换为字符串(字符串化)。
    例:#define STR(x) #x,则STR(123)会替换为"123"
  • ##:将两个标识符连接为一个新的标识符(连接符)。
    例:#define JOIN(a,b) a##b,则JOIN(num,1)会替换为num1
#include <stdio.h>// 1. #运算符:将宏参数转换为字符串(字符串化)
#define STR(x) #x  // 定义宏STR,使用#将参数x转换为字符串// 2. ##运算符:将两个参数连接为一个新的标识符(连接符)
#define JOIN(a, b) a##b  // 定义宏JOIN,使用##连接a和b为新标识符int main(void) {// 测试#运算符printf("使用#运算符的结果:\n");printf("STR(123) = %s\n", STR(123));       // 替换为"123",输出字符串"123"printf("STR(abc) = %s\n", STR(abc));       // 替换为"abc",输出字符串"abc"printf("STR(3.14) = %s\n", STR(3.14));     // 替换为"3.14",输出字符串"3.14"// 测试##运算符printf("\n使用##运算符的结果:\n");int num1 = 100;        // 定义变量num1int num2 = 200;        // 定义变量num2printf("JOIN(num, 1) = %d\n", JOIN(num, 1));  // 连接为num1,输出100printf("JOIN(num, 2) = %d\n", JOIN(num, 2));  // 连接为num2,输出200// ##运算符也可用于函数名或其他标识符int student10 = 95;    // 定义变量student10printf("JOIN(student, 10) = %d\n", JOIN(student, 10));  // 连接为student10,输出95return 0;
}

6. 预定义宏(编译器自带)

预定义宏占位符含义
__FILE__%s所在文件名
__func__%s所在函数名
__LINE__%d所在行号
__DATE__%s编译该文件日期
__TIME__%s编译该文件时间

注意:前后都是两个下划线

#include<stdio.h>
int main(void){int* p = NULL;int a = 10;//p = &a;if(p == NULL){printf("指针为NULL\n");// 把一个大串拆成多个小串(编译器会自动拼接相邻字符串)// 以下使用C语言预定义宏输出调试信息:printf("文件:%s\n"  // __FILE__:预定义宏,所在文件名"函数:%s\n"  // __func__:预定义宏,所在函数名"行号:%d\n"  // __LINE__:预定义宏,所在行号"日期:%s\n"  // __DATE__:预定义宏,编译该文件日期"时间:%s\n", // __TIME__:预定义宏,编译该文件时间__FILE__, __func__, __LINE__, __DATE__, __TIME__);return -1; // 默认意外退出返回-1}return 0;      // 正常退出返回0
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/918136.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/918136.shtml
英文地址,请注明出处:http://en.pswp.cn/news/918136.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32内部读写FLASH

很多情况下&#xff0c;在STM32中写入一些数据&#xff0c;在某些不可控因素下其数据无法保存。因此,解决此问题就要用到FLASH.什么是内部 Flash&#xff1f; Flash 是一种非易失性存储器&#xff0c;STM32 的程序和常量数据就存在 Flash 中。它的关键特点是&#xff1a;特性说…

Oracle 12c + Pl/Sql windows系统下表空间创建、迁移,dmp备份导入,数据库字符集更改

一、开发环境 操作系统&#xff1a;win11 Oracle版本&#xff1a;12c Oracle 数据库字符集&#xff1a;AL32UTF8 Pl/Sql版本&#xff1a;14 二、表空间创建 表空间是 Oracle 数据库中一种重要的逻辑结构&#xff0c;它是数据库中数据文件的逻辑集合&#xff0c;用于存储数据库对…

GUI:QT简介

一、什么是QT&#xff1f;Qt是一套跨平台的 C 图形用户界面&#xff08;GUI&#xff09;应用程序开发框架&#xff0c;由挪威 Trolltech&#xff08;奇趣科技&#xff09;于 1991 年创建&#xff0c;2008 年被诺基亚收购&#xff0c;2012 年后由 Qt Company 负责维护。它广泛应…

oceanbase执行execute immediate create table提示无权限

问题&#xff1a;OB库4.2.5.4版本&#xff0c;执行到这一句的时候&#xff0c;报没有权限&#xff1a;[rootlnob ~]# obclient -h192.168.207.28 -P2881 -ugistarlnzyob -pxxxxxx -A Welcome to the OceanBase. Commands end with ; or \g. Your OceanBase connection id is 3…

滴滴招java开发

滴滴集团 北京&#xff08;岗位信息已经过jobleap.cn授权&#xff0c;可在csdn发布&#xff09;收录时间&#xff1a; 2025年08月01日职位描述 负责滴滴海外业务准入审核及反作弊相关系统的后端开发及系统维护&#xff1b; 职位要求 1、统招本科及以上学历&#xff0c;计算机科…

深入解析基于Zookeeper分布式锁在高并发场景下的性能优化实践指南

深入解析基于Zookeeper分布式锁在高并发场景下的性能优化实践指南 在大规模分布式系统中&#xff0c;如何保证多个节点对同一资源的有序访问&#xff0c;是提高系统稳定性与一致性的核心需求之一。Zookeeper 提供的分布式锁机制&#xff0c;以其简洁的原理和高可靠性&#xff0…

腾讯云CodeBuddy AI IDE+CloudBase AI ToolKit打造理财小助手网页

CodeBuddy 腾讯云CodeBuddy AI IDECloudBase AI ToolKit打造理财小助手网页 在线体验地址&#xff1a;理财小助手 在线仓库&#xff1a;https://cnb.cool/pickstars-2025/ai-financial-assistant &#x1f31f; Hello&#xff0c;我是摘星&#xff01; &#x1f308; 在彩虹般…

2025-08-08 李沐深度学习11——深度学习计算

文章目录1 模型构造1.1 自定义 MLP&#xff08;多层感知机&#xff09;1.1.1 __init__ (构造函数)1.1.2 forward (前向传播)1.2 使用自定义 MLP1.3 自定义 Sequential 类1.4 前向传播1.5 模块的嵌套使用2 参数管理2.1 参数访问2.2 嵌套模型2.3 参数初始化2.4 参数共享3 自定义层…

汇编语言和高级语言的差异

汇编语言与高级语言在以下几个方面存在重要的区别&#xff1a;缺少结构化流程控制。汇编语言不提供if/else、switch/case、for、while等高级控制结构&#xff0c;依赖于底层的无条件跳转和条件跳转指令来实现流程控制。这种基于标签和跳转的方式虽然极其灵活&#xff0c;但缺乏…

文件管理从基础到高级:文件描述符、超大文件切片重组与快速删除实战

文件管理从基础到高级&#xff1a;文件描述符、超大文件切片重组与快速删除实战目标读者&#xff1a;Linux/macOS 用户、后端/运维/数据工程师 环境默认&#xff1a;Linux&#xff08;GNU 工具链&#xff09;&#xff0c;macOS 类似&#xff1b;Windows 可使用 WSL1&#xff09…

RPC 解析

RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff09;是一种让分布式系统中的服务能够像调用本地函数一样调用远程服务的通信机制。以下是其核心原理、技术实现及组件的详细解析&#xff1a;&#x1f527; 一、RPC 核心工作原理&#xff08;10 步全流程&…

wstool的一个完整的工作流解析

moveit的仓库源码编译的时候使用的是wstool来拉取仓库的所有内容文件&#xff0c;其命令流程如下: wstool init src wstool merge -t src https://raw.githubusercontent.com/moveit/moveit/master/moveit.rosinstall wstool update -t src rosdep install -y --from-paths src…

对数函数分段定点实现

目录 一、原理介绍 二、代码实现 三、结果显示 四、移植到C语言中的应用 4.1. 定义定点数配置和参数 4.2. 实现分段查找函数 4.3. 实现 log10 近似计算函数 4.4. &#xff08;可选&#xff09;定点数转浮点数 一、原理介绍 之前的博文对数函数分段线性实…

qt系统--事件

文章目录qt系统事件处理鼠标事件鼠标移动事件处理键盘事件定时器事件窗口移动和大小改变事件结语很高兴和大家见面&#xff0c;给生活加点impetus&#xff01;&#xff01;开启今天的编程之路&#xff01;&#xff01; 作者&#xff1a;٩( ‘ω’ )و260 我的专栏&#xff1a…

Linux机器可直接使用的自动化编译文件

还在为了Linux机器上一遍遍输入编译指令苦恼吗&#xff1f;你需要make指令以及自己的makefile文件&#xff01;在makefile中写入自己的个性化指令&#xff0c;让编译速度飞起&#xff0c;支持多文件编译一下文件为个人应用&#xff0c;可以直接cp到相应项目的目录&#xff0c;每…

Linux学习-数据结构(哈希表)

1.哈希表1.哈希算法将数据通过哈希算法映射成一个关键值&#xff0c;存放都在同一位置实现数据的高效存储和查找&#xff0c;将时间复杂度尽可能降低至O&#xff08;1&#xff09;2.哈希碰撞多个数据通过哈希算法得到的键值相同&#xff0c;称为产生哈希碰撞3.哈希表构建哈希表…

Google Chrome <139.0.7236.0 UAF漏洞

【高危】Google Chrome <139.0.7236.0 UAF漏洞 漏洞描述 Google Chrome 是美国谷歌&#xff08;Google&#xff09;公司的一款Web浏览器。 受影响版本中&#xff0c;OpenscreenSessionHost::ReportAndLogError 方法的参数使用了 std::string_view 类型来接收错误消息。当一…

CentOS8 Stream 网卡配置及重启

在 CentOS 8 Stream 中&#xff0c;网卡配置已由 NetworkManager 管理&#xff0c;传统的 ifcfg-eth0 文件仍然支持&#xff0c;但推荐使用 nmcli 或 nmtui 工具进行网络配置和管理。以下是网卡配置及重启的详细步骤&#xff1a;1. 查看当前网卡状态列出所有网卡bash复制nmcli …

SpringMvc的原理深度剖析及源码解读

一、springmvc启动加载流程1、引入spring-web.jar包时&#xff0c;在这个包的META-INF/services/javax.servlet.ServletContainerInitializer文件中定义的加载类SpringServletContainerInitializer,提供给springmvc实现初始化的操作。2、在SpringServletContainerInitializer类…

【ESP32-menuconfig(1) -- Build Type及Bootloader config】

Build Type Bootloader configmenuconfig介绍Build typeCONFIG_APP_BUILD_TYPECONFIG_APP_BUILD_TYPE_PURE_RAM_APPCONFIG_APP_REPRODUCIBLE_BUILDCONFIG_APP_NO_BLOBSCONFIG_APP_COMPATIBLE_PRE_V2_1_BOOTLOADERSCONFIG_APP_COMPATIBLE_PRE_V3_1_BOOTLOADERSBootloader config…