不,一般情况下,您不应将其移动以包含标题。
extern "C" 用于指示函数正在使用 C 调用约定。该声明对变量和#defines 没有影响,因此无需包含这些。如果#include 在extern "C" 块内,这会有效地修改该头文件中的函数声明!
背景:如果没有extern "C" 声明,使用C 编译器编译时,假定函数遵循C 约定,使用C++ 编译器编译时,假定遵循C++ 约定。如果 C 和 C++ 代码使用相同的头文件,则会出现链接器错误,因为编译后的函数在 C 和 C++ 中具有不同的名称。
虽然可以将所有代码放在#ifdef 块之间,但我个人不喜欢它,因为它实际上只用于函数原型,而且我经常看到人们将它复制粘贴到不应该的地方'不是。最干净的方法是将其保留在应有的位置,即 C/C++ 头文件中的函数原型周围。
所以,要回答您的问题“我应该在包含标头包含指令之前移动 extern "C" 位吗?”,我的回答是:不,您不应该。
但这可能吗?是的,在许多情况下,这不会破坏任何东西。有时甚至有必要,如果外部头文件中的函数原型不正确(例如,当它们是 C 函数并且您想从 C++ 调用它们时)并且您无法更改该库。
但是,在某些情况下这样做会破坏构建。这是一个简单的示例,如果您使用 extern "C" 包装包含,则无法编译:
foo.h:
#pragma once
// UNCOMMENTING THIS BREAKS THE BUILD!
//#ifdef __cplusplus
//extern "C" {
//#endif
#include "bar.h"
bar_status_t foo(void);
//#ifdef __cplusplus
//}
//#endif
foo.c:
#include <stdio.h>
#include "foo.h"
#include "bar.h"
bar_status_t foo(void)
{
printf("In foo. Calling bar wrapper.\n");
return bar_wrapper();
}
bar.h:
#pragma once
typedef enum {
BAR_OK,
BAR_GENERIC_ERROR,
BAR_OUT_OF_BEAR,
// ...
} bar_status_t;
extern "C" bar_status_t bar_wrapper(void);
bar_status_t bar(void);
bar.cpp:
#include <iostream>
#include "bar.h"
extern "C" bar_status_t bar_wrapper(void)
{
std::cout << "In C/C++ wrapper." << std::endl;
return bar();
}
bar_status_t bar(void)
{
std::cout << "In bar. One bear please." << std::endl;
return BAR_OK;
}
main.cpp:
#include <stdio.h>
#include <stdlib.h>
#include "foo.h"
#include "bar.h"
int main(void)
{
bar_status_t status1 = foo();
bar_status_t status2 = bar();
return (status1 != BAR_OK) || ((status2 != BAR_OK));
}
取消注释 a.h 中的块时,我收到以下错误:
main2.cpp:(.text+0x18): undefined reference to `bar'
collect2.exe: error: ld returned 1 exit status
Makefile:7: recipe for target 'app2' failed
没有,它构建得很好。仅从 foo 和 bar 调用 C 函数的 C 主程序无论哪种方式都可以正常构建,因为它不受 #ifdef __cplusplus 块的影响。