用C ++命名Mangling

时间:2015-08-29 10:43:17

标签: c++ extern

我正在阅读文章 - 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;
}

有人可以解释一下吗?

2 个答案:

答案 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,因此可以有任何关于他们的信息。如果你声明错误,或者确实只是提供你自己的声明,它可以自由地做任何想做的事情,包括但不限于神奇地纠正它。
无论如何,你无法知道它所期望的语言联系。