文号
831240
阅读
6821
回复
1
收藏
1
C语言中字符串与数字互相转换的函数
2017/02/26
IP:四川

字符串转换成数字

首先,不建议使用sscanf和atoi、atol、atoll、atof,它们无法检测溢出,而且atoX系列无法得知转换在何时结束。

C89函数,字节字符串:

  • strtol - 32位(windows)/64位(linux)有符号整数long,可指定进制
  • strtoul - 32位(windows)/64位(linux)无符号整数unsigned long,可指定进制
  • strtod - 双精度浮点数double

C95函数,宽字符串:

  • wcstol - 32位(windows)/64位(linux)有符号整数long,可指定进制
  • wcstoul - 32位(windows)/64位(linux)无符号整数unsigned long,可指定进制
  • wcstod - 双精度浮点数double

C99函数,字节字符串(需要VC2013):

  • strtoll - 64位有符号整数long long,可指定进制
  • strtoull - 64位无符号整数unsigned long long,可指定进制
  • strtoimax - 64位有符号整数intmax_t,可指定进制
  • strtoumax - 64位无符号整数uintmax_t,可指定进制
  • strtof - 单精度浮点数float
  • strtold - 扩展双精度浮点数long double

C99函数,宽字符串(需要VC2013):

  • wcstoll - 64位有符号整数long long,可指定进制
  • wcstoull - 64位无符号整数unsigned long long,可指定进制
  • wcstoimax - 64位有符号整数intmax_t,可指定进制
  • wcstoumax - 64位无符号整数uintmax_t,可指定进制
  • wcstof - 单精度浮点数float
  • wcstold - 扩展双精度浮点数long double

MSVC函数,字节字符串:

  • _strtoi64 - 64位(windows)有符号整数__int64,可指定进制
  • _strtoui64 - 64位(windows)无符号整数unsigned __int64,可指定进制

MSVC函数,宽字符串:

  • _wcstoi64 - 64位(windows)有符号整数__int64,可指定进制
  • _wcstoui64 - 64位(windows)无符号整数unsigned __int64,可指定进制
// long long and unsigned long long
#define strtoll _strtoi64
#define strtoull _strtoui64
#define wcstoll _wcstoi64
#define wcstoull _wcstoui64
// intmax_t and uintmax_t
#define strtoimax _strtoi64
#define strtoumax _strtoui64
#define wcstoimax _wcstoi64
#define wcstoumax _wcstoui64
// float
static float strtof(char *pstr, char **ppend) {
	double dblval = strtod(pstr, ppend);
	if ((_finite(dblval) && !_finite((float)dblval)) ||
		(dblval != 0 && (float)dblval == 0)) {
			errno = ERANGE;
	}
	return (float)dblval;
}
static float wcstof(wchar_t *pstr, wchar_t **ppend) {
	double dblval = wcstod(pstr, ppend);
	if ((_finite(dblval) && !_finite((float)dblval)) ||
		(dblval != 0 && (float)dblval == 0)) {
			errno = ERANGE;
	}
	return (float)dblval;
}
// long double
static long double strtold(char *pstr, char **ppend) { double dblval = strtod(pstr, ppend); return dblval; }
static long double wcstold(wchar_t *pstr, wchar_t **ppend) { double dblval = wcstod(pstr, ppend); return dblval; }

数字转换成字符串

数字转换成字符串,一般使用sprintf系列。由于一些历史的原因,sprintf系列函数发生了比较复杂的演化。

不安全版本函数的支持情况:

  • 原生支持C89标准的sprintf
  • 原生支持C89标准的vsprintf
  • 原生支持非标准的swprintf,VC2005后改为_swprintf
  • 原生支持非标准的vswprintf,VC2005后改为_vswprintf

安全版本函数的支持情况:

  • 原生支持非标准的_snprintf,见注释
  • 原生支持非标准的_snwprintf,见注释
  • 原生支持非标准的_vsnprintf,见注释(VC2015之前还被定义为vsnprintf)
  • 原生支持非标准的_vsnwprintf,见注释
  • VC2005开始支持C95标准的swprintf(替换之前的不安全版本)
  • VC2005开始支持C95标准的vswprintf(替换之前的不安全版本)
  • VC2015开始支持C99标准的snprintf
  • VC2015开始支持C99标准的vsnprintf(替换之前的非标准版本)

如果不需要安全性,可以直接使用sprintf和_swprintf。

如果需要兼容老版本VC,需要使用_snprintf和_snwprintf。

如果只需要兼容VC2005+,可以使用_snprintf和swprintf。

如果只需要兼容VC2015+,可以使用snprintf和swprintf。

注意_snprintf和_snwprintf和标准的版本不同:

_snprintf和_snwprintf字符串不溢出时会用一个0截断,字符串溢出时不会截断。

VC2015:

char buf[bufsz];
snprintf(buf, bufsz, "fmt", ...);

老版本VC实现方法:

char buf[bufsz];
memset(buf, 0, bufsz);
_snprintf(buf, bufsz - 1, "fmt", ...);

如果需要动态分配内存:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main()
{
	char *buf = NULL;
	int reqsz = 0;

	reqsz = _snprintf(NULL, 0, "%d", 12);
	buf = malloc(reqsz + 1);
	memset(buf, 0, reqsz + 1);
	_snprintf(buf, reqsz, "%d", 12);

	printf("%s\n", buf);

	free(buf);
	return 0;
}
</stdlib.h></string.h></stdio.h>
[ 修改于9年9个月前 - 2017/03/03 18:48:20 ]
笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的