何时在一个文件中多次包含相同的标题是有用的?

时间:2014-07-24 20:44:29

标签: c++ c include header-files

我正在阅读一个文件中同一个标题的多个包含内容,并找到一个有趣的声明(link):

  

你有意识地使用头文件有几个技巧   多次包括它(这实际上提供了一个有用的   功能)。

据我所知,这些技巧可能在实际项目中不受欢迎和混淆(特别是因为人们会采取预防措施来防范多种内容,例如include guards#pragma once)。 但是,那些技巧是什么?我提出了一些想法,但希望看到一些实际的例子(理想情况下,安全和尝试)。

我的想法:

  • C中的伪模板,其中模板参数被预处理器定义替换。 它可以在没有包含的情况下完成,但功能可能太大或太多,因此制作单独的文件是有意义的。
  • 逐块结构/类构造(连接片段)。它可以帮助模拟C中的继承,并在使用公共成员定义结构时防止代码重复。
  • 查找表和其他编译时数据结构(同样,借助预处理器定义)。

2 个答案:

答案 0 :(得分:8)

#include "file"表示获取头文件并将其所有内容放入#include行。

我们通常使用标头进行类型定义以及向源文件添加前向声明。在文件中定义两次相同类型(循环包含将始终导致它)会产生编译错误,因此我们使用#ifndef#pragma once。 (或两者兼有)

但是我们也可以放置重复的代码和宏并将其包含几次,即使在同一个文件中也是如此。在这种情况下,我们不会使用#ifndef#pragma once。如果你这样做,你必须格外小心,只有在你知道自己在做什么的情况下才能这样做。

例如:如果在某些操作系统中调用特定的系统功能(或者甚至是ac宏,如:offsetof)会导致一堆警告,并且它会让您感到困扰,并且您确定你的代码很好,但是你不想禁用你在所有项目或文件上得到的所有警告,你只想在调用特定函数时禁用它。

//suppress the warnings: 
#if defined(__GNUC__)
  #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wreorder"
    #pragma GCC diagnostic ignored "-Wunused-function"
    #pragma GCC diagnostic ignored "-Wunused-variable"
    #pragma GCC diagnostic ignored "-Wsign-compare"
    #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
    #pragma GCC diagnostic ignored "-Wsequence-point"
  #endif
#endif // __GNUC__

//here you call the function...
func(x,y,z);

//unsupress: bring back the warnings to normal state
#if defined(__GNUC__)
  #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
    #pragma GCC diagnostic pop
  #endif
#endif // __GNUC__

这将使您的代码看起来非常脏,特别是如果您多次调用该函数。

一种可能的解决方案,(我不是建议它是最好的......)是制作2个标题,一个用于抑制警告,另一个用于取消抑制。

在这种情况下,您的代码可能如下所示:

#include "suppress.h"
func(x,y,z);
#include "unsuppress.h"

//.... more code come here 
//now when call it again:
#include "suppress.h"
func(x,y,z);
#include "unsuppress.h"

答案 1 :(得分:2)

&#39;标准&#39;示例是<assert.h>标头。包含它的效果取决于NDEBUG

的值
#include <assert.h>

void func1(void)
{
    assert(...);
}

#undef NDEBUG
#include <assert.h>

void func2(void)
{
    assert(...);
}

#define NDEBUG
#include <assert.h>

void func3(void)
{
    assert(...);
}

func1()中的断言处于活动状态,除非编译环境中的某些内容在包含NDEBUG时设置了<assert.h>func2()中的断言处于活动状态,因为在NDEBUG被包含时<assert.h>未定义。 func3()中的断言处于非活动状态,因为在NDEBUG被包含时定义了<assert.h>

话虽如此,我从未在现实生活中使用过此设施,但C标准祝福(强制执行)所显示的行为。

请注意,这不是偶然发生的;之所以发生这种情况,是因为标题是故意设计成在一个TU中重复使用几次。