如何在C ++程序中使用C标头?

时间:2011-07-06 20:35:47

标签: c++ c visual-studio-2010 function-pointers header-files

我正在开发Visual Studio 2010中的一个项目,即生成一个win 32 dll文件。我的例子是C文件,编译和工作很好。我想在我编写的C ++函数中加入一些功能,但是我已经打了一个墙。

如果我尝试将C ++函数链接到C程序,它对字符串等一无所知,根本不起作用(当然)。

所以我只是将示例更改为C ++程序,然后我可以使用其他文件而不受惩罚。当我尝试这样做时,我得到一个我不理解的链接错误,并且不确定如何解决。

示例使用供应商提供的标头,其中包括

等语句
 typedef void ( __cdecl *BINDING_PROC_BEVNT)(WORD_T choice, INT_T * pStatus, 
            I_EVNT_T  * pIn, O_EVNT_T  * pOut);

在主要代码的正文中,遵循以下示例:

extern BINDING_PROC_BEVNT       b_evnt;

然后允许你写

b_evnt(choice, &status, &inpEvent, &outpEvent);

在供应商提供的C文件中,这些文件再次引用为:

BINDING_PROC_BEVNT      b_evnt; 
b_evnt = (BINDING_PROC_BEVNT)GetProcAddress(hCNCMod, "bevnt");

我看到的链接器错误是:

  

错误LNK2001:未解析的外部符号“void(__ cdecl * b_evnt)(unsigned short,short *,union I_EVNT_T *,union O_EVNT_T *)”(?b_evnt @@ 3P6AXGPAFPATI_EVNT_T @@ PATO_EVNT_T @@@ ZA)

如果我重命名我的主文件并重新编译为C程序,并省略了我的C ++函数,那么一切都可以很好地编译。即使将主文件作为C ++文件处理,Intellisense似乎也能识别出这些定义(悬停时会显示正确的定义)。

此外,我尝试将extern“C”添加到几个不同的位置,但它似乎没有在C ++文件中产生差异,并在C文件中生成编译错误(关于不知道字符串)。 / p>

任何见解都会受到赞赏,我今天可能只是盯着这个太长时间来看待明显的东西,或者它可能是我完全没有意识到的东西。

感谢您的帮助!

4 个答案:

答案 0 :(得分:10)

如果要编译具有C语言绑定的库,则必须明确告诉C ++库引用C对象的头文件,而不是C ++对象或C ++名称修改将阻止正确链接。通常你可以这样做:

extern "C" {
#include "vendor.h"
}

这将告诉C ++编译器大括号之间的符号是C符号,并且不应该应用名称修改。

答案 1 :(得分:6)

要包含C ++中的C头文件,请执行以下操作:

TEST.CPP

extern "C" {

#include "c_header_file.h"

}

听起来您可能需要做的就是在C ++代码中包含供应商头文件。

相关地,使头文件自动适用于C和C ++:

c_header_file.h

#ifdef __cplusplus
extern "C" {
#endif

void f(int);
// all declarations go here

#ifdef __cplusplus
}
#endif

并非所有供应商提供的头文件都包含上述__cplusplus检测,因此您必须像第一个示例一样在extern "C"中手动换行。

答案 2 :(得分:3)

error LNK2001: unresolved external symbol "void (__cdecl* b_evnt) 
(unsigned short,short *,union I_EVNT_T *,union O_EVNT_T *)" 
(?b_evnt@@3P6AXGPAFPATI_EVNT_T@@PATO_EVNT_T@@@ZA)

这意味着,无法找到C ++受损变量b_evnt。这是真的,因为它应该是C mangled(只是一个_前缀)。要解决这个问题,请在编译C ++时将其告知编译器:

#ifdef __cplusplus
extern "C" BINDING_PROC_BEVNT       b_evnt;
#else
extern BINDING_PROC_BEVNT       b_evnt;
#endif

如果就是这样,你就完成了。如果您需要更多符号,您可能希望使用Greg的解决方案 - 但请注意,这也不是修复。

答案 3 :(得分:0)

您的供应商提供的标头包含在C ++编译单元中,但它们并未为C ++做好准备。因此,函数的声明正在编译,其名称是C ++ compielr支持重载所需的名称。

标头需要包装在extern "C" {}块中,以便让C ++编译器知道这些声明使用C链接。

执行此操作最简单的方法可能就是使用自己的包装器标头来执行以下操作:

#ifndef FOO_WRAPPER_H
#define FOO_WRAPPER_H

#if __cplusplus
extern "C" {
#endif

#include "foo.h"

#if __cplusplus
}
#endif

#endif

并包含yiour包装器头而不是供应商的头 - 包装器适用于C或C ++编译。

另外,请与您的库供应商联系,让他们知道他们应该进行这些更改 - 库的用户不必使用C ++中的库来解决此问题。