[C.C++] C语言 宏

750 0
Honkers 2025-3-10 22:42:07 | 显示全部楼层 |阅读模式

目录

一、宏定义

1.1 预定义符号

1.2 预处理指令 #define

1.3 带有副作用宏定义

1.4 宏和函数的一个对比

​编辑

1.5 #undef

二、条件编译

2.1 #if、#else、#elif、#endif

2.2 #ifdef和#ifndef

2.3 C语言中如何通过条件编译来预防头文件的重复包含?


一、宏定义

在C语言中,宏定义是通过  #define 关键字实现的,它可以将被定义的标识符替换为相应的字符串或代码片段。宏定义主要用于简化代码、提高程序的通用性和易读性,同时也能在一定程度上提高程序的运行效率

1.1 预定义符号

在C语言中,预定义符号是由编译器提供的,它们具有特殊的含义和功能。

以下是C语言中的一些常见预定义符号及其用途:

  • __FILE__:表示当前源文件的文件名,可用于调试时显示文件名。 
  • __LINE__:表示当前代码所在的行号,可用于调试时显示代码位置。 
  • __DATE__:表示当前编译的日期,格式为"MMM DD YYYY",例如"Jul 29 2023"。 
  • __TIME__:表示当前编译的时间,格式为"HH:MM:SS",例如"10:30:36"。 
  • __STDC__:如果编译器遵循ANSI C标准,其值为1,否则未定义。这个符号通常用于检测编译器的兼容性。

在VS中(__STDC__)未定义,所以该编译器不支持ANSC l 标准,如下图:

1.2 预处理指令 #define

宏定义主要有两种类型:

  • 不带参数的宏定义和。
  • 带参数的宏定义。

不带参数的宏定义简单地将宏名替换为定义的字符串,例如:

  1. #define PI 3.14159
复制代码

带参数的宏定义除了进行简单的文本替换外,还会对参数进行计算。例如:

  1. #define S(a,b) a*b
复制代码

#define 定义的规则

  • 宏替换发生在预处理阶段,即编译前
  • 宏替换是简单的文本替换,不涉及计算
  • 宏替换不占用运行时间,只占用编译时间

1.3 # 和 ##

#操作符用于预编译时期,将宏参数转换为字符串。如图:

##操作符用于在预编译期间将两个宏参数连接起来,形成一个单独的标识符。如图:

1.3 带有副作用宏定义

例如,假设有一个宏定义MAX(a, b),它在预处理阶段展开为((a) > (b) ? (a) : (b))。如果使用MAX(x++, y++),预处理后的结果将是((x++) > (y++) ? (x++) : (y++))。这意味着x和y都将被自增两次,这可能并非程序员原本的意图。

正常情况下:

带有副作用情况下:

  • ret 返回的是7,自增了一次,在问好(?)前面。
  • a 的值是3 ,自增了一次,在问号(?)前面。
  • b 的值是8,自增了两次,在则问号前后各增加一次。
1.4 宏和函数的一个对比

相比之下,宏在预编译阶段将宏名替换为后面的替换体,避免了函数调用的开销。宏的展开是简单的文本替换,没有类型检查,因此可能会导致一些潜在的错误。然而,宏的使用可以提高代码的可读性和可维护性,并且在某些情况下,宏的使用可以提高程序的效率。

1.5 #undef

#undef是C语言预处理指令的一种,它的作用是取消之前通过#define指令定义的宏或符号常量

  1. #include <stdio.h>
  2. int main() {
  3. #define MAX 200
  4. printf("MAX = %d\n", MAX);
  5. #undef MAX
  6. int MAX = 10;
  7. printf("MAX = %d\n", MAX);
  8. return 0;
  9. }
复制代码

二、条件编译

条件编译的主要指令包括#if、#else、#elif、#endif、#ifdef和#ifndef。

2.1 #if、#else、#elif、#endif
  • #if用于判断表达式是否为真,如果为真则编译其后的代码;
  • #else用于与#if搭配,当前面的条件不满足时,编译#else后的代码;
  • #elif相当于#else和#if的结合,用于多个条件中的其他条件
  • #endif用于结束一个条件编译块;
2.2 #ifdef和#ifndef

#ifndef与#ifdef相反,用于判断一个宏是否未被定义,如果未被定义则编译其后的代码。

2.3 C语言中如何通过条件编译来预防头文件的重复包含?

1、使用#ifndef、#define、#endif预处理指令

  1. #ifndef MY_HEADER_H
  2. #define MY_HEADER_H
  3. // 头文件内容
  4. #endif
复制代码

当头文件第一次被包含时,由于没有定义MY_HEADER_H,编译器会执行#define指令,定义该宏。当头文件再次被包含时,由于该宏已被定义,编译器会跳过#ifndef和#endif之间的代码,从而避免重复包含。

2、使用#pragma once指令:

  1. #pragma once
  2. // 头文件内容
复制代码

这种方法的好处是不会出现宏名冲突的问题,且对于大型项目来说,可以提高编译速度。 

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Honkers

荣誉红客

关注
  • 4009
    主题
  • 36
    粉丝
  • 0
    关注
这家伙很懒,什么都没留下!

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行