我正在做一个有很多遗留C代码的项目。我们已经开始用c++编写,目的是最终转换遗留代码。我对C和c++如何交互有点困惑。我知道,通过用extern“C”包装C代码,c++编译器不会损坏C代码的名称,但我不完全确定如何实现这一点。
因此,在每个C头文件的顶部(在include守卫之后),我们有
#ifdef __cplusplus
extern "C" {
#endif
在底部,我们写上
#ifdef __cplusplus
}
#endif
在这两者之间,我们有所有的include、typedef和函数原型。我有几个问题,看看我是否理解正确:
If I have a C++ file A.hh which
includes a C header file B.h,
includes another C header file C.h,
how does this work? I think that
when the compiler steps into B.h,
__cplusplus will be defined, so it
will wrap the code with extern "C"
(and __cplusplus will not be
defined inside this block). So,
when it steps into C.h,
__cplusplus will not be defined
and the code will not be wrapped in
extern "C". Is this correct?
Is there anything wrong with
wrapping a piece of code with
extern "C" { extern "C" { .. } }?
What will the second extern "C"
do?
We don't put this wrapper around the .c files, just the .h files. So, what happens if a function doesn't have a prototype? Does the compiler think that it's a C++ function?
We are also using some third-party
code which is written in C, and does
not have this sort of wrapper around
it. Any time I include a header
from that library, I've been putting
an extern "C" around the #include.
Is this the right way to deal with
that?
Finally, is this set up a good idea?
Is there anything else we should do?
We're going to be mixing C and C++
for the foreseeable future, and I
want to make sure we're covering all
our bases.
extern "C"并没有真正改变编译器读取代码的方式。如果你的代码在. C文件中,它将被编译为C,如果它在.cpp文件中,它将被编译为c++(除非你对你的配置做了一些奇怪的事情)。
extern C的作用是影响连杆。c++函数在编译时,其名称会被打乱——这就是使重载成为可能的原因。函数名根据形参的类型和数量进行修改,因此两个同名的函数将具有不同的符号名。
外部“C”中的代码仍然是c++代码。在extern“C”块中可以做的事情是有限制的,但它们都是关于链接的。您不能定义任何不能用C链接构建的新符号。例如,这意味着没有类或模板。
extern“C”块巢很好。如果您发现自己无望地困在extern“C”区域中,还可以使用extern“c++”,但从清洁的角度来看,这并不是一个好主意。
现在,具体来说,关于你编号的问题:
关于#1:__cplusplus将在extern“C”块中定义。不过,这并不重要,因为块应该整齐地嵌套。
Regarding #2: __cplusplus will be defined for any compilation unit that is being run through the C++ compiler. Generally, that means .cpp files and any files being included by that .cpp file. The same .h (or .hh or .hpp or what-have-you) could be interpreted as C or C++ at different times, if different compilation units include them. If you want the prototypes in the .h file to refer to C symbol names, then they must have extern "C" when being interpreted as C++, and they should not have extern "C" when being interpreted as C -- hence the #ifdef __cplusplus checking.
回答你的问题#3:如果没有原型的函数在.cpp文件中,而不是在extern“C”块中,那么它们将具有c++链接。不过,这很好,因为如果它没有原型,它只能由同一文件中的其他函数调用,然后您通常不关心链接是什么样子的,因为您不打算让同一编译单元之外的任何东西调用该函数。
对于第4点,你已经完全明白了。如果您包含一个带有C链接的代码头(例如由C编译器编译的代码),那么您必须将标头扩展为“C”——这样您将能够链接到库。(否则,当你在寻找void h(int, char)时,你的链接器会寻找像_Z1hic这样的函数名)
5:这种混合是使用extern“C”的常见原因,我不认为这样做有什么错——只是要确保你明白你在做什么。
extern "C"并没有真正改变编译器读取代码的方式。如果你的代码在. C文件中,它将被编译为C,如果它在.cpp文件中,它将被编译为c++(除非你对你的配置做了一些奇怪的事情)。
extern C的作用是影响连杆。c++函数在编译时,其名称会被打乱——这就是使重载成为可能的原因。函数名根据形参的类型和数量进行修改,因此两个同名的函数将具有不同的符号名。
外部“C”中的代码仍然是c++代码。在extern“C”块中可以做的事情是有限制的,但它们都是关于链接的。您不能定义任何不能用C链接构建的新符号。例如,这意味着没有类或模板。
extern“C”块巢很好。如果您发现自己无望地困在extern“C”区域中,还可以使用extern“c++”,但从清洁的角度来看,这并不是一个好主意。
现在,具体来说,关于你编号的问题:
关于#1:__cplusplus将在extern“C”块中定义。不过,这并不重要,因为块应该整齐地嵌套。
Regarding #2: __cplusplus will be defined for any compilation unit that is being run through the C++ compiler. Generally, that means .cpp files and any files being included by that .cpp file. The same .h (or .hh or .hpp or what-have-you) could be interpreted as C or C++ at different times, if different compilation units include them. If you want the prototypes in the .h file to refer to C symbol names, then they must have extern "C" when being interpreted as C++, and they should not have extern "C" when being interpreted as C -- hence the #ifdef __cplusplus checking.
回答你的问题#3:如果没有原型的函数在.cpp文件中,而不是在extern“C”块中,那么它们将具有c++链接。不过,这很好,因为如果它没有原型,它只能由同一文件中的其他函数调用,然后您通常不关心链接是什么样子的,因为您不打算让同一编译单元之外的任何东西调用该函数。
对于第4点,你已经完全明白了。如果您包含一个带有C链接的代码头(例如由C编译器编译的代码),那么您必须将标头扩展为“C”——这样您将能够链接到库。(否则,当你在寻找void h(int, char)时,你的链接器会寻找像_Z1hic这样的函数名)
5:这种混合是使用extern“C”的常见原因,我不认为这样做有什么错——只是要确保你明白你在做什么。