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*参数的接口

相关推荐
董世昌412 小时前
js怎样控制浏览器前进、后退、页面跳转?
开发语言·前端·javascript
闻缺陷则喜何志丹2 小时前
【计算几何】P12144 [蓝桥杯 2025 省 A] 地雷阵|普及+
c++·数学·蓝桥杯·计算几何
EXtreme352 小时前
栈与队列的“跨界”对话:如何用双队列完美模拟栈的LIFO特性?
c语言·数据结构·leetcode·双队列模拟栈·算法思维
南棱笑笑生2 小时前
20251211给飞凌OK3588-C开发板跑飞凌Android14时让OV5645摄像头以1080p录像
c语言·开发语言·rockchip
翔云 OCR API2 小时前
赋能文档的数字化智能处理:通用文字/文档/合同识别接口
开发语言·人工智能·python·计算机视觉·ocr
tang_shou2 小时前
STM32CubeMx使用STM32F4系列芯片实现串口DMA接收
c语言·arm开发·stm32·单片机·嵌入式硬件·mcu·stm32cubemx
hoiii1872 小时前
MATLAB实现HOG特征提取与SVM行人检测
开发语言·支持向量机·matlab
呱呱巨基3 小时前
C++ 红黑树
数据结构·c++·笔记·学习
JIngJaneIL3 小时前
基于Java酒店管理系统(源码+数据库+文档)
java·开发语言·数据库·vue.js·spring boot