8

此表达式可在标准 (N3797) §8.5.4/7 中的示例中找到

unsigned int ui1 = {-1}; // error: narrows

鉴于§8.5.4/7 及其第 4 个要点:

缩小转换是一种隐式转换:

  • 从整数类型或无作用域枚举类型到不能表示原始类型的所有值的整数类型,除非源是常量表达式,其值在整数提升后将适合目标类型。

我想说这里没有缩小范围,因为 -1 是一个常量表达式,它在积分提升后的值适合一个无符号整数。

另请参阅关于Integral Promotion的 §4.5/1 :

如果 int 可以表示源类型的所有值,则可以将除 bool、char16_t、char32_t 或 wchar_t 的整数转换等级 (4.13) 小于 int 等级的整数类型的纯右值转换为 int 类型的纯右值; 否则,可以将源纯右值转换为 unsigned int 类型的纯右值。

从 4.13 开始,我们得到 -1(一个 int)的秩等于一个 unsigned int 的秩,因此它可以转换为一个 unsigned int。

编辑

不幸的是, Jerry Coffin从这个帖子中删除了他的答案。我相信他走在正确的轨道上,如果我们接受这样一个事实,即在标准发生这种变化之后,目前对第 8.5.4/7 节第 4 条要点的解读是错误的。

4

3 回答 3

7

int从到没有积分提升unsigned int,因此它仍然是不正确的。

那将是一个完整的转换

于 2014-01-20T19:07:28.857 回答
1

窄化是从整数类型到整数类型的隐式转换,不能表示原始类型的所有值

当然,从整数类型int到整数类型unsigned int的转换不能代表原始类型的所有值——这里的标准是非常明确的。如果你真的需要它,你可以做

 unsigned int ui1 = {-1u};

这可以在没有任何错误/警告的情况下工作,因为1u它是一个类型的文字,unsigned int然后被否定。这在标准状态中被明确定义为[expr.unary.op] :

无符号量的负数是通过从 2 n中减去其值来计算的,其中 n 是提升的操作数中的位数。

-1然而是int否定的前后,因此它变成了一个狭窄的转换。没有否定文字;有关详细信息,请参阅此答案

提升是,非正式地,将相同的值复制到更大的空间中,所以这里不应该混淆,因为 (ofsignedunsigned) 的大小是相等的。即使您尝试将其转换为某种更大的尺寸,unsigned long long也可以说它仍然是一种缩小转换,因为它不能真正代表负数。

于 2014-01-20T19:12:55.660 回答
1

标准措辞的更改旨在确认将负值转换为无符号类型是并且一直是缩小转换的理解。

非正式地,-1 不能在任何无符号类型的范围内表示,并且表示它的位模式如果存储在无符号 int 中也不表示相同的值。因此,这是一个缩小转换,不涉及提升/扩大。

这是关于阅读标准的精致艺术。像往常一样,编译器最清楚。

于 2014-01-21T14:03:42.903 回答