标准c ++库链接

时间:2014-04-20 12:22:04

标签: c++ linker standard-library

我试图了解标准库何时链接到我自己的二进制文件。我写了以下内容:

#include <stdio.h>

double atof(const char*);

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

它使用g++ -c main.cpp编译成功,但是当我链接刚刚创建的目标文件时,我发现了一个错误。错误描述是:

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

但是我不明白为什么会出现这个错误?我认为标准的c ++库通过ld链接器自动链接到我的二进制文件。包含头文件和声明我需要明确使用的函数之间有什么区别。

4 个答案:

答案 0 :(得分:4)

作为C ++的一般规则,手动声明atof()等库函数是个坏主意。

它曾经在旧的C程序中很常见,但是C没有函数重载,因此它对“几乎”正确的声明更加宽容。 (好吧,有些旧的编译器,我真的不能说最新的编译器)。这就是为什么我们将C描述为“弱类型”语言,而C ++是一种更“强类型”的语言。

另一个复杂因素是编译器执行“名称修改”:它们传递给链接器的名称是源名称的修改版本。 C编译器可能会从C ++编译器执行完全不同的名称修改。 atof()的标准lib版本是C函数。要在C ++源文件中声明它,您需要将其声明为

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

或可能

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

还有许多额外的复杂性,但这足以继续下去。

最安全的想法是只包含适当的标题。

#include <iostream>
#include <cstdlib>

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

响应@DmitryFucintv评论的额外背景

  1. 调用约定
  2. 调用函数时, calling convention 是关于如何在调用函数和被调用函数之间传递参数和返回值的协议。在x86体系结构中,最常见的两个是__cdecl__stdcall,但其他一些存在。

    请考虑以下事项:

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

    在C程序中,这可能会编译并链接OK。函数f()期望__stdcall格式的args,但我们以__cdecl格式传递它们。结果是不确定的,但很容易导致堆栈损坏。

    因为C ++链接器有点麻烦,它可能会产生类似你看到的错误。大多数人都认为这是一个更好的结果。

    2名称管理

    Name Mangling(或名称修饰)是一种方案,编译器会在 object 名称中添加一些额外的字符,以便为链接器提供一些提示。 对象可以是函数或变量。允许函数重载的语言(如C ++和Java)必须执行类似的操作,以便链接器可以区分具有相同名称的不同函数。 e.g。

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

答案 1 :(得分:1)

这是因为atof具有C链接,并且您将其编译为C ++ - 更改:

double atof(const char*);

为:

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

它应该有用。

显然你通常不应该这样做,你应该使用正确的标题:

 #include <cstdlib>

答案 2 :(得分:0)

这与标准库无关。

您遇到的问题是atof未定义,因此链接器找不到它。您需要定义函数,否则无法知道代码应该做什么。

看起来atof是标题stdlib.h中的C函数。这段代码应该可行,但不使用C ++独占函数。

#include <stdlib.h>

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

答案 3 :(得分:0)

当您声明atof时,您正在为标准声明一个微妙的不同的功能。您声明的功能是 在标准库中定义。

请勿重新声明标准功能,因为您可能会错误地将其标记为错误。您已经正确地为头部和头部声明了函数。