C++中实现定义行为操作是否允许多次执行选择不同合法结果?
相关标准条款依据
- [conv.fpint] 第2款规定
若待转换值处于可表示值范围内但无法被精确表示,则选择相邻更低或更高可表示值的行为属于**implementation-defined(实现定义)**行为。
- [intro.abstract] 第2款规定
本标准将抽象机的特定方面与操作描述为实现定义(例如
sizeof(int)),这些内容构成抽象机的参数。每个实现必须附带文档,说明其在这些方面的特征与行为,该文档需定义对应该实现的抽象机实例(以下简称“对应实例”)。
- [intro.abstract] 第5款规定
执行良构程序的符合标准实现,产生的可观测行为必须与同一程序、同一输入下对应抽象机实例的某一可能执行路径的可观测行为一致。但若任意执行路径包含未定义操作,本标准对该输入下执行该程序的实现无任何约束(即使对首个未定义操作之前执行的操作也无要求)。
问题
被定义为实现定义行为的操作是否可以存在多种可能执行结果?
考虑如下场景:某实现的float类型无法精确表示值16777217,按标准该场景下可选择相邻的16777216或16777218作为转换结果,但该实现设定规则为:该转换奇数次求值时选择更低的可表示值,偶数次求值时选择更高的可表示值,示例代码如下:
float a1 = 16777217; // 16777216 float a2 = 16777217; // 16777218 . . . float a<2n-1> = 16777217; // 16777216 float a<2n> = 16777217; // 16777218
更新补充场景
另一同类场景示例:
sizeof(int); // 4 sizeof(int); // 8 . . . sizeof(int); // 4 sizeof(int); // 8
即sizeof(int)奇数次求值结果均为4,偶数次求值结果均为8。上述两种场景下的实现是否属于符合C++标准的合规实现?
解答
这两种场景下的实现都不符合C++标准的合规要求,判断依据非常明确:
- 首先要明确实现定义行为的核心约束:标准规定实现定义的内容是抽象机的固定参数,实现必须通过公开文档明确这些参数、对应行为规则,最终定义出一个确定的抽象机实例。所谓“实现可自行选择”,指的是实现在标准划定的可选范围内选定一套固定、可复现的规则,绝非允许实现随意输出不稳定的随机结果。
- 针对
sizeof(int)的场景:int是C++的基础算术类型,类型大小是类型本身的固有属性,同一类型的大小在整个程序生命周期内必须保持一致。如果奇数次求值sizeof(int)返回4、偶数次返回8,等于int类型本身的定义都处于跳变状态,根本无法构造出一个符合标准要求的确定抽象机实例,这种实现从基础逻辑上就不合规。 - 针对浮点数转换的场景:标准确实允许无法精确表示值时选择相邻的低值或高值,但这个选择规则必须是确定的。比如实现可以文档明确规定“所有这类转换一律舍入到更低的可表示值”,或者“按照当前浮点控制寄存器设置的舍入模式选择结果”,这些都是合规的实现。但如果规则是随求值次数奇偶来回跳,意味着同样的转换操作、相同的输入、相同的程序状态下没有确定结果,这种规则根本无法作为抽象机的固定参数,也满足不了“文档明确定义行为”的强制要求,自然不属于合规实现。
- 注意不要混淆实现定义行为和未定义行为的边界:实现定义是给实现划定了可选的规则范围,要求实现在范围内选定固定、可复现、文档化的行为逻辑;未定义行为才是标准不对实现做任何约束的场景。随求值次数跳变的不稳定行为,不属于实现定义行为允许的选择范畴。
内容的提问来源于stack exchange,提问作者xmh0511
相关产品推荐
相关产品推荐

