C编程——integer/long转字符串表示
C programming - integer/long to string representation
我正在阅读 "C Interfaces and Implementations"。书中描述了一些非常有趣的概念。代码有时非常丑陋(在我看来),但现在我遇到了关于将 integer/long 转换为字符串(字符数组)的问题。书中描述的是:
const char *Atom_int(long n) {
char str[43];
char *s = str + sizeof str;
unsigned long m;
if (n == LONG_MIN)
m = LONG_MAX + 1UL;
else if (n < 0)
m = -n;
else
m = n;
do
*--s = m%10 + '0';
while ((m /= 10) > 0);
if (n < 0)
*--s = '-';
return Atom_new(s, str + sizeof str - s);
}
因为没有描述为什么这个函数是这样使用的...我想知道为什么它不只是像这样简单的东西:
const char *Atom_int(long n)
{
char str[43];
char *s = str;
sprintf(str, "%ld", n);
return Atom_new(s, str + sizeof str - s);
}
有什么区别吗?关于使用 sprintf 的 "simple" 方法,我是否遗漏了任何可能导致与书中函数不同的结果?我的意思是,如果它只是为了展示如何在不使用 ltoa/sprintf/... 的情况下将 long 转换为字符串,那很好。但如果这是唯一的原因,那就没必要复杂了,...
您为这两个函数提供的原始代码存在两个主要问题os:
str
数组未 '[=13=]'
终止,传递给 printf
时调用未定义的行为。
- 将指针
s
返回到具有自动存储 str
的数组也是不正确的。取消引用此 return 值也将调用未定义的行为。
关于您的问题,第一个函数的目的ose 是显示整数到字符串转换器的实现。使用 sprintf
打败了这个 purpose。请注意作者如何处理 INT_MIN
的微妙情况:由于 most 系统上的整数溢出,计算 -n
会调用未定义的行为,尽管结果在所有现代系统上都是正确的.但完全符合标准 os 是一门困难的艺术:他的解决方案假定 2s 补码,否则将失败。
这是使用相同原型的改进解决方案。它更便携,不需要特殊情况 LONG_MIN
,减少除法和模运算。
const char *Atom_int(long n) {
char str[43];
char *s = str + sizeof str;
unsigned long m;
if (n < 0)
m = (unsigned long)-(n + 1) + 1;
else
m = n;
while (m >= 10) {
*--s = m % 10 + '0';
m /= 10;
}
*--s = m + '0';
if (n < 0)
*--s = '-';
return Atom_new(s, str + sizeof str - s);
}
另请注意,您的 proposed 备选方案不正确:您将错误的长度传递给 Atom_new()
。您应该传递 return 由 sprintf
或 snprintf
编辑的字节数。这是一个改进的版本:
const char *Atom_int(long n) {
char str[43];
return Atom_new(str, snprintf(str, sizeof str, "%ld", n));
}
我正在阅读 "C Interfaces and Implementations"。书中描述了一些非常有趣的概念。代码有时非常丑陋(在我看来),但现在我遇到了关于将 integer/long 转换为字符串(字符数组)的问题。书中描述的是:
const char *Atom_int(long n) {
char str[43];
char *s = str + sizeof str;
unsigned long m;
if (n == LONG_MIN)
m = LONG_MAX + 1UL;
else if (n < 0)
m = -n;
else
m = n;
do
*--s = m%10 + '0';
while ((m /= 10) > 0);
if (n < 0)
*--s = '-';
return Atom_new(s, str + sizeof str - s);
}
因为没有描述为什么这个函数是这样使用的...我想知道为什么它不只是像这样简单的东西:
const char *Atom_int(long n)
{
char str[43];
char *s = str;
sprintf(str, "%ld", n);
return Atom_new(s, str + sizeof str - s);
}
有什么区别吗?关于使用 sprintf 的 "simple" 方法,我是否遗漏了任何可能导致与书中函数不同的结果?我的意思是,如果它只是为了展示如何在不使用 ltoa/sprintf/... 的情况下将 long 转换为字符串,那很好。但如果这是唯一的原因,那就没必要复杂了,...
您为这两个函数提供的原始代码存在两个主要问题os:
str
数组未'[=13=]'
终止,传递给printf
时调用未定义的行为。- 将指针
s
返回到具有自动存储str
的数组也是不正确的。取消引用此 return 值也将调用未定义的行为。
关于您的问题,第一个函数的目的ose 是显示整数到字符串转换器的实现。使用 sprintf
打败了这个 purpose。请注意作者如何处理 INT_MIN
的微妙情况:由于 most 系统上的整数溢出,计算 -n
会调用未定义的行为,尽管结果在所有现代系统上都是正确的.但完全符合标准 os 是一门困难的艺术:他的解决方案假定 2s 补码,否则将失败。
这是使用相同原型的改进解决方案。它更便携,不需要特殊情况 LONG_MIN
,减少除法和模运算。
const char *Atom_int(long n) {
char str[43];
char *s = str + sizeof str;
unsigned long m;
if (n < 0)
m = (unsigned long)-(n + 1) + 1;
else
m = n;
while (m >= 10) {
*--s = m % 10 + '0';
m /= 10;
}
*--s = m + '0';
if (n < 0)
*--s = '-';
return Atom_new(s, str + sizeof str - s);
}
另请注意,您的 proposed 备选方案不正确:您将错误的长度传递给 Atom_new()
。您应该传递 return 由 sprintf
或 snprintf
编辑的字节数。这是一个改进的版本:
const char *Atom_int(long n) {
char str[43];
return Atom_new(str, snprintf(str, sizeof str, "%ld", n));
}