我正在阅读文章 - http://www.geeksforgeeks.org/extern-c-in-c/
有两个例子 -
int printf(const char *format,...);
int main()
{
printf("GeeksforGeeks");
return 0;
}
它说这不会编译因为编译器无法找到错误版本的' printf'功能。但是,下面给出了输出。
extern "C"
{
int printf(const char *format,...);
}
int main()
{
printf("GeeksforGeeks");
return 0;
}
这是外在的" C"阻止名称被破坏。但是,代码运行并提供输出。从哪里得到' printf'的定义。我读了一篇帖子,上面写着' stdio.h'包含在默认情况下。如果是这样,则必须运行以下代码。但是,它给出了未定义printf的错误。
int main()
{
printf("GeeksforGeeks");
return 0;
}
有人可以解释一下吗?
答案 0 :(得分:4)
您的编译器通过将printf专门作为内置处理来提供帮助。
示例代码" tst.cpp":
int printf(char const *format,...);
int foo(int a, char const *b);
int main() {
printf("Hello, World!");
foo(42, static_cast<char const *>("Hello, World!"));
return 0;
}
使用Microsoft的cl编译器命令编译&#34; cl / c tst.cpp&#34;我们可以检查生成的.obj并找到:
00000000 r $SG2552
00000010 r $SG2554
00000000 N .debug$S
00000000 i .drectve
00000000 r .rdata
00000000 t .text$mn
U ?foo@@YAHHPBD@Z
U ?printf@@YAHPBDZZ
00e1520d a @comp.id
80000191 a @feat.00
00000000 T _main
请注意,foo()和printf()都被破坏了。
但是当我们通过cygwin&#34; g ++ -c tst.cpp&#34;编译/usr/lib/gcc/i686-pc-cygwin/3.4.4/cc1plus.exe时,我们得到:
00000000 b .bss
00000000 d .data
00000000 r .rdata
00000000 t .text
U __Z3fooiPKc
U ___main
U __alloca
00000000 T _main
U _printf
这里foo()被破坏而printf()没有,因为cygwin编译器很有帮助。大多数人会认为这是编译器缺陷。如果使用&#34; g ++ -fno-builtin -c tst.cpp&#34;调用cygwin编译器。然后问题就消失了,两个符号都应该被破坏了。
更新的g ++是正确的,使用/usr/libexec/gcc/i686-redhat-linux/4.8.3/cc1plus通过&#34; g ++ -c tst.cpp&#34;进行编译。我们得到:
00000000 T main
U _Z3fooiPKc
U _Z6printfPKcz
foo()和printf()都被破坏了。
但是如果我们声明printf使得cygwin g ++无法识别它:
char const * printf(char const *format,...);
int foo(int a, char const *b);
int main() {
printf("Hello, World!");
foo(42, static_cast<char const *>("Hello, World!"));
return 0;
}
然后foo()和printf()都被破坏了:
00000000 b .bss
00000000 d .data
00000000 r .rdata
00000000 t .text
U __Z3fooiPKc
U __Z6printfPKcz
U ___main
U __alloca
00000000 T _main
答案 1 :(得分:1)
让我们来看看相关的标准报价:
17.6.2.3链接 [using.linkage]
2使用外部链接声明的C标准库中的名称是否具有
extern "C"
或extern "C++"
链接是实现定义的。为此,建议实现使用extern "C++"
链接。
17.6.4.3保留名称 [reserved.names]
2如果程序在保留它的上下文中声明或定义名称,除了本条款明确允许的名称外,其行为是未定义的。
17.6.4.3.3外部链接 [extern.names]
1在标头中声明为具有外部链接的对象的每个名称都保留给实现,以在名称空间
std
和全局名称空间中指定具有外部链接的库对象。 2在标题中使用外部链接声明的每个全局函数签名都保留给实现,以指定具有外部链接的函数签名 3使用外部链接声明的标准C库中的每个名称都保留给实现,以便在名称空间extern "C"
和全局名称空间中用作std
链接的名称。 4使用外部链接声明的标准C库中的每个函数签名都保留给实现,以用作具有extern "C"
和extern "C++"
链接的函数签名,或者作为全局命名空间中的命名空间范围的名称
我们从中得到的是编译器可以假定在任何给定实例中printf
总是引用标准库函数printf
,因此可以有任何关于他们的信息。如果你声明错误,或者确实只是提供你自己的声明,它可以自由地做任何想做的事情,包括但不限于神奇地纠正它。
无论如何,你无法知道它所期望的语言联系。