首页 > 解决方案 > C 编译器是否假设有符号整数的加法是可交换的?

问题描述

我正在尝试检查签名添加是否会溢出。一般来说,检查是否

int a + int b

会溢出(a 和 b 都是正数),我检查是否

if (a > INT_MAX - b)

但现在我想检查一下

int a + int b - int c

会溢出。我知道 a、b 和 c 是正数并且 b >= c,所以我做了以下检查:

if (a > INT_MAX - b + c)

现在我的问题是,编译器可以重写吗

INT_MAX - b + c     to     INT_MAX + c - b   ?

我担心的是,它会首先执行 INT_MAX + c,这可能会溢出并导致未定义的行为。

标签: cinteger-overflow

解决方案


在推理未定义的行为时考虑“编译器”做了什么是一种谬误。编译器是透明的。行为在您的代码中,而不是在编译器中。您应该问“我的代码是什么 INT_MAX - b + c 意思?它会溢出吗?答案永远不在“编译器”中,而是在标准中。

该标准只要求出现在您的程序中的单个操作不会溢出。它从不提及任何未明确出现在程序中的重写表达式。在您的程序中,并且等效于. 所以要求是不溢出,然后加到的结果不溢出。不会出现在您的程序中,因此您不必担心它。INT_MAX - b + c(INT_MAX - b) + c(INT_MAX - b)cINT_MAX + c - b

如果编译器以任何方式重写您的表达式,它必须确保重写的表达式具有与您的相同的可见行为,根据as-if规则。因此,如果它确实替换INT_MAX - b + cINT_MAX + c - b,它必须确保溢出不会发生或被透明地处理(例如被硬件忽略)。


推荐阅读