作为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,但还存在许多其他类型。
考虑以下内容:
int __stdcall f(int a, double b, char *c)
{
return something;
}
#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程序中,这可能会编译和链接成功。函数
f()
期望以__stdcall格式传递参数,但我们以__cdecl格式传递参数。结果是不确定的,但很容易导致堆栈损坏。
因为C++链接器有些挑剔,它可能会生成像你看到的那样的错误。大多数人认为这是更好的结果。
2 名称修饰
名称修饰(或名称装饰)是一种方案,其中编译器向
对象名称添加一些额外的字符,以给链接器一些提示。一个
对象可以是函数或变量。允许函数重载的语言(如C++和Java)必须做一些类似的事情,以便链接器可以区分具有相同名称的不同函数。
例如:
int f(int a);
int f(double a);
int f(const char *a, ...);