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