c++ifndef/define/endif头文件问题

头文件中的ifndef/define/endif有什么作用?

条件编译


#define ABCD 2
#include <iostream>
 
int main()
{
 
#ifdef ABCD
    std::cout << "1: yes\n";
#else
    std::cout << "1: no\n";
#endif
 
#ifndef ABCD
    std::cout << "2: no1\n";
#elif ABCD == 2
    std::cout << "2: yes\n";
#else
    std::cout << "2: no2\n";
#endif
 
#if !defined(DCBA) && (ABCD < 2*4-3)
    std::cout << "3: yes\n";
#endif
 
 
// 注意若编译器不支持 C++23 的 #elifdef/#elifndef 指令则会选择“不期待”块(见后述)。
#ifdef CPU
    std::cout << "4: no1\n";
#elifdef GPU
    std::cout << "4: no2\n";
#elifndef RAM
    std::cout << "4: yes\n"; // 期待的块
#else
    std::cout << "4: no!\n"; // 由于跳过未知的指令不期待地选择此块
                             // 并直接从 "#ifdef CPU" “跳”到此 "#else" 块
#endif
 
// 为修复此问题,我们可以条件性地仅若支持 C++23 指令 #elifdef/#elifndef
// 才定义 ELIFDEF_SUPPORTED 宏。
#if 0
#elifndef UNDEFINED_MACRO
#define ELIFDEF_SUPPORTED
#else
#endif
 
#ifdef ELIFDEF_SUPPORTED
    #ifdef CPU
        std::cout << "4: no1\n";
    #elifdef GPU
        std::cout << "4: no2\n";
    #elifndef RAM
        std::cout << "4: yes\n"; // 期待的块
    #else
        std::cout << "4: no3\n";
    #endif
#else // 不支持 #elifdef 时使用累赘的旧 `#elif defined`
    #ifdef CPU
        std::cout << "4: no1\n";
    #elif defined GPU
        std::cout << "4: no2\n";
    #elif !defined RAM
        std::cout << "4: yes\n"; // 期待的块
    #else
        std::cout << "4: no3\n";
    #endif
#endif
}
  • 建议你看下这篇博客👉 :c++预处理器概述 #define #ifdef #ifndef #endif
  • 除此之外, 这篇博客: c/c++头文件中#ifndef/#define/#endif的用法中的 下面给出#ifndef/#define/#endif的用法: 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • ifndef __XXX_H__    //意思是  "if not define __XXX_H__" 也就是没包含XXX.h
    define __XXX_H__   //就定义__XXX_H__
    ...  //此处放头文件中本来应该写的代码
    endif       //否则不需要定义 

    若未定义XXX.h则这里就定义XXX.h,然后运行里面的内容,若下次还走到了这个文件,则进行#ifndef的判断,则#ifndef与#endif之间的内容不会再次被载入
    但是,必须记住的是预处理器仍将整个头文件读入,即使这个头文件所有内容将被忽略。由于这种处理将减慢编译速度,所以如果可能,应该避免出现多重包含。

    补充:

  • 以下回答由chatgpt基于相关博客总结生成:

    ifndef/define/endif是C++中的预处理器指令,用于防止头文件被重复包含。

    ifndef是一个条件预处理指令,表示如果某个宏没有定义,则执行以下代码块。通常情况下,宏的命名使用两个下划线加上头文件的名称和后缀,以确保全局唯一性。

    define是一个宏定义指令,用于给一个已经定义的标识符(宏)赋予一个新的值。在头文件中,通常将宏定义为头文件的名称和后缀,以确保全局唯一性。

    endif是预处理指令的结束标志。

    通过使用#ifndef/define/endif,可以确保头文件只被包含一次,避免重复定义和无限循环编译的问题。

    下面是一个具体的解决方案示例:

    1. 头文件a.h的内容:
    #ifndef _A_H_
    #define _A_H_
    
    // 头文件a.h的代码
    
    #endif
    
    1. 头文件b.h的内容:
    #ifndef _B_H_
    #define _B_H_
    
    // 头文件b.h的代码
    
    #endif
    
    1. 源文件test.cpp的内容:
    #include "a.h"
    #include "b.h"
    
    // test.cpp的代码
    

    在预处理阶段,头文件a.h中的#ifndef指令会检查宏_A_H_是否已定义,如果未定义则继续执行下一行的#define指令,将宏_A_H_定义为真。此时头文件a.h中的代码会被执行。当编译器处理到头文件b.h时,由于宏_A_H_已经定义为真,ifndef块的代码将被跳过,避免了重复包含的问题。

    需要注意的是,虽然预处理器仍会读取整个头文件的内容,但在#ifndef/define/endif的作用下,不会再次执行已被定义的代码块。因此,应该避免多次包含相同的代码块,以提高编译速度。

    总结来说,使用#ifndef/define/endif可以确保头文件在编译过程中只被包含一次,避免了重复定义和无限循环编译的问题。编程时应该为每个头文件的开头和结尾都添加这些指令。

主要是避免头文件被重复包含。
比如说 my.h 头文件包含了 stdio.h
主程序同时包含了 stdio.h 和 my.h
那么如果stdio.h没有 ifndef ... ,那么其中的函数,就会被包含2次,相当于一个源代码里重复写了2个相同的代码,就会出错。