例如,假设我有以下文件:hello.cpp,hello.h和main.c
在hello.cpp中说我有以下内容:
#include "hello.h"
extern "C" void test_func(int &a, int b){
some stuff
}
在hello.h中我有以下内容:
#ifdef __cplusplus
extern "C" {
#endif
void test_func(int& a, int b);
#ifdef __cplusplus
}
#endif
这是我感到困惑的地方。如果我在main.c中有以下内容:
#include "hello.h"
extern void test_func(int*, int);
然后这将无法正确编译。它告诉我我的hello.h文件中有错误,我认为这是因为C不支持按引用传递?我注意到,如果我将我的hello.h文件更改为“void test_func(int * a,int b)”,那么这将正确编译。
但是,如果我的main.c文件中没有#include“hello.h”,那么它也会正确编译。而且,即使不包含hello.h,我也可以从main.c调用test_func。是否足够声明函数原型?为什么?如果我想包含hello.h那么这意味着我必须使它与C兼容并且没有任何通过引用传递的函数?
这一切都很新,所以提前感谢任何人的帮助。
答案 0 :(得分:2)
使用两个不同的原型声明相同的C函数是未定义的行为。不要这样做。 (这种特殊情况很可能“起作用”,因为典型的编译器通过在堆栈上放置一个内存地址来传递指针类型,并通过在堆栈上放置一个内存地址来传递引用类型。)
所以是的,你现在的hello.h根本不能用于C代码。如果您希望函数跨越C-C ++“边界”,它应该具有类似C的声明。 (除了它可以在C ++端的命名空间中;在C端忽略此命名空间。)
相反,您可以围绕C ++函数创建一个C包装器:
// hello.h
#ifndef HELLO_H_GUARD_
#define HELLO_H_GUARD_
#ifdef __cplusplus
void test_func(int &a, int b);
extern "C"
#endif
void test_func_c(int *a, int b);
#endif
// hello.cpp
void test_func(int &a, int b) {
//...
}
extern "C"
void test_func_c(int *a, int b) {
test_func(*a, b);
}
顺便提一下,你提到了一个“main.c”文件。混合C和C ++时,main
函数应该在C ++源文件中。如果你愿意,那可以只是一个调用你的“真正的”C类主函数的包装器。
答案 1 :(得分:0)
从另一个目标文件调用一个目标文件中的函数严格来说是链接器是否可以在另一个目标文件中找到正确名称的对象的问题。通常,C ++编译器会命名为mangling,以确保您不会调用错误版本的函数 - 例如,如果我编译:
void test_func(int &a, int b) {
return;
}
然后调用nm,我得到类似的东西:
0000000000000000 T _Z9test_funcRii
然而,'extern“C”'告诉编译器不要进行名称修改,所以我得到:
0000000000000000 T test_func
一个C程序可以完全自由地用它想要的任何参数调用test_func,并且由编码器来确保他传递的参数是正确的。在你的情况下,它工作的唯一原因是因为你的C ++编译器显然使用指针实现了传递引用(这并不令人惊讶)。