我很困惑是否在C中使用extern来表示函数的前向声明。场景是每个函数都在单独的.c / .cpp文件中。我通过这个问题 - External linkage of const in C理解,如果所有都是.c文件,我不应该使用extern进行前向声明,而不管函数是否在同一个文件中定义。
但是我想知道更多关于这一点的时候明确使用extern进行前向声明(我认为当前向声明的函数是用不同的语言定义而不是调用它时,extern将是必需的),并且任何警告都是意识到了。
答案 0 :(得分:2)
在C语言中,extern inline
具有特殊含义,明确的extern
会产生影响。
除此之外,在functon声明中指定明确的extern
从来没有任何意义,因为C和C ++中的函数总是通过defualt进行外部链接。
"不同的语言"可能与extern "C"
有关,但这与普通extern
完全不同。
答案 1 :(得分:2)
我认为当前向声明的函数用不同的语言定义而不是调用它时,extern将是必需的。
我应该警告你,你的问题措辞不当。我很确定你对何时使用
感兴趣extern "C" int foo(int);
在C ++中,但我不确定,我不得不希望我不浪费时间。
让我们区分编译器和链接器。我遗漏了一些细节,但没有任何影响你问题的答案。
编译器使用前向声明。在声明函数时,您将为编译器提供有关如何使用它的信息。声明函数 F ,当编译器在使用 F 时运行时,它知道该怎么做。 (在K& R时代,如果没有声明,编译器会使用默认值,有时会导致热闹的结果。所以现在它们在C和C ++中都是强制性的。)
通常,函数的前向声明是函数原型:它提供参数类型。在C中,这不是绝对必要的。你可以写
int foo();
告诉编译器foo
是一个返回int
的函数,但不是它需要的参数。因此,编译器无法检查,因此您有责任确保这些正确。
extern
声明 - 无论是函数还是变量 - 通知编译器符号及其类型,并说定义将由另一个模块提供。编译器留下占位符以供链接器稍后填充。
例如,如果您查看 getopt (3)手册页,您会看到optarg
被声明为extern
;它在C运行时库中定义,但您可以使用它,因为它已被声明。
现在我们来到链接器和C ++的extern "C"
。
对于链接器,模块公开符号。未声明为static
的全局变量和函数具有外部链接,这意味着它们可以被其他模块使用。
在C中,函数名和外部符号之间存在1:1的对应关系。名称是符号。例如, getopt (3)在C标准库libc中具有相同名称的符号:
$ nm -g $(find /usr/lib/ -name libc.a) 2>/dev/null | grep 'T getopt'
0000000000001620 T getopt
0000000000000000 T getopt_long
0000000000000040 T getopt_long_only
在C ++中,名称不是符号。 C ++函数可以重载;同名可以代表采用不同参数的不同功能。编译器构造一个编码参数类型的符号。比较:
$ echo 'int foo(int foo) { return foo * foo; }' > a.c && cc -c a.c && nm a.o
0000000000000000 T foo
$ echo 'int foo(int foo) { return foo * foo; }' > a.C && c++ -c a.C && nm a.o
0000000000000000 T _Z3fooi
符号名称的编码通常称为 name mangling 。 nm (1)具有demangling功能:
$ echo 'int foo(int foo) { return foo * foo; }' > a.C && c++ -c a.C && nm -C a.o
0000000000000000 T foo(int)
请注意,参数类型会显示在名称旁边。
在C ++中,extern "C"
将函数声明或定义为C函数。这是一个定义:
$ echo 'extern "C" int foo(int foo) { return foo * foo; }' > a.C && c++ -c a.C && nm a.o
0000000000000000 T foo
在声明中,它告诉编译器该函数是在别处定义的,并且使用一个C符号。
在定义中,它告诉编译器发出一个C符号,即不破坏名称,以便该函数可以被其他C模块使用。
我希望能回答你的问题。
答案 2 :(得分:1)
默认情况下,函数具有外部链接,这意味着
extern int foo(void);
和
int foo(void);
具有完全相同的含义。对于所有函数声明都是如此,除了那些以某种方式涉及static
的声明。
特别是,extern
的存在或不存在对类型检查无效,以及该函数是否以不同的语言定义是无关紧要的。