x ^= x & -x;其中 x 是一个无符号整数调用 UB?

Does x ^= x & -x; where x is an unsigned integer invoke UB?

由于 - 运算符应用于 xunsigned,此函数是否会调用未定义的行为?我搜索了标准,但找不到解释。

unsigned foo(unsigned x)
{
    return x ^= x & -x;
}

海事组织是的。

编辑
void func(unsigned x) 
{
    printf("%x", -x);
}

int main(void)
{
    func(INT_MIN);
}

IMO 唯一的解释是它被提升为更大的有符号整数大小然后转换为无符号整数。

如果提升为更大的整数大小,如果没有更大的有符号整数类型会怎样?

此表达式的行为已明确定义。

类似于 x = x + 1 的构造是允许的,因为 x 在计算所有其他子表达式之前不会被赋值。这同样适用于这种情况。

-x 也没有问题,因为表达式具有无符号类型,因此具有明确定义的环绕行为,而不是溢出。

关于一元 - 运算符的 C standard 第 6.5.3.3p3 节指出:

The result of the unary - operator is the negative of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type.

因此,由于没有发生提升,因此在整个表达式中类型保持 unsigned。尽管标准中没有明确说明,-x 实际上与 0 - x.

相同

对于传递给此函数的 INT_MIN 的特定情况,它的类型为 int 并且在 unsigned 的范围之外,因此在传递给功能。这导致有符号值 -2,147,483,648 被转换为无符号值 2,147,483,648(在二进制补码中恰好具有相同的表示形式,即 0x80000000)。然后当 -x 被评估时,它环绕产生 2,147,483,648.

6.2.5 Types
...
9 The range of nonnegative values of a signed integer type is a subrange of the corresponding unsigned integer type, and the representation of the same value in each type is the same.41) A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.
41) The same representation and alignment requirements are meant to imply interchangeability as arguments to functions, return values from functions, and members of unions.
...
6.3 Conversions
...
6.3.1.3 Signed and unsigned integers

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.60)

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.
60) The rules describe arithmetic on the mathematical value, not the value of a given type of expression
...
6.3.1.8 Usual arithmetic conversions
...
Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.

简而言之 - -x 不会导致未定义的行为。表达式的结果仍然是无符号的,它只是映射到一个明确定义的非负值。