我试图了解标准库何时链接到我自己的二进制文件。我写了以下内容:
#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
链接器自动链接到我的二进制文件。包含头文件和声明我需要明确使用的函数之间有什么区别。
答案 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评论的额外背景
调用函数时, 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
时,您正在为标准声明一个微妙的不同的功能。您声明的功能是 在标准库中定义。
请勿重新声明标准功能,因为您可能会错误地将其标记为错误。您已经正确地为头部和头部声明了函数。