英文:
How do the augmented assignment operators in C behave when the signedness of the operands do not match?
问题
I have seen a similar question but mine is specifically referring to the augmented assignment operators such as +=
, -=
, etc. How exactly do the those operators work when I have the following?
extern signed s;
extern unsigned u;
s += u;
Will this be equivalent to this?
s = (signed)((unsigned)s+u);
More specifically would this invoke undefined behavior due to signed integer overflow?
signed s = INT_MAX;
unsigned u = 1;
s += u;
I am aware that when using the normal arithmetic operators, the unsigned type usually dominates. However, I am not sure if this holds true for the augmented assignment operators.
英文:
I have seen a similar question but mine is specifically referring to the augmented assignment operators such as +=
, -=
, etc. How exactly do the those operators work when I have the following?
extern signed s;
extern unsigned u;
s += u;
Will this be equivalent to this?
s = (signed)((unsigned)s+u);
More specifically would this invoke undefined behavior due to signed integer overflow?
signed s = INT_MAX;
unsigned u = 1;
s += u;
I am aware that when using the normal arithmetic operators, the unsigned type usually dominates. However, I am not sure if this holds true for the augmented assignment operators.
答案1
得分: 3
这段代码的翻译如下:
这个:
s += u;
与这个相同:
s = s + u;
根据[C标准](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf)的第6.5.16.2p3节:
> 形式为 `E1 op = E2` 的复合赋值等同于简单的赋值表达式 `E1 = E1 op (E2)`,只是 lvalue `E1` 仅被评估一次,并且在不确定序列的函数调用方面,复合赋值的操作是单次评估。
所以首先评估 `s + u`。这导致 `s` 转换为 `unsigned` 类型,按照通常的算术转换,结果是无符号的。然后将此结果赋回给 `s`,它经历了从 `unsigned` 到 `signed` 的转换。
所以在这个特定情况下:
signed s = INT_MAX;
unsigned u = 1;
s += u;
`s` 的值转换为 `unsigned` 并添加了 1,结果是 `INT_MAX + 1` 的无符号值。然后将此值转换为 `signed`,由于该值超出范围,根据第6.3.1.3p3节,会发生一个实现定义的转换:
> *1* 当具有整数类型的值转换为另一整数类型而不是 _Bool 时,如果该值可以由新类型表示,它将保持不变。
>
> *2* 否则,如果新类型是无符号的,则通过重复添加或减去一个超出新类型表示范围的最大值加一的值,直到该值在新类型的范围内,进行转换。
>
> *3* **否则,新类型是有符号的,而值无法表示在其中;结果要么是实现定义的,要么引发实现定义的信号。**
因此,上述代码没有未定义的行为,但具有实现定义的行为。
<details>
<summary>英文:</summary>
This:
s += u;
Is the same as this:
s = s + u;
As per section 6.5.16.2p3 of the [C standard](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf):
> A compound assignment of the form `E1 op = E2` is equivalent to the
> simple assignment expression `E1 = E1 op (E2)`, except that the lvalue
> `E1` is evaluated only once, and with respect to an
> indeterminately-sequenced function call, the operation of a compound
> assignment is a single evaluation
So first `s + u` is evaluated. This causes `s` to be converted to type `unsigned` as per the usual arithmetic conversions, and the result is unsigned. Then this result is assigned back to `s` which undergoes a conversion from `unsigned` to `signed`.
So in this particular case:
signed s = INT_MAX;
unsigned u = 1;
s += u;
The value of `s` is converted to `unsigned` and 1 is added to it, resulting in an unsigned value of `INT_MAX + 1`. This value is then converted to `signed`, which undergoes an implementation defined conversion due to the value being out of range as per section 6.3.1.3p3:
> *1* When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new
> type, it is unchanged.
>
> *2* Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that
> can be represented in the new type until the value is in the range of
> the new type.
>
> *3* **Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an
> implementation-defined signal is raised.**
So the above does not have undefined behavior, but it does have implementation defined behavior.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论