【C语言基础】宏定义的用法详解

这篇具有很好参考价值的文章主要介绍了【C语言基础】宏定义的用法详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨
📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】
📢:文章若有幸对你有帮助,可点赞 👍 收藏 ⭐不迷路🙉
📢:内容若有错误,敬请留言 📝指正!原创文,转载请注明出处


引言:为什么使用宏定义?

✨C语言中,一般都不会直接使用常量,而是先将其定义为一个宏,然后在程序中使用该宏名,进而调用了这个常量。
修改方便。等我们需要修改这个常数时候,只需要在宏定义出修改一次即可。而不用到代码中到处去寻找,看哪里都用过这个常数。

一、宏定义的定义

在C语言中,宏定义是一种预处理指令,用于在编译之前将标识符替换为特定的值或代码片段。下面是几种常见的宏定义方式:

1. 简单宏定义

#define 宏名 值

示例:

#define PI 3.14159
#define N (321)

定义N等于321。N在使用过程中会被321完全代替。注意不需要加“;”。其次,赋值的数值最好加上小括号。

2. 参数化宏定义

#define 宏名(参数列表) 值或代码片段

示例:

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

3. 字符串化宏定义

#define STRINGIFY(x) #x

示例:

printf("宏名: %s\n", STRINGIFY(MAX));
// 输出: 宏名: MAX

4. 连接宏定义

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

示例:

int CONCAT(a, b) = 10;
// 相当于 int ab = 10;

5. 条件宏定义

#ifdef 宏名
#ifndef 宏名
#endif

示例:

#define DEBUG
#ifdef DEBUG
    printf("调试模式\n");
#endif

在这段代码中,#define DEBUG 表示定义了一个名为 DEBUG 的宏。#ifdef DEBUG 是一个条件编译指令,用于检查 DEBUG 宏是否已经定义。如果 DEBUG 宏已经定义,那么 printf(“调试模式\n”); 这行代码将会被编译,否则将被忽略。
在使用条件编译时,通过定义或取消定义宏,我们可以在编译时根据需要选择性地包含或排除代码。这对于在调试程序时输出额外的信息非常有用,以及在发布版本时禁用调试代码以提高性能。
如果在包含上述代码的文件的开头定义了 #define DEBUG,那么在编译时将会输出 “调试模式”。反之,如果没有定义 DEBUG 宏,那么这行代码将被编译器忽略,不会产生任何输出。
注意,#ifdef 是一个条件编译指令的开头,#endif 是条件编译指令的结尾,之间的代码将根据宏的定义情况进行编译或忽略。
因此条件宏的使用跟if else的选择结构语法类似,不同的是#ifndef或是#ifdef 后面跟的必须是一个定义了或是没有定义的宏;其次,它们还可以在函数内外都可以使用。

if defined

#ifdef的使用和#if defined()的用法一致
#ifndef又和#if !defined()的用法一致

7.特殊条件的宏定义

当 #if 后的条件为0时,对应的代码段会被预处理器忽略,相当于被注释掉。
当 #if 后的条件为1时,对应的代码段会被预处理器包含,相当于被保留下来用于编译和执行。

【C语言基础】宏定义的用法详解,# C语言,c语言,开发语言

8.宏定义嵌套宏定义

#define M (N+5)
#define S(r) (PI*r*r)

宏定义的分类:对象宏和函数宏(函数宏顾名思义,就是行为类似函数)
例如:

#define a 3.14
#define N (a*a)

9.宏定义没有值

宏定义可以没有具体的值,这种情况下宏名只作为一个标识符存在。在定义宏时,可以省略值部分,也就是不使用等号(=)或表达式。这样的宏定义通常用于条件编译或特定的标记。
例如,以下是一个没有具体值的宏定义的示例:

#define DEBUG_MODE

