gpt4 book ai didi

c - 使用 .* 宽度说明符调用 sprintf 时出现奇怪的警告

转载 作者:行者123 更新时间:2023-12-05 01:23:40 24 4
gpt4 key购买 nike

对于下面的代码:

https://godbolt.org/z/WcGf9hEs3

#include <stdio.h>

int main() {

char temp_buffer[8];
double val = 25.3;

sprintf(temp_buffer, "%.*g", sizeof(temp_buffer), val);
printf("%s", temp_buffer);
}

我在带有 -Wall 标志的 gcc 11.3 中收到警告:

<source>:8:29: warning: field precision specifier '.*' expects argument of type 'int', but argument 3 has type 'long unsigned int' [-Wformat=]
8 | sprintf(temp_buffer, "%.*g", sizeof(temp_buffer), val);
| ~~^~ ~~~~~~~~~~~~~~~~~~~
| | |
| int long unsigned int
<source>:8:27: warning: '%.*g' directive writing between 1 and 310 bytes into a region of size 8 [-Wformat-overflow=]
8 | sprintf(temp_buffer, "%.*g", sizeof(temp_buffer), val);
| ^~~~
<source>:8:26: note: assuming directive output of 12 bytes
8 | sprintf(temp_buffer, "%.*g", sizeof(temp_buffer), val);
| ^~~~~~
<source>:8:5: note: 'sprintf' output between 2 and 311 bytes into a destination of size 8
8 | sprintf(temp_buffer, "%.*g", sizeof(temp_buffer), val);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

事实上,目标缓冲区的大小太小,无法存储给定大小参数的值,但是警告 'sprintf' output between 2 and 311 bytes into a destination of size 8 ?那 311 字节的值从何而来?

如果我将小数位数转换为 int (int)sizeof(temp_buffer) 潜在的溢出数字会急剧下降:

'sprintf' output between 2 and 16 bytes into a destination of size 8

最佳答案

代码中存在多个问题:

  • sprintf 需要 * 占位符的 int 值,而您传递的 size_t 可能有不同的大小和代表。
  • 调用可能有未定义的行为,因为您请求的精度是目标数组的长度,这可能会产生超过所述长度的输出。

传递 sizeof(temp_buffer) 是一个错误,编译器似乎对实际参数值感到困惑,并且没有对精度值或要转换的数字做出特定假设。然而,当他们记录输出可以是 2 到 311 字节时,他们似乎错了:

  • 对于值 25.3,最接近的 IEEE 754 编号的精确表示是 25.300000000000000710542735760100185871124267578125,需要 52 个字节。
  • 通过 printf("%.1000g", -0x1.fffffffffffffp+1023) 输出的最大数字有 310 个字符,因此需要 311 个字节,这似乎是 2 到 311 字节.
  • 然而 %.*g 转换实际上可以产生超过 311 个字节:printf("%.1000g", -5e-324) 在两者上产生 758 个字符macOS 和 Linux。

当您将 sizeof(temp_buffer) 转换为 (int) 时,编译器确定精度为 8(非平凡的优化)并确定输出可以小到 2 字节(一个数字和一个空终止符)但不超过 16(-,一个数字,. 、7 个小数、e- 和多达 3 个指数数字加上一个空终止符。对于 8 字节数组来说,这仍然可能太多了。

很好地警告程序员这种潜在的未定义行为!

使用 snprintf(),一个更大的数组并传递 (int)(sizeof(temp_buffer) - 9) 作为精度以获得尽可能多的小数最坏的情况。很难产生适合所有情况的尽可能多的小数,并且可能需要多次尝试或复杂的后处理。

关于c - 使用 .* 宽度说明符调用 sprintf 时出现奇怪的警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72064283/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com