Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
包括C/C+中的头文件+;不止一次 在C或C++ + 中包含头文件不止一次有用吗?_C++_C_Header Files - Fatal编程技术网

包括C/C+中的头文件+;不止一次 在C或C++ + 中包含头文件不止一次有用吗?

包括C/C+中的头文件+;不止一次 在C或C++ + 中包含头文件不止一次有用吗?,c++,c,header-files,C++,C,Header Files,如果这个机制从未被使用过,为什么编译器会担心包含一个文件两次;如果它真的没用,如果新的编译器确保每个头只包含一次,不是会更方便吗 编辑: 我知道有一些标准的方法可以做像和这样的事情,但是为什么你还要具体说明呢?编译器的默认行为不应该只包含一次文件吗?是的,只包含一次会更方便,这就是为什么要使用#pragma一次。在C++中: 编辑: 注:#pragma once不可移植。你可以用 #ifndef FILENAME_H #define FILENAME_H 如果您希望头文件具有可移植性,可以将其

如果这个机制从未被使用过,为什么编译器会担心包含一个文件两次;如果它真的没用,如果新的编译器确保每个头只包含一次,不是会更方便吗

编辑:


我知道有一些标准的方法可以做像和这样的事情,但是为什么你还要具体说明呢?编译器的默认行为不应该只包含一次文件吗?

是的,只包含一次会更方便,这就是为什么要使用#pragma一次。在C++中:

编辑:

注:#pragma once不可移植。你可以用

#ifndef FILENAME_H
#define FILENAME_H

如果您希望头文件具有可移植性,可以将其放在头文件的顶部。

是的,在使用预处理器生成代码时,或者在执行Boost.PP之类的技巧时,它非常有用

有关示例,请参见X宏。基本思想是该文件包含宏的主体,您定义参数,然后包含它。下面是一个人为的例子:

macro.xpp

std::cout << MESSAGE;
#undef MESSAGE
这还允许您在参数上使用
#if
和friends,这是普通宏无法做到的

#ifndef _INC_HEADER_
#define _INC_HEADER_

//header code

#endif
其中
标题
是标题的名称


例如,
main\u win.h
将是
\u INC\u main\u win\u

是的,包含一次以上的标题可能会很有用(尽管这是相当罕见的)。典型的例子是
,它根据是否定义了
NDEBUG
,以不同的方式定义了
asssert
。因此,将其包括在内是有意义的,然后对NDEBUG进行(通常是有条件的)定义,然后再次将其包括在内,并使用(至少可能)不同的
断言定义:

assert
宏根据
NDEBUG
的当前状态在每次
包括在内1

然而,大多数标题在成为幂等时都会遇到一些麻烦(即,无论它们被包含的频率有多高,都会产生相同的效果)


1C99,§7.2/1.

一个典型示例(未经测试)-要点是它将枚举列表考虑在内,以便它们在
枚举和流式代码中一致出现:

// states.h
X(Uninitialised)
X(Initialised)
X(Running)
X(Complete)
X(Shutdown)

// app.c++
#if defined(X)
# error X is already defined
#endif

enum States {
    #define X(TAG) TAG,
    #include "states.h"
    #undef X
    Extra_So_Trailing_Comma_Ignored
};

std::ostream& operator<<(std::ostream& os, const States& state)
{
    #define X(TAG) if (state == TAG) return os << #TAG;
    #include "states.h"
    #undef X
    return os << "<Invalid-State>";
}
//states.h
X(未初始化)
X(草签)
X(运行)
X(完整)
X(关闭)
//APP.C++
#如果定义(X)
#错误X已定义
#恩迪夫
枚举状态{
#定义X(标记)标记,
#包括“states.h”
#未定义X
多余的尾随逗号被忽略
};

std::ostream&operator当您需要一些不想手动维护的“枯燥”代码生成时,可以一次又一次地使用多重包含。 典型的例子是C/C++枚举和相应的字符串,大致如下所示:

// MYENUM_VALUES.H
MYENUMVALUE(a)
MYENUMVALUE(b)
MYENUMVALUE(c)
MYENUMVALUE(d)

// MYENUM.H
#define MYENUMVALUE(x) x,
enum MyEnum
{
#include "MYENUM_VALUES.H"
}
#undef MYENUMVALUE

// MYENUMTOSTRING.C
#define MYENUMVALUE(x) case x : return #x;

const char * MyEnumToString(MyEnum val)
{
    switch (val)
    {
    #include "MYENUM_VALUES.H"
    default return "unknown";
    }
} 
#undef MYENUMVALUE

我也不明白为什么人们会选择一个不可移植的解决方案,当一些代码> IFDEF并不难。在C++中,使用头保护。在不可移植的C++中,你使用“γ-语用”一次/我也从不理解在包含警卫中强制使用开始下划线;保留大写字母。只要从你的项目的名字开始。@ Als:我知道它是由新的MSVC,GCC和CLAN编译器支持的,但它仍然不是标准的C++,并且包含保护并不难。至于
#pragma one
更有效,我很想看到一些比较,因为至少GCC和clangrecognize包含了保护,并且对待它们非常类似于
#pragma
。下划线大写是保留的,不应该使用。不要被您的语句搞混:
其中HEADER是HEADER的名称
您可以给出任何名称,但不是强制的,它必须是头文件名。在C中,允许在枚举器列表中使用尾随逗号(正是这种情况)。在C++中是否有很大不同?@ UnurugGangor:在一个比特中挖了一圈——看起来它在C++ 03和更早的时候是不允许的,但是在C++ 11中添加了容忍。当然,即使在C++03下,特定的编译器也可能更宽容。是的,这应该是默认行为,因为这是常见的情况(他们可能定义了一个新的预处理器指令
#multipleincludes
或其他什么,用于罕见的需要多个包含的情况)。但C的设计目的是使编译器易于从头开始编写,而不易于编程。这在20世纪70年代是有意义的,当时有许多通用的体系结构,没有像
gcc
这样易于修改的开源编译器,程序很少超过10万行。这对2012年来说毫无意义。始终将常见情况作为默认情况!我认为这不是重复:它不质疑技术解决方案的目的,而是为了“包括”的实际目的。这是一个我只是想问的问题,而另一个不是。我正在评估重新开放的投票,并决定关闭它。即使这不是一个骗局,这个问题在本质上似乎是推测性的,并且很可能吸引基于观点的答案——这对于这个网站来说也是离题的。
// MYENUM_VALUES.H
MYENUMVALUE(a)
MYENUMVALUE(b)
MYENUMVALUE(c)
MYENUMVALUE(d)

// MYENUM.H
#define MYENUMVALUE(x) x,
enum MyEnum
{
#include "MYENUM_VALUES.H"
}
#undef MYENUMVALUE

// MYENUMTOSTRING.C
#define MYENUMVALUE(x) case x : return #x;

const char * MyEnumToString(MyEnum val)
{
    switch (val)
    {
    #include "MYENUM_VALUES.H"
    default return "unknown";
    }
} 
#undef MYENUMVALUE