在上面的示例中,DEBUG_MODE 是一个宏名,它没有与之对应的具体值。这种宏定义通常用于在代码中插入调试相关的语句或区块。在编译过程中,可以通过检查宏名的定义与否来选择性地编译或执行相应的代码片段。
需要注意的是,没有具体值的宏定义在替换过程中,宏名会被直接替换为空。因此,如果在代码中使用该宏名,它将被替换为空,可能会导致语法错误或意想不到的结果。因此,在使用没有具体值的宏定义时需要谨慎。

二、宏定义需要注意的问题

📢1.宏定义一般在函数的外面。
📢2.宏定义必须要先定义,再使用宏。如果先使用就会编译报错。
📢3.宏定义中宏名一般使用大写,便于区分变量名。不是语法规定的,是一般约定俗成的。

【C语言基础】宏定义的用法详解,# C语言,c语言,开发语言

三、宏定义中为什么要加do和while(0)?

目的:在宏定义中添加do{...}while(0)结构的目的是为了将多个语句作为宏的一个整体,使其在代码中的使用更加灵活和安全。

宏展开后的代码会替代宏的调用部分,如果不使用do{...}while(0)结构,而是直接用花括号{...}包裹展开的代码,可能会导致在某些场景下产生语法错误或意想不到的行为。
下面是一些理由解释为什么要使用do{...}while(0)结构:

1.语法问题:do{...}while(0)结构保证了展开的代码作为一个完整的语句块存在。如果不添加这样的结构,并且将展开的代码用花括号包裹,可能会在某些情况下引起语法错误。使用do{...}while(0)结构能够确保展开的代码符合语法要求。

2.宏的调用位置:在一些特定的上下文中,宏的调用可能需要像普通的语句一样出现。例如,将宏用作函数调用的参数,或者将多个宏调用放在一个复合语句的条件部分。使用do{...}while(0)结构可以让宏的展开代码在这些情况下保持一致的行为。

3.语句的结束符号:由于宏展开后生成的代码可能包含多个语句,因此在每个语句的末尾都需要添加结束符号。使用do{...}while(0)结构可以确保在每个语句之后都添加了;分号,以避免语法错误。

总之,使用do{...}while(0)结构可以确保宏展开后的代码在各种上下文中具有一致的行为,避免语法错误,并且能够被作为单个语句来使用。这是一种常见的宏定义的惯用写法。

四、宏定义和typedef的相同作用

以下两种具有相同的作用

typedef unsigned short U16;
#define U16    unsigned  short 

编程规范:应尽可能使用函数代替宏

📢:常量建议使用 const 定义代替宏。
说明:宏对比函数,有一些明显的缺点:
1、宏缺乏类型检查,不如函数调用检查严格。
2、宏展开可能会产生意想不到的副作用,如#define SQUARE(a) (a) * (a)这样的定义,如果是 SQUARE(i++),
就会导致 i 被加两次;如果是函数调用 double square(double a) {reurn a * a ;}则不会有此副作用。
3、以宏形式写的代码难以调试难以打断点,不利于定位问题。
4、宏如果调用的很多,会造成代码空间的浪费,不如函数空间效率高。

【C语言基础】宏定义的用法详解,# C语言,c语言,开发语言文章来源地址https://www.toymoban.com/news/detail-657820.html

