C/C++ ---条件编译#ifdef

一、迅速理解#ifdef/#ifndef

这两个是条件编译指令,核心:根据「宏是否定义」决定要不要编译某段代码,类比 "if 判断"。

指令 含义 类比普通代码
#ifdef A #else 如果宏 A 被定义过,就编译后续代码 if (A已定义) { ... }
#ifndef A #else 如果宏 A 没被定义过,就编译后续代码 if (A未定义) { ... }
#endif 结束条件编译(必须配对) }

简单来说条件语句有两个: #ifdef 和 #ifndef 如果定义了某个宏 如果没有定义某个宏?

要注意每一个条件语句都要有对应的结束匹配语句: #endif

1. 基础用法示例( 2 个场景)
场景 1:区分调试 / 发布模式(最常用)

运行 : 简单说 为什么编译器可以通过宏来确定,这个编译器做的处理之后我会用gcc编译器举例来说 gcc 可以带上宏选项

复制代码
// 第一步:定义/注释宏,控制逻辑
#define DEBUG  // 取消这行就是发布模式 debug理解为调试模式 

// 第二步:条件编译
#include <stdio.h>
int main() {
#ifdef DEBUG  // 如果定义了DEBUG,执行调试代码
    printf("调试模式:打印变量值\n");  // 发布时自动不编译这行
#else
    printf("发布模式:不打印调试信息\n");
#endif
    return 0;
}

像我们使用的IDE,可视化界面上有模式的选择,本质上就是在编译的时候,会带上对应的宏定义之后代码就会进行选择性的执行了

场景 2:防止头文件重复包含(#ifndef核心用法)

运行

cpp 复制代码
// 头文件 test.h 开头
#ifndef TEST_H  // 如果TEST_H没定义
#define TEST_H  // 立刻定义它,防止重复  

// 头文件的核心内容(函数、宏、结构体等)
void func();

#endif  // 结束条件编译

(这样多次#include "test.h"时,只有第一次会编译内容,避免重复定义错误)

二、C++11 下的NULL定义的代码含义以及nullptr的引入

2.1 C/C++下空指针: NULL是什么

cpp 复制代码
#ifndef NULL
#ifdef __cplusplus
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif

这段代码的意思: 条件编译: 如果NULL宏不存在,就执行下面语句: 如果是C++编译器 (__cplusplus 是c++编译器会加上的选项 )就执行 :

C++ 编译环境---》 让NULL就是0

C语言 编译环境下 ---》 NULL是 void*

2.2 C++为什么NULL为0&&nullptr哪来的

1. c语言弱类型属性 void*

cpp 复制代码
#include<stdio.h>

int main() {


	int* p1 = NULL;
	int* p2 = (void*)0;
	void* p = p2;
	int* pa = p; // 
	char* pc = p;// 发现 void*可以转换为其他任意任意的指针: int* char*

	return 0;
}

void* 可以赋值给 任意具体类型的指针

2. C++11 提出对类型的强制要求

  1. c++是强类型匹配 2. NULL会出现重载的小问题所以有nullptr

在c++中不允许void*类型赋值给具体类型的指针 因为C++类型的强类型匹配规则,

所以必须显式的写强转 : 如上面代码 int*pi = (int*) p p是一个void*类型

其次为什么 int* pi =NULL 因为0是唯一一个可以直接表示空指针的整数,所以用0啊

所以在C++中空指针本质上是用0来表示了,但是它有一个缺点就是 C++函数重载的时候:

如下:

cpp 复制代码
// 整数重载
void func(int a){;}
// 指针重载 
void func(int* a){;}

当我们调用函数 func(NULL)的时候 会优先匹配int的func这就有点彻底,我的NULL就是想表示空指针啊,你太过分了 。

所以引入了nullptr

nullptr

C++引入nullptr的原因就是因为想表示这就是一个空指针常量,注意我的描述它是常量不是宏就是一个指针常量而且是空指针 ,所以C++到这类型就得到一个闭环了。

3. c接口很多都是func(void* a)万能类型参数还能用吗 ?

答案是完全可用 : 如下表来参考这个关系:

|-----------------------------------------------------|---|
| | |
| int * = void* (这是不可以接受的赋值 类型不匹配c++不允许 ) | |
| void* = int* ; (这是可用接受的 因为void* 可用理解为空类型 或者万能类型) | |

没有报错:

如linux中 pthread的线程库就很多void*参数的接口

相关推荐
程序猿_极客1 小时前
【2025 年最新版】Java JDK 安装与环境配置教程(附图文超详细,Windows+macOS 通用)
java·开发语言·windows·macos·jdk
一个不知名程序员www4 小时前
算法学习入门 --- 哈希表和unordered_map、unordered_set(C++)
c++·算法
二哈喇子!4 小时前
BOM模型
开发语言·前端·javascript·bom
C++ 老炮儿的技术栈5 小时前
在C++ 程序中调用被 C编译器编译后的函数,为什么要加 extern “C”声明?
c语言·c++·windows·git·vscode·visual studio
二哈喇子!5 小时前
空指针异常
开发语言
咚为5 小时前
Rust Print 终极指南:从底层原理到全场景实战
开发语言·后端·rust
%xiao Q5 小时前
GESP C++五级-202406
android·开发语言·c++
Psycho_MrZhang5 小时前
Neo4j Python SDK手册
开发语言·python·neo4j
Traced back5 小时前
# C# + SQL Server 实现自动清理功能的完整方案:按数量与按日期双模式
开发语言·c#
Sarvartha5 小时前
C++ STL 栈的便捷使用
c++·算法