0

情况

我正在使用 min GW 编译器:

>bin\cpp --version
cpp.exe (GCC) 6.1.0
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

我有两个头文件main.hsubmodule.h. 由于各种原因,我不能简单地将其中一个标题包含到另一个标题中。


[更新]

我认为您需要解释为什么不能简单地将其中一个标题包含到另一个标题中的各种原因,因为这是显而易见的答案... – Andrew

  • 我无法导入main.hsubmodule.h因为在这种情况下,更改main.h会触发子模块的重新编译,尽管此处没有任何更改。编译时间是我的客户关心的主要问题。

  • 我不能包括在内submodule.hmain.h因为submodule.h定义了很多东西,但只有少数定义是公开的。我的客户希望尽可能减少标识符的可见性。

  • 我的客户端使用 的内容main.h来验证目标软件不同版本的兼容性。上述数组的存在和大小是兼容性标准之一。因此数组的定义必须留在main.h

  • 有一些版本的目标软件根本没有子模块。因此,构建此子模块的文件可能存在也可能不存在。(对于我的客户)有很多开销来处理必须由其他人而不是我来完成的情况。所以我的客户也想限制“闪烁”文件的数量。


我还有很多其他*.h文件包含main.h但不包含submodule.h,它们不应该在子模块中隐藏一些东西。

submodule.h定义了很多在submodule.c. 其中包括数组类型定义和该类型的全局变量:

typedef const char INDEX_TABLE_t[42]; 
const INDEX_TABLE_t INDEX_TABLE;

实现了这个submodule.c数组:

const INDEX_TABLE_t INDEX_TABLE {/* 42 random char values */};

INDEX_TABLE其他*.h文件中使用的变量ist:

char SOME_OTHER_INDEX[23] = {/* 23 random char values */};

#define SELECTOR_VALUE 5
#define a_fix_name INDEX_TABLE[SOME_OTHER_INDEX[SELECTOR_VALUE]]

这些*.h文件包括main.h但不包括submodule.h.

INDEX_TABLE_t因此,我曾经添加和编译好的(完全相同的)类型定义INDEX_TABLE_tmain.h

问题

我的客户使用了一个代码 alaysis 工具 (QA-C),它抱怨 type 的双重定义INDEX_TABLE_t

[C] More than one declaration of 'INDEX_TABLE_t' (with no linkage). 

客户指示我更改代码,以便代码分析工具不再发出此错误。

我通常通过将extern关键字添加到除一次之外的所有内容来解决此问题。但在这种情况下,编译器会抛出异常:

error: conflicting specifiers in declaration of 'INDEX_TABLE_t'

但是声明相等的(它们是基于模型呈现的)。

问题

我有机会让编译器和代码分析器都开心吗?

我唯一的选择是创建另一个要包含在main.h或所有其他文件中的头文件吗?*.h

4

1 回答 1

3

我有两个头文件main.hsubmodule.h. 由于各种原因,我不能简单地将其中一个标题包含到另一个标题中。

然后帮自己一个忙并解决这个问题,即使你实际上并不#include "submodule.h"在里面main.h。您声称您不能这样做的说法非常难闻。

实现了这个submodule.c数组:

const INDEX_TABLE_t INDEX_TABLE {/* 42 random char values */};

您似乎=在初始化程序之前省略了一个。此外,INDEX_TABLE_t作为一个带有元素的数组类型const,我认为额外的元素不会const产生任何额外的影响。

我的客户使用了一个代码解析工具 (QA-C),它抱怨类型 INDEX_TABLE_t 的双重定义。

[C] More than one declaration of 'INDEX_TABLE_t' (with no linkage). 

我想该工具所关注的正是声明在单独的文件中重复的事实,而不是集中在单个标题中。这是一个有效的担忧,与其说是现在的程序,不如说是持续的维护和开发。您为未来的维护者(也许是未来的您)设置了一个陷阱,他们可能只更改一个类型定义,或者以不兼容的方式更改这两个,从而引入一个微妙但有影响力的错误。

客户指示我更改代码,以便代码分析工具不再发出此错误。

我通常通过将 extern 关键字添加到除一次之外的所有内容来解决此问题。但在这种情况下,编译器会抛出异常:

error: conflicting specifiers in declaration of 'INDEX_TABLE_t'

但是声明是相等的(它们是基于模型呈现的)。

INDEX_TABLE_t指定类型,而不是对象或函数。它不能具有外部链接 (per extern),因为它自动且必然没有链接。

我有机会让编译器和代码分析器都开心吗?

是的。

创建另一个头文件以包含在 main.h 或所有其他 *.h 文件中是我唯一的选择吗?

不完全是,但您确实需要将类型定义放在一个标头中,并让您的所有来源直接或间接地从那里获取它。您的想法的一种替代方法是#include将该标题直接放入您的 .c 文件中,这可能需要仔细管理#include语句的顺序。

但总的来说,听起来您的标头集合可以从一些重构中受益。作为一般规则,每个标头都应该(并且应该能够)包括为使用但未在其中声明的标识符提供声明所需的所有标头,并且不包括其他标头。这在一定程度上是通过在每个标头中使用包含防护来促进的。如果你从一开始就没有为它设计,那么它可能还有其他方面的工作,但它肯定可以完成。


回应编辑的问题

该软件的某些版本不包括子模块但(可能)确实使用main.h是一个强烈的指示,对于只有子模块提供实例的对象的类型来说,这main.h是一个错误的地方。它应该放在与submodule相关联的标头中,或者更广泛地与所有使用submodule的此属性的不同源的集合相关联。typedef

也许那个标题可能是submodule.h它自己。也许它应该是一个单独的标题,比如说submodule_general.h,它甚至可能是一个更好的地方,现在也可以放置一些其他的东西submodule.h。也许其中有些东西submodule.h不需要存在,并且删除它 - 可能连同将一些对象和函数从外部转换为内部 - 将使其更易于包含submodule.h在更多地方。

但是,您在标头之间拆分声明以避免重复并服务于您可能拥有的任何其他目标,您始终可以选择将标头直接或间接通过其他标头包含到需要它们的源中。

于 2019-01-08T15:38:21.340 回答