到了这里,关于【C语言基础】宏定义的用法详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Go语言Context (ctx)的基础概念与用法

    ctx 字面意思 上下文 ,是golang中特有的一种语法,几乎每一个程序中都会通篇传递着一个 ctx 。而一些框架又对其进行二次封装,诸如Gin框架中的 c *gin.Context 。因此此次进行 ctx 的学习并记录。 这是 ctx 的接口部分,其提供了一个接口及许多函数、结构体(如图)。 其通过

    2024年01月22日
    浏览(40)
  • 逍遥自在学C语言 | 位运算符的基础用法

    第一位闪亮登场,有请今后会一直教我们C语言的老师 —— 自在。 第二位上场的是和我们一起学习的小白程序猿 —— 逍遥。 位运算符是一组用于在二进制数之间进行操作的运算符 运算符 名称 示例 位与 a b | 位或 a | b ^ 位异或 a ^ b ~ 位取反 ~a 二进制左移 a 2 二进制右移 a

    2023年04月08日
    浏览(67)
  • C语言基础知识:宏定义

    目录 一.预处理 二.宏定义用法 ①宏常量 ②宏语句 ③宏函数 ④其它 1.#undef 是用来撤销宏定义的,用法如下: 2.使用ifndef防止头文件被重复包含和编译 三.宏定义相关作用符 ①换行符 \\\"\\\" ②字符串化符 \\\"#\\\" ③片段连接符\\\"##\\\" 四.宏函数的巧用 ①类型传递 ②传递数组 五.注意事项

    2024年02月06日
    浏览(43)
  • 【05】STM32·HAL库开发-C语言基础知识 | stdint.h介绍 | 位操作 | 宏定义的使用 | 条件编译 | extern声明 | typdef使用 | 结构体、指针、代码规范介绍。

      stdint.h 是从 C99 中引进的一个标准 C 库的文件,可以在MDK5的安装路径:D:MDK5.34ARMARMCCinclude中找到。   stdint.h 定义了很多类型别名,将有符号的char类型定义别名为int8_t等,使用此套别名有易于移植。   在MDK中需要配置才能支持使用S99标准, 默认是勾选的 。   只

    2024年02月08日
    浏览(43)
  • C语言 指针声明和定义 - C语言零基础入门教程

    目录 [一.指针简介] [1.内存] [2.内存地址] [3.指针声明] [二.指针类型] [三.声明并初始化一个指针] [1.声明指针并直接初始化 – 推荐] [2.先声明指针在初始化 – 不推荐] [四.查看指针地址和指针的值] [五.NULL 指针 – 空指针] [六.重点总结] [七.猜你喜欢] 零基础 C/C++ 学习路线推荐

    2024年03月22日
    浏览(40)
  • LangChain与大型语言模型(LLMs)应用基础教程:角色定义

    如果您还没有看过我之前写的两篇博客,请先看一下,这样有助于对本文的理解: LangChain与大型语言模型(LLMs)应用基础教程:Prompt模板 LangChain与大型语言模型(LLMs)应用基础教程:信息抽取 LangChain是大型语言模型(LLM)的应用框架,LangChain可以直接与 OpenAI 的 text-davinci-003、gpt-3.5-t

    2024年02月01日
    浏览(53)
  • C++语言基础——函数(详解)

    目录 函数是什么 函数的定义 主函数举例  空函数 函数的调用 语法格式 举例说明:计算x的n次方 递归 递归的主要点 递归的结构 条件 递归使用的场景 函数全名叫 计算机函数 ,它可以帮助你完成一些特定的程序。你可以把它简单理解成一把手枪。 手枪的作用: 完成几发子

    2024年01月21日
    浏览(56)
  • MySQL笔记(一):设计范式、基础概念、数据库定义语言DDL

    MySQL是一种数据库管理系统 (DBMS),是基于客户机-服务器的数据库; 分为两个不同的部分, 服务器软件(MySQL DBMS)是负责所有数据访问和处理的一个文件,这个软件运行在称为数据库服务器的计算机上,与数据文件打交道; 客户机则是与用户打交道的软件,对于用户提出的

    2024年02月03日
    浏览(59)
  • 自然语言处理基础详解入门

    自然语言是指人类社会约定俗成的,并且区别于人工语言(如计算机程序)的语言,,是自然而然的随着人类社会发展演变而来的语言,它是人类学习生活的重要工具。 自然语言处理(Natural Language Processing, NLP)是一门以计算机为工具,对书面或口头形式的语言 进行各种处理

    2024年02月16日
    浏览(48)
  • C语言基础入门----(5)数组详解

    Tips:本文主要面向C语言初学者及新手,属于系列文章,笔者借此巩固自身同时也希望帮助更多新人更快的入门,如有不当或错误,欢迎指正。 目录 前言 一、数组的定义 1.1数组的概念         1.2数组的定义格式 1.3注意事项  1.4数组元素的访问 1.5数组的特点  1.6常见错误:

    2024年02月04日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包