數值與字符串轉換是C/C++開發中最高頻的操作之一。本文系統梳理int/long/float/double與string雙向轉換的四種主流方法,對比其適用場景、優缺點與注意事項。
#include <stdlib.h>
int a = 3;
long b = 23;
char buf1[32], buf2[32];
itoa(a, buf1, 10); // 十進制,buf1 = "3"
ltoa(b, buf2, 10); // buf2 = "23"
#include <stdio.h>
int a = 3;
float b = 4.2f;
char buf[64];
sprintf(buf, "%d,%.2f", a, b); // buf = "3,4.20"
snprintf(buf, sizeof(buf), "%d,%.2f", a, b); // 安全版本
sprintf不安全(緩衝區溢出),需用snprintf;類型不匹配導致未定義行為
#include <sstream>
#include <string>
int a = 3;
float b = 4.2f;
std::ostringstream oss;
oss << a << "," << b;
std::string s = oss.str(); // s = "3,4.2"
operator<<),無緩衝區溢出風險
#include <string>
std::string s1 = std::to_string(42); // "42"
std::string s2 = std::to_string(3.14159); // "3.141590" (固定6位小數)
#include <stdlib.h>
int a = atoi("32"); // 32
long b = atol("333"); // 333
double c = atof("23.4"); // 23.4
atoi("abc")返回0),無溢出檢測
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
char *endptr;
long val = strtol("333", &endptr, 10); // 十進制
if (endptr == str) { /* 無有效數字 */ }
if (*endptr != '\0') { /* 尾部有非數字字符 */ }
if (errno == ERANGE) { /* 溢出 */ }
endptr、errno),支持任意進制(2-36)
#include <stdio.h>
int a; float b;
sscanf("23 23.4", "%d %f", &a, &b); // 返回成功匹配項數
#include <sstream>
#include <string>
std::istringstream iss("23 23.4");
int a; float b;
if (iss >> a >> b) { /* 成功 */ }
fail()、bad()),支持用戶類型
#include <string>
std::string s = "3.14";
size_t pos;
double d = std::stod(s, &pos); // pos = 4
// 異常處理
try {
int i = std::stoi("abc");
} catch (const std::invalid_argument&) { /* 格式錯誤 */ }
catch (const std::out_of_range&) { /* 溢出 */ }
pos獲取解析位置,支持進制前綴(0x, 0)| 場景 | 推薦方案 | 備選 |
|---|---|---|
| C代碼,整數轉字符串 | snprintf | itoa(Windows) |
| C代碼,浮點數轉字符串 | snprintf | - |
| C++11+,簡單轉換 | to_string / stoi/stod | stringstream |
| C++,高性能/格式控制 | snprintf / fmt庫 | ostringstream |
| C代碼,健壯解析 | strtol/strtod | sscanf |
| C++,異常風格錯誤處理 | stoi/stod | istringstream |
snprintf替代sprintf,指定緩衝區大小strtol/strtod或C++11函數snprintf("%.6f")或std::setprecisionERANGE或捕獲out_of_range掌握各種轉換方法的特性與適用邊界,能顯著提升代碼的健壯性、可移植性與可維護性。