【发布时间】:2015-05-18 23:20:20
【问题描述】:
以字节为单位查找某些数据的大小是一种常见的操作。
人为的例子:
char *buffer_size(int x, int y, int chan_count, int chan_size)
{
size_t buf_size = x * y * chan_count * chan_size; /* <-- this may overflow! */
char *buf = malloc(buf_size);
return buf;
}
这里明显的错误是整数会溢出(例如,一个 23171x23171 RGBA 字节缓冲区)。
3 个或更多个值相乘时的提升规则是什么?
(一对值相乘很简单)
我们可以稳妥行事,直接施放:
size_t buf_size = (size_t)x * (size_t)y * (size_t)chan_count * (size_t)chan_size;
另一种选择是添加括号以确保乘法和提升的顺序是可预测的(并且对之间的自动提升按预期工作)...
size_t buf_size = ((((size_t)x * y) * chan_count) * chan_size;
...可行,但我的问题是。
是否有确定的方法将 3 个或更多值相乘以确保它们会自动提升?
(避免溢出)
或者这是未定义的行为?
注意事项...
- 在这里使用
size_t不会防止溢出,它只是防止溢出该类型的最大值。 - 在给出的示例中,让参数也可以是
size_t是有意义的,但这不是这个问题的重点。
【问题讨论】:
-
考虑将所有参数设为
size_t,避免在函数中进行强制转换。如果您使用int参数,请考虑在相乘之前确保它们都是非负的(如果不是正数)——但是您可能需要 3 次转换才能安全,4 次才能系统/一致。 -
@Jonathan Leffler,是的,在这个例子中你的权利。但这不是问题的重点——输入可能是
int,原因有很多——例如,图像格式可能使用整数。 -
这是第一句话;这不是一个选择。因此,您继续看第二句话。
-
"但是你可能需要 3 次强制转换" - 我喜欢更简洁可能,如果这是编译器特定的(未定义) 行为。没关系。然后最好只添加演员表。但是如果 C 规范中有一个令人难忘的规则。意识到这一点是很好的,以便在审核代码时标记潜在的错误。
-
这取决于您要承担的风险。你认为如果你省略一些强制转换,编译器有可能做出错误的决定吗?如果是这样,请不要冒险。当有整数溢出的机会时,现代编译器似乎想不遗余力地破坏代码。我不会冒险的。标准可能说“你应该没事”,但我没有确保这一点,因为我不喜欢冒险。这就是我制作 cmets 的原因,而不是答案。这还不够确定,不能作为答案。如果有人提出一个引用标准的答案,表明你是安全的(或不安全的),那就太好了。
标签: c casting integer-promotion