【问题标题】:How can I avoid redefinition of types while including multiple header files?如何在包含多个头文件时避免重新定义类型?
【发布时间】:2018-09-21 11:28:36
【问题描述】:

我正在重新编译一个 C 项目,但我不确定如何以正确的方式解决这个问题。 这是一种情况 -

啊.h

#ifndef A_H
#define A_H
typedef int INT; 
// other variables and function definition
#endif

b.h

#ifndef B_H
#define B_H
typedef int INT;
// other variables and function definition
#endif

main.c

#include "a.h" 
#include "b.h"

int main()
{
    INT i = 10; 
    return 0;
}

我使用 gcc 在 Linux 中遇到的错误:

In file included from ./main.c,

    ./b.h:<linenumber>: error: redefinition of typedef ‘INT’
    a.h.h:<linenumber>: note: previous declaration of ‘INT’ was here

由于其他变量和函数,我必须包含两个标题。我还没有编写此代码,但这似乎在我的 Solaris 环境中编译,这很奇怪。我能做些什么来解决这个问题?

【问题讨论】:

  • 将 typedef 替换为 #define 宏。同样的#define 工作。
  • 通常的方法是将声音命名约定与声音程序设计一起使用。如果INT 与“a”和“b”都无关,那么显然不应在这些标头中声明它。作为旁注,您不应该发明自己的整数类型车库标准。使用 stdint.h。
  • 这是有效的。谢谢!!但是为什么 #define 在这里工作而不是 typedef 呢?
  • @SwapnilShivhare #definetypedef 是两个非常不同的东西。第一个通过文本替换工作,第二个实际上创建了一个新类型。它适用于#define,因为重新定义之前定义的宏是合法的,只要它具有相同的定义。
  • 请注意 C11 §6.7 Declarations ¶3 允许:可以重新定义 typedef 名称以表示与当前相同的类型,前提是该类型不是可变修改的类型; 所以你不能在您的编译选项中使用-std=c11-std=gnu11。或者,您必须使用旧版本的 GCC(即 GCC 4 或更早版本),因为 GCC 版本 5 或更高版本默认为 C11 模式,或者您必须故意指定旧版本的标准。但是,您可能会因为兼容性而合理地决定不使用该功能。

标签: c gcc include redefinition


【解决方案1】:

可能 Solaris 上的本机编译器接受您可以重新定义 typedef(可能假设新的 typedef 与以前的 typedef 相同,这里就是这种情况)。

我将介绍另一个头文件mytypes.h,如下所示:

mytypes.h

#ifndef MYTYPES_H
#define MYTYPES_H
typedef int INT;     
#endif

在使用INT 的任何地方都包括mtypes.h,甚至可能在main.c 中:

啊.h

#ifndef A_H
#define A_H
#include "mytypes.h"   // can be removed if INT is not used in a.h
// other variables and function definition
#endif

b.h

#ifndef B_H
#define B_H
#include "mytypes.h"   // can be removed if INT is not used in b.h
// other variables and function definition
#endif

ma​​in.c

#include "a.h" 
#include "b.h"
#include "mytypes.h"  // not really necessary because it's already included
                      // via a.h and b.h, but still good practice

int main()
{
    INT i = 10; 
    return 0;
}

【讨论】:

    【解决方案2】:

    如果您被允许更改库代码或编译器选项,那么 Michael Walz 的答案就是要走的路

    如果不幸的是它可更改,则可以通过在包含标题之前重命名然后取消定义来解决它

    #define INT INT_A
    #include "a.h"
    #undef INT
    
    #define INT INT_B
    #include "b.h"
    #undef INT
    

    现在只需将INT_A 用于a.h 中的所有接口,而不是INT。与b.h中的INT_B相同

    【讨论】:

      猜你喜欢
      • 2014-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-27
      • 2023-03-09
      相关资源
      最近更新 更多