C x^=x&-x;其中x是无符号整数?
由于C x^=x&-x;其中x是无符号整数?,c,language-lawyer,C,Language Lawyer,由于-运算符被应用于x而未签名,此函数是否会调用未定义的行为?我查了一下标准,找不到解释 unsigned foo(unsigned x) { return x ^= x & -x; } 是的 编辑 IMO唯一的解释是,它被提升为较大的有符号整数大小,然后转换为无符号整数 如果它被提升为更大的整数大小,如果没有更大的有符号整数类型会发生什么?此表达式的行为定义良好 允许使用类似于x=x+1的构造,因为在计算所有其他子表达式之前,x不会被赋值。在这种情况下也是如此 -x也没有问题
-
运算符被应用于x
而未签名,此函数是否会调用未定义的行为?我查了一下标准,找不到解释
unsigned foo(unsigned x)
{
return x ^= x & -x;
}
是的
编辑
IMO唯一的解释是,它被提升为较大的有符号整数大小,然后转换为无符号整数
如果它被提升为更大的整数大小,如果没有更大的有符号整数类型会发生什么?此表达式的行为定义良好
允许使用类似于x=x+1
的构造,因为在计算所有其他子表达式之前,x
不会被赋值。在这种情况下也是如此
-x
也没有问题,因为表达式具有无符号类型,因此具有定义良好的环绕行为,而不是溢出行为
第6.5.3.3p3节关于一元-
运算符的规定:
一元-
运算符的结果是其(提升的)操作数的负数。对操作数执行整数提升,结果具有提升类型
因此,由于未发生升级,因此类型在整个表达式中保持无符号。尽管标准中没有明确规定,-x
实际上与0-x
相同
对于将INT\u MIN
传递到此函数的特定情况,它的类型为INT
,并且超出了无符号的范围,因此在传递到此函数时会进行转换。这将导致有符号值2147483648转换为无符号值2147483648(在两个补码中恰好具有相同的表示形式,即0x8000000)。然后,当计算-x
时,它会环绕,结果是2147483648
6.2.5类型
…
9有符号整数类型的非负值范围是
对应的无符号整数类型,以及每个类型中相同值的表示形式
类型相同。41)涉及无符号操作数的计算永远不会溢出,
因为无法由结果无符号整数类型表示的结果是
约化模:比可计算的最大值大一的数
由结果类型表示。
41)相同的表示和对齐要求意味着互换性
函数的参数、函数的返回值和联合的成员。
…
6.3转换
…
6.3.1.3有符号和无符号整数
1当整数类型的值转换为除\u Bool
以外的其他整数类型时,如果
该值可以用新类型表示,但没有更改。
2否则,如果新类型是无符号的,则通过反复添加或
比新类型中可以表示的最大值多减去一个
直到值在新类型的范围内。60)
3否则,新类型已签名,且无法在其中表示值;要么
结果是定义了实现或发出了定义了实现的信号。
60)规则描述的是基于数学值的算术运算,而不是给定类型表达式的值
…
6.3.1.8常用算术转换
…
否则,如果具有无符号整数类型的操作数的秩大于或等于
等于另一个操作数类型的秩,然后具有
有符号整数类型转换为无符号的操作数类型
整数类型。
简而言之,-x
不会导致未定义的行为。表达式的结果仍然是无符号的,它只是映射到定义良好的非负值。注释不用于扩展讨论;这段对话已经结束。我100%不相信,特别是对于我问题中的最后一个案例。无论如何,谢谢你。顺便说一句,这是我的个人记录-8
。仍然可以理解为什么它被如此频繁地DV-ted。@P_ujsupports会导致没有升级,因为INT\u MIN
具有类型INT
,并且将其传递给函数会导致转换为无符号INT
。
void func(unsigned x)
{
printf("%x", -x);
}
int main(void)
{
func(INT_MIN);
}