c语言数据缓冲区最小长度单位换算,c-确定sprintf缓冲区的大小-标准是什么?

c-确定sprintf缓冲区的大小-标准是什么?

When converting an int like so:

char a[256];

sprintf(a, "%d", 132);

确定应该多大的最佳方法是什么? 我认为手动设置是可以的(就像我在任何地方看到的那样),但是应该设置多大? 在32位系统上,最大的int值是多少?是否有一些棘手的方法可以即时确定该值?

7个解决方案

77 votes

这里有些人在争论这种方法是过大的,对于将int转换为字符串,我可能更倾向于同意。 但是,当找不到字符串大小的合理范围时,我已经看到了这种方法,并且自己使用了。

int size = snprintf(NULL, 0, "%d", 132);

char * a = malloc(size + 1);

sprintf(a, "%d", 132);

我将分解这里发生的事情。

在第一行,我们要确定需要多少个字符。 snprintf的前两个参数告诉我,我要将结果的0个字符写入NULL。这样做时,malloc实际上不会在任何地方写入任何字符,它只会返回将要写入的字符数。 这就是我们想要的。

在第二行,我们正在动态分配内存到malloc指针。 确保将1加上所需的大小(对于尾随char终止字符)。

现在已经为malloc指针分配了足够的内存,我们可以安全地使用char将整数写入char指针。

当然,如果需要,您可以使其更简洁。

char * a = malloc(snprintf(NULL, 0, "%d", 132) + 1);

sprintf(a, "%d", 132);

除非这是一个“快速且肮脏的”程序,否则您始终要确保释放使用malloc调用的内存。这是动态方法与C并存的地方。但是,恕我直言,如果您不想分配 庞大的char指针,在大多数情况下,您只会使用其中很小的一部分,那么我认为这不是一个坏方法。

Daniel Standage answered 2020-07-27T06:45:57Z

14 votes

通过使用C ++ 11 / C99中的vsnprintf,可以使Daniel Standage的解决方案适用于任意数量的参数。

int bufferSize(const char* format, ...) {

va_list args;

va_start(args, format);

int result = vsnprintf(NULL, 0, format, args);

va_end(args);

return result + 1; // safe byte for \0

}

根据c99标准中第7.19.6.12节的规定:

vsnprintf函数返回的字符数 如果n足够大,就已经写了,不算 终止的空字符,如果为负则为负值

发生编码错误。

Regis Portalez answered 2020-07-27T06:46:31Z

13 votes

一个int的最大可能位数为int,一个十进制数字“值”至少3位,因此任意int所需的空间上的松散上限为snprintf。那个+3是一个事实, 我们在分割时四舍五入,一个为符号,一个为nul终止符。

如果“在32位系统上”表示您知道int是32位,则需要12个字节。 10代表数字,一个代表符号,一个代表nul终止符。

在您的特定情况下,要转换的int为int,则需要4个字节。 巴杜姆,吃。

固定大小的缓冲区可以在合理的范围内使用时,它们是更简单的选择。 我不太谦虚地认为上述限制是合理的(32位int为13字节而不是12,而64位int为23字节而不是21)。 但是对于困难的情况,在C99中,您可以致电snprintf来获取大小,然后致电malloc那么多。 对于这样一个简单的案例,这太过分了。

Steve Jessop answered 2020-07-27T06:45:10Z

8 votes

我看到此对话已有两年的历史了,但是我在尝试找到MS VC ++的答案时发现了它,而snprintf不能用来找到它的大小。 我将发布最终找到的答案,以防它对其他人有帮助:

VC ++具有功能_scprintf,专门用于查找所需的字符数。

HopeItHelps answered 2020-07-27T06:46:56Z

2 votes

如果您要打印一个简单的整数,而没有别的什么,那么确定输出缓冲区大小的方法要简单得多。 至少在计算上更简单,代码有点笨拙:

char *text;

text = malloc(val ? (int)log10((double)abs(val)) + (val < 0) + 2 : 2);

log10(value)返回在基数10中存储正非零值所需的位数(减一)。对于小于1的数字,它有点偏离轨道,因此我们指定abs(),并将特殊逻辑编码为零 (三元运算符,测试?truecase:falsecase)。 添加一个用于存储负数的符号(val <0)的空间,一个用于弥补与log10的差,另一个用于空终止符(总计2),您已经计算出 给定数字所需的确切存储空间量,而无需两次调用snprintf()或等效函数来完成工作。 另外,它通常使用的内存少于INT_MAX所需的内存。

但是,如果您需要非常快速地打印大量数字,则不必分配INT_MAX缓冲区,然后重复打印该数字。 较少的内存颠簸效果更好。

另请注意,您可能实际上并不需要(double)而不是(float)。 我没有打扰检查。 像这样来回投射也可能是一个问题。 YMMV在所有这些上。 不过,对我来说效果很好。

Pegasus Epsilon answered 2020-07-27T06:47:30Z

1 votes

您担心缓冲区大小会很好。 要将这种思想应用到代码中,我将使用snprintf

snprintf( a, 256, "%d", 132 );

要么

snprintf( a, sizeof( a ), "%d", 132 ); // when a is array, not pointer

Arun answered 2020-07-27T06:47:54Z

0 votes

首先,sprintf是魔鬼。 如果有的话,请使用snprintf,否则您将有可能浪费内存并导致应用程序崩溃。

至于缓冲区的大小,就像所有其他缓冲区一样-尽可能小,必要时要大。 在您的情况下,您有一个带符号的整数,因此请使用尽可能大的大小,并随时添加一点安全填充。 没有“标准尺寸”。

它也不取决于您所运行的系统。 如果您在堆栈上定义了缓冲区(如您的示例中所示),则取决于堆栈的大小。 如果您自己创建线程,则可以自己确定堆栈大小,以便知道限制。 如果您期望递归或深层堆栈跟踪,那么还需要格外小心。

EboMike answered 2020-07-27T06:48:24Z

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值