Standard c++ library linking

2019-05-15 04:40发布

问题:

I'm trying to understand when does standard library linking to my own binary. I've written the following:

#include <stdio.h>

double atof(const char*);

int main(){
    const char * v="22";
    printf("Cast result is %f", atof(v));
}

It's compiling successful with g++ -c main.cpp, but when I'm linking just created object file I've an error. Error descriptio is:

/tmp/ccWOPOS0.o: In function `main':
main.cpp:(.text+0x19): undefined reference to `atof(char const*)'
collect2: error: ld returned 1 exit status

But I don't understand why this error is caused? I think that the standard c++ library automatically linked to my binary by the ld linker. What is the difference between the including header files and just declaring a functions which I need to use explicitly .

回答1:

As a general rule in C++, it is a bad idea to manually declare library functions such as atof().

It used to be common in old C programs, but C doesn't have function overloading so it is more forgiving about "almost" correct declarations. (Well some of the old compilers were, I can't really speak for the newest ones). That is why we describe C as a "weakly typed" language, while C++ is a more "strongly typed" language.

An additional complication is that the compilers perform "name mangling": the name they pass to the linker is a modified version of the source name. The C compiler may perform quite different name mangling from the C++ compiler. The standard lib version of atof() is a C function. To declare it in a C++ source file you need to declare it as

extern "C"
{
    double atof(const char *);
}

or possibly

extern "C" double atof(const char *);

There are many additional complexities, but that is enough to go on with.

Safest idea is to just include the appropriate headers.

#include <iostream>
#include <cstdlib>

int main()
{
    const char v[]= "22";
    std::cout << "Cast result is " << atof(v) << std::endl;
    return 0;
}

Extra background in response to comment by @DmitryFucintv

  1. Calling conventions

When calling a function, a calling convention is an agreement on how parameters and return values are passed between the calling function and the called function. On x86 architecture, the two most common are __cdecl and __stdcall, but a number of others exist.

Consider the following:

/* -- f.c --*/

int __stdcall f(int a, double b, char *c)
{
    // do stuff
    return something;
}

/* main.c */

#include <iostream>
extern int __cdecl f(int a, double b, char *c);

int main()
{
    std::cout << f(1, 2.3, "45678") << std::endl;
    return 0;
}

In a C program, this will probably compile and link OK. The function f() is expecting its args in __stdcall format, but we pass them in __cdecl format. The result is indeterminate, but could easily lead to stack corruption.

Because the C++ linker is a bit fussier, it will probably generate an error like the one you saw. Most would agree that is a better outcome.

2 Name Mangling

Name Mangling (or name decoration) is a scheme where the compiler adds some extra characters to the object name to give some hints to the linker. An object might be a function or a variable. Languages that permit function overloading (like C++ and Java) must do something like this so that the linker can tell the difference between different functions with the same name. e.g.

int f(int a);
int f(double a);
int f(const char *a, ...);


回答2:

It's because atof has C linkage, and you're compiling this as C++ - change:

double atof(const char*);

to:

extern "C" double atof(const char*);

and it should work.

Obviously you should not normally do this and you should just use the correct header:

 #include <cstdlib>


回答3:

This has nothing to do with the standard library.

The problem you have is that atofis not being defined, so the linker doesn't find it. You need to define the function, otherwise is impossible to know what the code is supposed to do.

And it looks like atof is a C function in the header stdlib.h. This code should work, although is not using C++ exclusive functions.

#include <stdlib.h>

int main(){
    const char * v="22";
    printf("Cast result is %f", atof(v));
}


回答4:

When you declare atof, you're declaring a subtly different function to the standard one. The function you're declaring is not defined in the standard library.

Don't re-declare standard functions, because you're liable to getting it wrong, as here. You're including the header and the header correctly declares the functions for you.