【问题标题】:How to include a file only once / Prevent Function Redefinitions in old C API from C++ Program如何仅包含一次文件/防止来自 C++ 程序的旧 C API 中的函数重定义
【发布时间】:2013-11-26 15:43:53
【问题描述】:

我有一个 C++ 程序,它必须使用基于 C 的 API 来完成特定任务。如果我在我的程序中只包含一个 cpp,我完全没有问题。但是,如果我包含在头文件中(我需要在其中使用某些类型),链接器会出现重新定义错误。

这是由于在外部库(带有已编译 dll 的 C 标头)标头中创建了许多 typedef。我正在寻找这个问题的任何可能的解决方案。

当我搜索时,我似乎只能找到标头保护的东西(和 #pragma 一次),但这些并不是问题的解决方案,因为我发现的是单独编译单元中的多个定义,然后在链接时发生冲突.

我正在考虑 extern,但发现我无法将标头中定义的任何类型用作 C++ 类中的成员,这主要是我想要做的。

Output for building on Warning Level 4
Warning 1   warning C4273: 'getwchar' : inconsistent dll linkage    c:\program files (x86)\microsoft visual studio 11.0\vc\include\stdio.h  615 1   project-test
Warning 2   warning C4273: 'putwchar' : inconsistent dll linkage    c:\program files (x86)\microsoft visual studio 11.0\vc\include\stdio.h  617 1   project-test
Warning 3   warning C4273: 'getwchar' : inconsistent dll linkage    c:\program files (x86)\microsoft visual studio 11.0\vc\include\stdio.h  615 1   project-test
Warning 4   warning C4273: 'putwchar' : inconsistent dll linkage    c:\program files (x86)\microsoft visual studio 11.0\vc\include\stdio.h  617 1   project-test
Warning 5   warning C4100: 'data' : unreferenced formal parameter   c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  8   1   project-test
Warning 6   warning C4100: 'event' : unreferenced formal parameter  c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  8   1   project-test
Warning 7   warning C4100: 'widget' : unreferenced formal parameter c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  8   1   project-test
Warning 8   warning C4100: 'data' : unreferenced formal parameter   c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  15  1   project-test
Warning 9   warning C4100: 'event' : unreferenced formal parameter  c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  15  1   project-test
Warning 10  warning C4100: 'widget' : unreferenced formal parameter c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  15  1   project-test
Warning 11  warning C4505: 'g_bit_nth_lsf' : unreferenced local function has been removed   c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gutils.h   267 1   project-test
Warning 12  warning C4505: 'g_bit_nth_msf' : unreferenced local function has been removed   c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gutils.h   269 1   project-test
Warning 13  warning C4505: 'g_bit_storage' : unreferenced local function has been removed   c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gutils.h   271 1   project-test
Warning 14  warning C4505: 'g_string_append_c_inline' : unreferenced local function has been removed    c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gstring.h  130 1   project-test
Warning 15  warning C4505: 'g_trash_stack_push' : unreferenced local function has been removed  c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gtrashstack.h  44  1   project-test
Warning 16  warning C4505: 'g_trash_stack_pop' : unreferenced local function has been removed   c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gtrashstack.h  46  1   project-test
Warning 17  warning C4505: 'g_trash_stack_peek' : unreferenced local function has been removed  c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gtrashstack.h  47  1   project-test
Warning 18  warning C4505: 'g_trash_stack_height' : unreferenced local function has been removed    c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gtrashstack.h  48  1   project-test
Error   19  error LNK2005: "long __cdecl abs(long)" (?abs@@YAJJ@Z) already defined in FitsFile.obj  C:\Users\Ian\SkyDrive\Documents\Uni\FINPRO\projects\project-test\project-test\main.obj  project-test
Error   20  error LNK2005: "__int64 __cdecl abs(__int64)" (?abs@@YA_J_J@Z) already defined in FitsFile.obj  C:\Users\Ian\SkyDrive\Documents\Uni\FINPRO\projects\project-test\project-test\main.obj  project-test
Error   21  error LNK2005: "struct _ldiv_t __cdecl div(long,long)" (?div@@YA?AU_ldiv_t@@JJ@Z) already defined in FitsFile.obj   C:\Users\Ian\SkyDrive\Documents\Uni\FINPRO\projects\project-test\project-test\main.obj  project-test
Error   22  error LNK2005: "struct _lldiv_t __cdecl div(__int64,__int64)" (?div@@YA?AU_lldiv_t@@_J0@Z) already defined in FitsFile.obj  C:\Users\Ian\SkyDrive\Documents\Uni\FINPRO\projects\project-test\project-test\main.obj  project-test
Error   23  error LNK2005: _getwchar already defined in FitsFile.obj    C:\Users\Ian\SkyDrive\Documents\Uni\FINPRO\projects\project-test\project-test\main.obj  project-test
Error   24  error LNK2005: _putwchar already defined in FitsFile.obj    C:\Users\Ian\SkyDrive\Documents\Uni\FINPRO\projects\project-test\project-test\main.obj  project-test
Error   25  error LNK1169: one or more multiply defined symbols found   C:\Users\Ian\SkyDrive\Documents\Uni\FINPRO\projects\project-test\Debug\project-test.exe project-test

Output for building on Warning Level 4 (when only including for one place)
Warning 1   warning C4273: 'getwchar' : inconsistent dll linkage    c:\program files (x86)\microsoft visual studio 11.0\vc\include\stdio.h  615 1   project-test
Warning 2   warning C4273: 'putwchar' : inconsistent dll linkage    c:\program files (x86)\microsoft visual studio 11.0\vc\include\stdio.h  617 1   project-test
Warning 3   warning C4100: 'data' : unreferenced formal parameter   c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  8   1   project-test
Warning 4   warning C4100: 'event' : unreferenced formal parameter  c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  8   1   project-test
Warning 5   warning C4100: 'widget' : unreferenced formal parameter c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  8   1   project-test
Warning 6   warning C4100: 'data' : unreferenced formal parameter   c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  15  1   project-test
Warning 7   warning C4100: 'event' : unreferenced formal parameter  c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  15  1   project-test
Warning 8   warning C4100: 'widget' : unreferenced formal parameter c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  15  1   project-test
Warning 9   warning C4505: 'g_bit_nth_lsf' : unreferenced local function has been removed   c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gutils.h   267 1   project-test
Warning 10  warning C4505: 'g_bit_nth_msf' : unreferenced local function has been removed   c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gutils.h   269 1   project-test
Warning 11  warning C4505: 'g_bit_storage' : unreferenced local function has been removed   c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gutils.h   271 1   project-test
Warning 12  warning C4505: 'g_string_append_c_inline' : unreferenced local function has been removed    c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gstring.h  130 1   project-test
Warning 13  warning C4505: 'g_trash_stack_push' : unreferenced local function has been removed  c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gtrashstack.h  44  1   project-test
Warning 14  warning C4505: 'g_trash_stack_pop' : unreferenced local function has been removed   c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gtrashstack.h  46  1   project-test
Warning 15  warning C4505: 'g_trash_stack_peek' : unreferenced local function has been removed  c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gtrashstack.h  47  1   project-test
Warning 16  warning C4505: 'g_trash_stack_height' : unreferenced local function has been removed    c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gtrashstack.h  48  1   project-test

【问题讨论】:

  • 听起来这个C“API”不是很像API,如果你在使用上有这么多麻烦的话。是否有详细的使用说明或任何内容?
  • typedef 只有在同一目标文件包含两次文件时才会出现问题。链接器阶段的重新定义是由于变量的定义 - 因此您需要提供有关标头和确切错误的更多信息
  • 你能澄清一下链接器是否抱怨重复的函数或重复的变量?
  • 真正包含文件的全部点是多次包含它们。如果您的包含文件的编写方式导致出现问题,那么您需要修复包含文件,而不是问我如何只包含一次文件。
  • @IanCant 这不是 typedef 问题。这是一个多重定义的函数。

标签: c++ c visual-studio visual-c++ redefinition


【解决方案1】:

在间接层后面抽象 C 功能:

原始结构(如果我理解正确,这就是你现在所拥有的):

file1.h -> #include included_c_api.h
file2.h -> #include included_c_api.h CAUSES errors.

新结构:

new_c_api.h -> wrapper over included_c_api.h functionality (w/ your own symbols)
new_c_api.c[pp] -> #include included_c_api.h
file1.h -> #include new_c_api.h
file2.h -> #include new_c_api.h

如果included_c_api.h中暴露的功能非常大,这个解决方案可能不切实际。

【讨论】:

  • 据我的挖掘和上述 cmets 所知,这似乎是我唯一可用的真正解决方案。它确保文件只在间接层后面包含一次。
  • 从而消除编译器的错误并确保它可以使用。有关进一步的解释,请参阅有关问题的 cmets。
【解决方案2】:

寻找两件事:

a) 你不使用包含守卫。作为一般规则,所有标题都应具有以下结构。这可确保只有一个标头副本包含在 C++ 文件中。

