#define和预处理指令

本文深入解析C++预处理指令的作用及应用,包括如何避免代码重复引用、根据条件创建对象等场景,并通过实例代码演示具体实现。

#define和预处理指令--(妖妖随笔)

预处理过程是先于编译器对源代码进行处理(进行初步的转换),产生新的源代码提供给编译器。

格式:预处理指令是以#开头的代码行,#后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。

 

#空指令             没有任何效果

#include           引入一个源代码文件

#define             定义宏

#undef              取消定义宏

#if                    如果条件为真,则编译下面的代码

#elif                 如果前面的#if不为真,则编译下面的代码

#endif              结束一个#if...#elif条件编译块

#ifdef               如果已经定义了某个宏,则编译下面的代码

#ifndef             如果没有定义某个宏,则编译下面的代码

#error              停止编译并显示错误信息

 

1.防止重复引用的代码:

 

#ifndef A_H    意思是"if not define a.h"  如果不存在a.h

#define A_H   就引入a.h

#endif           否则不需要引入

 

 

#ifndef _OBJC_RUNTIME_H  //如果不存在_OBJC_RUNTIME_H

#define _OBJC_RUNTIME_H  //就引入_OBJC_RUNTIME_H(定义宏)

 

#include <objc/objc.h>   //引入文件

#include <stdarg.h>

#include <stdint.h>

#include <stddef.h>

#include <Availability.h>

#include <TargetConditionals.h>

 

#if TARGET_OS_MAC        //如果条件为真,就编译下面的代码

#include <sys/types.h>

#endif                   //结束条件编译块

 

 

2.根据条件创建一个Button:

        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];

        btn.frame = CGRectMake(0, 0, 100, 100);

        [btn addTarget:self action:@selector(btnClicked) forControlEvents:UIControlEventTouchUpInside];

        [self.view addSubview:btn];

 

但是根据新的需求,这个Button暂时不需要显示在界面上面,这时候可以使用预处理指令来进行条件判断

 

(1)第一种方法,定义一个具体的宏

#define _SHOWBTN_ 0

{

        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];

        btn.frame = CGRectMake(0, 0, 100, 100);

        [btn addTarget:self action:@selector(btnClicked) forControlEvents:UIControlEventTouchUpInside];

        [self.view addSubview:btn];

#if _SHOWBTN_

        [self.view addSubview:btn];  //如果需要显示按钮,将其添加到父视图中

#else

        //不将其添加到父视图中 

#endif

}

使用:这时候如果想显示该Button对象,那么将#define _SHOWBTN_ 1,否则写为#define _SHOWBTN_ 0

 

(2)第二种方法(定义一个没有数值的宏)

#ifdef _SHOWBTN_

  [self.view addSubview:btn];

#endif

 

这段代码的意思就是如果定义了宏_SHOWBTN_,那么就将btn添加到父视图,如果没有定义的话,那么不添加到父视图。

使用:这时候如果我们想要将其添加到父视图,则在文件的顶部写上#define _SHOWBTN_

转载于:https://www.cnblogs.com/yaoyao0110/p/4812144.html

### `#ifndef` `#define` 预处理指令的使用方法 在C/C++开发中,`#ifndef` `#define` 是常用的预处理指令,主要用于防止头文件的重复包含。当多个源文件包含同一个头文件时,如果没有适当的防护机制,会导致类型重定义、变量重复声明等问题。通过使用 `#ifndef` `#define`,可以确保头文件的内容在一次编译过程中只被处理一次。 基本使用格式如下: ```c #ifndef HEADER_NAME_H #define HEADER_NAME_H // 头文件内容,如结构体定义、函数声明等 #endif // HEADER_NAME_H ``` 其中,`HEADER_NAME_H` 是一个宏名称,通常与头文件名相对应,以确保唯一性。例如,对于 `gnss_imu.h` 文件,可以定义为 `GNSS_IMU_H` [^1]。 ### 常见错误及解决方法 1. **宏名称重复或命名不规范** 如果多个头文件使用相同的宏名称,可能导致条件编译失效,进而导致重复定义错误。例如: ```c #ifndef HEADER_H #define HEADER_H // 文件A的头文件内容 #endif ``` ```c #ifndef HEADER_H #define HEADER_H // 文件B的头文件内容 #endif ``` 上述两个头文件使用了相同的宏名,当它们同时被包含时,第二个头文件将不会被处理,导致潜在的编译错误。 解决方法:使用与文件名相关的唯一宏名,如 `GNSS_IMU_H`、`SENSOR_DATA_H` 等 [^5]。 2. **未正确闭合条件编译块** 忘记写 `#endif` 会导致预处理器无法正确结束条件编译块,从而引发语法错误或逻辑错误。 示例错误代码: ```c #ifndef GNSS_IMU_H #define GNSS_IMU_H typedef struct { float latitude; float longitude; } Data_GNSS_IMU; // 忘记添加 #endif ``` 解决方法:确保每个 `#ifndef` 都有对应的 `#endif`,并且注释中可以标明宏名以便识别 [^1]。 3. **宏定义与全局变量/函数名冲突** 如果宏名与全局变量或函数名相同,可能导致意外的替换行为。例如: ```c #define MAX 100 int MAX = 50; // 宏 MAX 被替换为 100,导致语法错误 ``` 解决方法:避免使用与变量或函数相同的宏名,建议宏名全部大写,并使用下划线分隔,如 `MAX_VALUE` [^5]。 4. **误用 `#ifdef` 或 `#if defined(...)`** 有时开发者使用 `#ifdef` 或 `#if defined(...)` 来判断宏是否定义,但若未正确使用,可能导致逻辑错误。例如: ```c #ifdef DEBUG && RELEASE // 该条件不会被正确解析 #endif ``` 正确写法应为: ```c #if defined(DEBUG) && defined(RELEASE) // 条件正确 #endif ``` 因为 `#ifdef` 只能判断一个宏是否定义,而 `#if defined(...)` 支持更复杂的逻辑表达式 [^2]。 5. **未启用C99或更高标准导致的结构体宏定义问题** 在某些编译器(如Keil)中,若未启用C99标准,可能无法正确识别匿名结构体或某些 `typedef` 定义方式,导致类型重定义错误。 解决方法:在编译器设置中启用C99标准支持。例如在Keil中,可在 `Options for Target -> C/C++ -> C Language` 中选择 `C99` 模式 [^4]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值