Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Name Mangling in C++

Tags:

c++

extern

I was going through the article - http://www.geeksforgeeks.org/extern-c-in-c/

There are two example given -

int printf(const char *format,...);

int main()
{
    printf("GeeksforGeeks");
    return 0;
}

It say this wont compile because the compiler wont be able to find the mangled version of 'printf' function. However, the below give output.

extern "C"
{
    int printf(const char *format,...);
}

int main()
{
    printf("GeeksforGeeks");
    return 0;
}

This is beacuse extern "C" block prevent the name from being mangled. However, the code run and gives output. From where does it get the definition of 'printf'. I read a post which says 'stdio.h' is included by default. If this is true, below code must run. However, it give error that printf is not defined.

int main()
{
    printf("GeeksforGeeks");
    return 0;
}

Can somebody explain this?

like image 698
Naved Alam Avatar asked Aug 29 '15 10:08

Naved Alam


1 Answers

Your compiler is being helpful by treating printf specially as a built-in.

Sample code "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;
}

When compiling with Microsoft's cl compiler command "cl /c tst.cpp" we can inspect the resulting .obj and find:

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  

Note that both foo() and printf() are mangled.

But when we compile with /usr/lib/gcc/i686-pc-cygwin/3.4.4/cc1plus.exe via cygwin "g++ -c tst.cpp", we get:

00000000 b .bss
00000000 d .data
00000000 r .rdata
00000000 t .text
         U __Z3fooiPKc
         U ___main
         U __alloca
00000000 T _main
         U _printf

Here foo() is mangled and printf() is not, because the cygwin compiler is being helpful. Most would consider this a compiler defect. If the cygwin compiler is invoked with "g++ -fno-builtin -c tst.cpp" then the problem goes away and both symbols are mangled as they should be.

A more up-to-date g++ gets it right, compiling with with /usr/libexec/gcc/i686-redhat-linux/4.8.3/cc1plus via "g++ -c tst.cpp" we get:

00000000 T main
         U _Z3fooiPKc
         U _Z6printfPKcz

Both foo() and printf() are mangled.

But if we declare printf such that cygwin g++ does not recognize it:

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;
}

Then both foo() and printf() are mangled:

00000000 b .bss
00000000 d .data
00000000 r .rdata
00000000 t .text
         U __Z3fooiPKc
         U __Z6printfPKcz
         U ___main
         U __alloca
00000000 T _main
like image 170
ewd Avatar answered Oct 05 '22 12:10

ewd