#ifndef MYPROJECT_DIR_FILE_H
#define MYPROJECT_DIR_FILE_H

... all declarations and definitions ...

#endif

b) 确保在标头中定义的所有函数都是内联的。否则,多个 C++ 文件将具有相同函数的副本,这会使链接器感到困惑。 inline 请求丢弃除一份函数之外的所有副本。

【讨论】:

  • inline 不会请求丢弃,它会导致函数嵌入到该对象模块自己的代码中,因此链接器根本看不到它。
  • 不正确:inline 函数仍然可以被 odr 使用,这会导致包含常规定义。在任何情况下,编译器都可以随意忽略inline
【解决方案3】:

您不会说问题出在变量还是函数上。他们有不同的解决方案:

变量:头文件必须有一个变量的'extern'声明,只有一个'C'文件包含定义(与extern声明相同,但前面没有extern一词)。

functions:只有当你在头文件中有函数体时才会发生这种情况——在这种情况下,你应该把'inline'放在函数定义的前面,以便函数代码嵌入到每个使用它的对象模块中,并且链接器根本不需要处理它。函数原型不会导致重复定义错误。

当链接 C 代码和 C++ 代码时,您还需要正确命名修饰 - 这基本上意味着当您使用 C++ 编译器编译这些声明时,您应该使用以下代码包围所有适用于“C”对象的声明:

extern "C" { 

... 'C' declarations

}

你通常会看到

#if defined(__cplusplus)
extern "C" { 
#endif 

在头文件的顶部(底部的类似代码),这些文件被设计为包含在 C 和 C++ 文件中。这已经很好地覆盖了here - 但听起来你目前没有名称修改问题,尽管我希望你会在项目完成之前......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-08
    • 1970-01-01
    • 2019-06-28
    • 1970-01-01
    • 2018-07-20
    • 1970-01-01
    相关资源
    最近更新 更多