在C语言中,我该如何将无符号长整型(unsigned long)的值转换为字符串(char *),并保持我的源代码可移植性,或者只需重新编译使其在其他平台上工作(而无需重写代码)?
例如,如果我有sprintf(buffer, format, value),我该如何以与平台无关的方式确定缓冲区的大小?
例如,如果我有sprintf(buffer, format, value),我该如何以与平台无关的方式确定缓冲区的大小?
const int n = snprintf(NULL, 0, "%lu", ulong_value);
assert(n > 0);
char buf[n+1];
int c = snprintf(buf, n+1, "%lu", ulong_value);
assert(buf[n] == '\0');
assert(c == n);
char buf[n+1];
)需要C99。 - kennytmsprintf(buffer, "%lu", value);
将value
的字符串表示写入buffer
中。然而,溢出是一个潜在的问题,因为sprintf
会快乐地(且不知情地)写入你的缓冲区末尾。snprintf
作为替代方案,它允许您指定最大缓冲区大小。snprintf
。它是标准的,并且提供了完全解决此问题的支持。 - Johannes Schaub - litbsnprintf
;您可以轻松地限制所需缓冲区的大小。(另一方面,使用 %s
进行打印则需要谨慎。) - Donal Fellowssnprintf
指定非常明确的上限,而不是考虑数字大小来数学地建立这样的上限,更糟糕的是,在我看来,他们会用对数来预先计算那个大小。 - Carl Smotriczchar *ultostr(unsigned long value, char *ptr, int base)
{
unsigned long t = 0, res = 0;
unsigned long tmp = value;
int count = 0;
if (NULL == ptr)
{
return NULL;
}
if (tmp == 0)
{
count++;
}
while(tmp > 0)
{
tmp = tmp/base;
count++;
}
ptr += count;
*ptr = '\0';
do
{
res = value - base * (t = value / base);
if (res < 10)
{
* -- ptr = '0' + res;
}
else if ((res >= 10) && (res < 16))
{
* --ptr = 'A' - 10 + res;
}
} while ((value = t) != 0);
return(ptr);
}
char buffer [50];
unsigned long a = 5;
int n=sprintf (buffer, "%lu", a);
尝试使用sprintf
函数:
unsigned long x=1000000;
char buffer[21];
sprintf(buffer,"%lu", x);
编辑:
请注意,您需要提前分配一个缓冲区,并且不知道在这样做时数字实际上会有多长。 我假设是32位的long
,可以产生10位数的数字。
请查看Carl Smotricz的答案,以获得有关涉及问题的更好解释。
对于长整型数值,您需要添加长度信息“l”和无符号十进制整数“u”,
有关可用选项的参考,请参见sprintf
#include <stdio.h>
int main ()
{
unsigned long lval = 123;
char buffer [50];
sprintf (buffer, "%lu" , lval );
}
value_copy = value;
unsigned size_needed = 1; // For the null character.
if (value_copy < 0) size_needed++; // Only needed for signed types.
do {
size_needed++; // Add 1 per digit.
value_copy /= 10;
} while (value_copy != 0);
查找ULONG_MAX
的字符串长度。
从巧妙的IMAX_BITS(m)
开始,它返回类似于ULONG_MAX
的Mersenne Number中位数的位数。(即使类型有填充,这也给我们最大的位宽。)然后乘以log102(0.301...)以找到十进制数字的数量,并加上2进行四舍五入和空字符。
#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
#define LOG2_10_N 28
#define LOG2_10_D 93
#define UNSIGNED_LONG_STRING_SIZE (IMAX_BITS(ULONG_MAX)*LOG2_10_N/LOG2_10_D + 2)
// Slightly different for signed types, one more for the sign:
#define SIGNED_LONG_STRING_SIZE (IMAX_BITS( LONG_MAX)*LOG2_10_N/LOG2_10_D + 3)
有了字符串大小,就有许多可能的下一步。我喜欢使用C99(及更高版本)的复合字面量来形成所需的空间。该空间在块的末尾之前都是有效的。
char *unsigned_long_to_string(char *dest, unsigned long x) {
sprintf(dest, "%lu", x);
return dest;
}
// Compound literal v-----------------------------------v
#define UNSIGNED_LONG_TO_STRING(u) unsigned_long_to_string((char [UNSIGNED_LONG_STRING_SIZE]){0}, (u))
int main(void) {
puts(UNSIGNED_LONG_TO_STRING(42));
puts(UNSIGNED_LONG_TO_STRING(ULONG_MAX));
}
输出
42
18446744073709551615 // This varies
strlen
确定实际生成的字符串长度,calloc
一个(该大小+1)的缓冲区并将字符串复制到其中。 - Carl Smotriczlog10(ULONG_MAX)
... - kennytmsnprintf
,那么它是一个绝佳的答案。请查看我的回答以获取更多详细信息。 - Carl Smotricz