2

后续问题:

  1. 类型转换:double to char:多个问题
  2. 将无符号值分配给有符号字符

背景:ISO/IEC 9899:202x (E) 工作草案 — 2020 年 2 月 5 日 C17..C2x N2479(已添加重点):

J.3实现定义的行为,J.3.5 整数

— 当值不能在该类型的对象中表示时,将整数转换为有符号整数类型的结果或产生的信号(6.3.1.3)。

6.3.1.4 实数浮点数和整数

当标准浮点类型的有限值转换为 _Bool 以外的整数类型时,小数部分被丢弃(即,该值被截断为 0)。如果整数部分的值不能用整数类型表示,则行为未定义

问题:为什么将“超出范围的整数转换为整数”会导致 IB,但将“超出范围的浮点数转换为整数”会导致 UB?即为什么行为不一致(例如两种情况下的IB)?

UPD。用户 PP 在重复问题中的回答:

我怀疑它是否可以合理回答。这主要是因为历史,并且基于C标准化时的实现,硬件行为等。所以“一致性”是不可能的/不切实际的(这不像委员会决定任意将某些行为归类为 IB、UB 或未指定)。

4

1 回答 1

2

从标准的角度来看,是否将某物分类为实现定义行为和未定义行为的问题取决于是否应要求所有实现都记录与语言语义大体一致的行为,无论成本或有用性如何. 没有必要强制实施以客户认为有用的方式处理操作,因为预期允许以这种方式运行的实施无论是否有授权都会这样做。因此,将实现可能 100% 一致地处理的有用动作描述为未定义行为比将有时可能无法一致实现的实现定义动作描述为更好。

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

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 将始终执行而没有副作用的平台上,或在允许将超出范围的转换视为未定义行为的实现上,x/(y+1) 的计算和转换为 short 可以推迟到在调用 f1 之后,如果 f1 返回零,则完全跳过。然而,这种转换可能会影响由转换引发的信号的行为,因此在转换可能引发信号的实现标准下似乎是不允许的。

另一方面,虽然在越界转换的情况下让实现发出信号可能很有用,但这种信号主要在诊断质量被视为比性能更重要的情况下有用。如果将转换处理为没有副作用,则性能更重要的实现可以自由地进行上述优化,并且似乎后一种操作过程在所有平台上都是可行的。

float在某些平台上,将 a 转换为遗嘱的最快方法是int陷阱;如前所述,一个动作可能陷入的可能性会使分类为实现定义的行为代价高昂。虽然不太可能有任何平台处理从例如floattoshort的转换为从floatto的转换int,然后是从intto的转换是不切实际的short,但有些平台可能不是最有用的行为(例如,如果平台可以免费将这种转换的结果与目标类型的范围挂钩,那么这可能比转换为更有用int然后是目标类型)。即使标准的作者预期并打算从浮点类型到小整数类型的转换永远不会对 范围内的任何值产生未排序的陷阱,但标准仍将其int归类为 UB 一般操作,在某些情况下可能会出现不可预测的行为但在其他情况下以可预测的特定于实现的方式,而不需要任何努力来确定它们应该以可预测的方式表现的特定情况。

通过检查 C89 和 C99 中描述左移的方式,可能最好地说明后一个原则。没有理由不应该为 的所有整数值x << 0屈服,而 C89 指定行为的方式正是这样做的。然而,C89 规范在某些情况下指定了行为,允许某些实现以不同的且不一定可预测的方式运行可能很有用。C99 没有努力确定所有实现都应以与 C89 相同的方式处理负数左移的情况,因为作者预计所有实现都将以 C89 方式处理此类情况,无论是否有授权。xx

于 2021-03-14T22:22:49.473 回答