标准c++库链接
Standard c++ library linking
我正试图了解标准库何时链接到我自己的二进制文件。我写了以下内容:
#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
链接器自动链接到我的二进制文件。包含头文件和仅仅声明我需要显式使用的函数之间有什么区别。
作为C++中的一般规则,手动声明atof()
等库函数是个坏主意。
它曾经在旧的C程序中很常见,但C没有函数重载,所以它对"几乎"正确的声明更宽容。(好吧,有些旧的编译器是,我真的不能代表最新的编译器)。这就是为什么我们将C描述为"弱类型"语言,而C++是一种更"强类型"的语言。
另一个复杂的问题是编译器执行"名称篡改":它们传递给链接器的名称是源名称的修改版本。C编译器可能执行与C++编译器截然不同的名称篡改。atof()
的标准库版本是一个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评论的额外背景
- 调用约定
调用函数时,调用约定是关于如何在调用函数和被调用函数之间传递参数和返回值的协议。在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格式,但我们以__cdecl格式传递它们。结果是不确定的,但很容易导致堆栈损坏。
因为C++链接器有点模糊,它可能会生成一个类似您所看到的错误。大多数人都认为这是一个更好的结果。
2名称Mangling
Name Mangling(或名称修饰)是一种方案,编译器在对象名称中添加一些额外的字符,以向链接器提供一些提示。对象可能是函数或变量。允许函数重载的语言(如C++和Java)必须这样做,以便链接器能够区分具有相同名称的不同函数。例如
int f(int a);
int f(double a);
int f(const char *a, ...);
这是因为atof
有C链接,您将其编译为C++更改:
double atof(const char*);
至:
extern "C" double atof(const char*);
它应该起作用。
显然,你通常不应该这样做,你应该只使用正确的标题:
#include <cstdlib>
这与标准库无关。
问题是atof
没有被定义,所以链接器找不到它。你需要定义函数,否则就不可能知道代码应该做什么。
看起来atof
是头stdlib.h中的C
函数。尽管没有使用C++独占函数,但这段代码应该可以工作。
#include <stdlib.h>
int main(){
const char * v="22";
printf("Cast result is %f", atof(v));
}
当您声明atof
时,您声明的是一个与标准函数略有不同的函数。您声明的函数是,而不是标准库中定义的。
不要重新声明标准函数,因为你很容易出错,就像这里一样。您包含了头,并且头为您正确地声明了函数。
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- CMake-按正确顺序将项目与C运行时对象文件链接
- 从链接列表c++中删除一个项目
- 有根的二进制搜索树.保留与其父级的链接
- 读取文件的最后一行并输入到链接列表时出错
- 静态数据成员的问题-修复链接错误会导致编译器错误
- node-gyp 在 macOS 上未正确链接库
- 基于boost的程序的静态链接——zlib问题
- 无法链接 CMake 中的本地库
- 内联函数中具有内部链接的全局变量
- 链接阶段在Ubuntu上失败,但在MacOS上失败
- 使用gcc从静态链接的文件中查找可选符号
- 我可以将一个用clang c++11编译的对象与另一个用c++17编译的对象链接起来吗
- 将--whole archive链接器选项与CMake和具有其他库依赖项的库一起使用
- 下面是我为检测链接列表中的循环而制作的代码
- 有了gcc,是否可以链接库,但前提是它存在
- 使用C链接在函数内部创建C++模板
- Visual Studio mkl_link_tool.exe链接错误
- 尝试链接我的着色器时,我收到错误代码"error c5145 must write to gl_position"
- 有人能帮我处理这个链接列表吗?C++