且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

为什么将“超出范围整数转换为整数"会导致IB,而将“超出范围浮点转换为整数"会导致UB?

更新时间:2021-12-29 00:58:44

从标准的角度来看,是否将某类归类为实现定义的行为"和未定义的行为",取决于是否需要所有实现记录一种行为,该行为通常与该语言的语义一致,而不论其成本或实用性如何.无需强制要求实现以其客户认为有用的方式来处理操作,因为可以预期的是,允许执行的行为可以在有或没有授权的情况下这样做.因此,将其描述为未定义行为"的有用动作(实现可能会100%一致地处理)比将其定义为实现定义的动作"(有时可能无法始终如一地实现)是更好的选择.

From the point of view of the Standard, the question of whether to classify something as Implementation-Defined Behavior and Undefined Behavior depends on whether all implementations should be required to document a behavior generally consistent with the semantics of the language, regardless for cost or usefulness. There was no need to mandate that implementations process actions in ways their customers would find useful, because it was expected that implementations allowed to behave in such fashion would do so with or without a mandate. Consequently, it was seen as better to characterize as Undefined Behavior useful actions which implementations might process 100% consistently, than to characterize as Implementation-Defined actions which might sometimes be impractical to implement consistently.

请注意,对于将操作视为已记录行为的实现,有时可能会产生不明显的成本.考虑例如:

Note that for an implementation to treat an action as having documented behavior could sometimes have costs that might not be obvious. Consider, for example:

int f1(int x, int y);
int f2(int x, int y, int z);
void test(int x, unsigned char y)
{
  short temp = x/(y+1);
  if (f1(x,y))
    f2(x,y,temp);
}

在转换为short的平台将始终执行而不会产生副作用的平台上,或在允许将超出范围的转换视为Undefined Behavior的实现中,x/(y + 1)的计算和转换为short的操作可能推迟到调用f1之后,如果f1返回零,则完全跳过.但是,这种转换可能会影响转换产生的信号的行为,因此,在该标准中,转换可能产生信号的实现方式似乎是不允许的.

On platforms where the conversion to short would always execute without side effects, or on implementations that were allowed to treat out-of-range conversions as Undefined Behavior, the computation of x/(y+1) and conversion to short could be deferred until after the call to f1, and skipped altogether if f1 returns zero. Such transformation could affect the behavior of a signal raised by the conversion, however, and would thus not appear to be allowable under the Standard on implementations where the conversion could raise a signal.

另一方面,虽然在越界转换的情况下使实现提高信号可能是有用的,但这种信号主要在诊断质量比性能更重要的情况下有用.如果将性能视为更重要的实施将转换视为无副作用,则可以***地进行上述优化,并且后者的做法似乎在所有平台上都是可行的.

On the other hand, while it may be useful to have implementations raise a signal in case of an out-of-bounds conversion, such signals would mainly be useful in situations where quality of diagnostics was viewed as more important than performance. Implementations where performance was more important would be free to make optimizations like the above if they processed the conversion as having no side effects, and it seemed likely that the latter course of action would be practical on all platforms.

在某些平台上,将捕获将 float 转换为 int 的最快方法;如前所述,动作可能被捕获的可能性会使分类为实现定义"的行为变得昂贵.虽然不太可能存在任何平台来处理来自例如Google的转化是不切实际的从 float int 的转换,是 float short 的转换,然后是 int 的转换code>到 short ,在某些平台上,这可能不是最有用的行为(例如,如果某个平台可以不花任何额外费用将这种转换结果转换为目标类型的范围,可能比先转换为 int 然后再转换为目标类型更有用).即使该标准的作者曾期望并打算从浮点类型到小整数类型的转换永远不会对 int 范围内的任何值产生未排序的陷阱,但该标准仍归类为UB常规.在某些情况下可能会表现出不可预测的行为,而在另一些情况下可能会表现为特定于实现的行为,而无需进行任何努力来确定应以可预测的方式表现出来的特定情况.

There were platforms where the fastest way of converting a float to an int will trap; as noted, the possibility that an action may trap would make classification as Implementation-Defined behavior expensive. While it is unlikely that there would have been any platforms where it would have been impractical to process a conversion from e.g. float to short as a conversion from float to int, followed by a conversion from int to short, there are platforms where that may not be the most useful behavior (e.g. if a platform can at no extra cost peg the result of such a conversion to the range of the target type, that may be more useful than a conversion to int and then the target type). Even if the authors of the Standard would have expected and intended that conversions from floating-point types to small integer types never yield unsequenced traps for any values which are within range of int, the Standard classifies as UB general actions which might behave unpredictably in some cases but in a predictable implementation-specific fashion in others, without any effort to identify specific cases where they should behave predictably.

后一种原理也许可以通过检查C89和C99中描述的左移方式来***地说明.没有理由为什么 x<<0 不应为 x 的所有整数值产生 x ,而C89指定行为的方式将精确地做到这一点.但是,C89规范在某些情况下指定了行为,在某些情况下,允许某些实现以不同的方式(不一定是可预测的方式)运行可能会很有用.C99不会发现所有实现都应该像C89一样对待负数左移的情况,因为作者希望所有实现都可以以C89方式在有或没有授权的情况下处理此类情况.

The latter principle is perhaps best illustrated by examining the way left shift was described in C89 and C99. There is no reason why x << 0 shouldn't yield x for all integer values of x, and the way C89 specified the behavior would do precisely that. The C89 spec, however, specified behavior in some cases where it may be useful to allow some implementations to behave in a different, and not necessarily predictable, fashion. C99 makes no effort to identify situations where all implementations should treat left shifts of negative numbers the same way as C89 did, because the authors expected that all implementations would treat such cases in C89 fashion with or without a mandate.