atof、stof和strtof的用法和区别

        atof、stof和strtof是 C++ 和 C 标准库中用于将字符串转换为浮点数的函数,它们有相似的功能,但在使用和细节上并不相同。


std::atof

std::atof 是 C 标准库函数,用于将 C 风格的字符串(即 const char*)转换为 double 类型的数值。定义在 <cstdlib><stdlib.h>头文件中。

函数原型:

/**
* @brief atof      将字符串转换为双精度浮点数
* @param str       指向要转换的 C 风格字符串的指针
* @return          转换后的 double 类型的数值
*/
double atof(const char* str);

异常处理:std::atof 不提供异常处理机制。如果转换失败,它返回 0.0,无法区分空字符串和转换失败。

函数用法:

#include <iostream>
#include <cstdlib>

int main() {
    const char* str = "123.45";
    double num = std::atof(str);
    std::cout << "Converted number: " << num << std::endl;
    return 0;
}

输出:

Converted number: 123.45 

std::stof

std::stof 是 C++11 引入的标准库函数,定义在 <string> 头文件中。

函数原型:

/**
* @brief stof      将字符串转换为浮点数
* @param str       要转换的字符串
* @param pos       指向一个 size_t 对象,存储转换后第一个未处理字符的索引(可选)
* @return          转换后的 float 类型的数值
*/
float stof(const std::string& str, std::size_t* pos = 0);

异常处理:如果转换失败,会抛出 std::invalid_argument 异常。如果值超出范围,会抛出 std::out_of_range 异常。 

函数用法:

#include <iostream>
#include <string>

int main() {
    std::string str = "123.45";
    try {
        float num = std::stof(str);
        std::cout << "Converted number: " << num << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "Conversion failed: " << e.what() << std::endl;
    }
    return 0;
}

输出:

Converted number: 123.45

std::strtof

std::strtof 是 C 标准库函数,用于将 C 风格的字符串转换为 float 类型的数值。定义在 <cstdlib> 头文件中。

函数原型:

/**
* @brief strtof    将字符串转换为浮点数
* @param str       指向要转换的 C 风格字符串的指针
* @param endptr    指向一个字符指针对象,用于存储转换后第一个未处理字符的地址(可选)
* @return          转换后的 float 类型的数值
*/
float strtof(const char* str, char** endptr);

异常处理:如果转换的值超出 float 类型的范围,返回 HUGE_VALF 或 -HUGE_VALF,并设置 errno 为 ERANGE。 endptr 可以用于检查是否整个字符串都被成功转换。

函数用法:

#include <iostream>
#include <cstdlib>
#include <cerrno>   // 用于 errno

int main() {
    const char* str = "123.45abc";
    char* endptr;

    float num = std::strtof(str, &endptr);

    std::cout << "Converted number: " << num << std::endl;
    if (*endptr != '\0') {
        std::cout << "Remaining string: " << endptr << std::endl;
    }

    if (errno == ERANGE) {
        std::cerr << "Out of range error." << std::endl;
    }

    return 0;
}

 输出:

Converted number: 123.45
Remaining string: abc

#include <iostream>
#include <cstdlib>
#include <cerrno>   // 用于 errno

int main() {
    char *str = (char *)malloc(strlen("123.45 67.89 12.345") + 1);
    strcpy(str, "123.45 67.89 12.345");
    float x = std::strtof(str, &str);
    float y = std::strtof(str, &str);
    float z = std::strtof(str, &str);
    std::cout << "Converted number: " << x << " " << y << " " << z << std::endl;
    if (*str != '\0') {
        std::cout << "Remaining string: " << str << std::endl;
    }

    if (errno == ERANGE) {
        std::cerr << "Out of range error." << std::endl;
    }td::cerr << "Out of range error." << std::endl;
    }

    return 0;
}

输出:

Converted number: 123.45 67.89 12.345 


使用建议

  • std::stof:如果你要转换的字符串是 std::string 类型的,推荐在 C++11 及以上版本中使用,尤其是在需要异常处理的情况下。
  • std::atof:简单易用,但没有错误处理,不推荐用于需要严格错误检查的场景。
  • std::strtof:如果你要转换的字符串是 C 风格类型的 char *,推荐使用。适合需要细粒度控制和错误处理的场景,尤其在 C 语言环境中。

三者速度比较

  • std::atof:由于没有复杂的错误处理和检查机制,理论上应是最快的。它直接将字符串转换为 double 类型,简单高效。
  • std::strtof:相较于 std::atof,增加了 endptr 参数,用于错误检查和部分字符串转换,可能稍微增加一点开销,但还是相对较快。
  • std::stof:由于需要处理 std::string 对象,并且包含异常处理机制,理论上是最慢的,但差异通常不是很大。

        实际的性能差异很大程度上取决于标准库的具体实现,各个编译器和标准库版本的优化程度可能有所不同。可以使用下面的代码查看自己编译器的各个函数的速度:

#include <iostream>
#include <string>
#include <cstdlib>
#include <chrono>
#include <cstring>
#include <stdexcept>

void test_atof() {
    const char* str = "123.456";
    for (int i = 0; i < 1000000; ++i) {
        double num = std::atof(str);
        (void)num; // 防止优化移除无用的变量
    }
}

void test_Strtof() {
    const char* str = "123.456";
    for (int i = 0; i < 1000000; ++i) {
        float num = strtof(str, nullptr);
        (void)num; // 防止优化移除无用的变量
    }
}

void test_Stof() {
    std::string str = "123.456";
    for (int i = 0; i < 1000000; ++i) {
        float num = std::stof(str);
        (void)num; // 防止优化移除无用的变量
    }
}

int main() {
    auto start = std::chrono::high_resolution_clock::now();
    test_atof();
    auto end = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> duration = end - start;
    std::cout << "std::atof: " << duration.count() << " seconds" << std::endl;

    start = std::chrono::high_resolution_clock::now();
    test_Strtof();
    end = std::chrono::high_resolution_clock::now();
    duration = end - start;
    std::cout << "strtof: " << duration.count() << " seconds" << std::endl;

    start = std::chrono::high_resolution_clock::now();
    test_Stof();
    end = std::chrono::high_resolution_clock::now();
    duration = end - start;
    std::cout << "stof: " << duration.count() << " seconds" << std::endl;

    return 0;
}

输出:

std::atof: 0.923375 seconds
strtof: 0.87684 seconds
stof: 0.996698 seconds

        这个测试程序运行 1,000,000 次转换操作,并测量每个函数的执行时间。从输出结果来看,是std::strtof比较快。 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值