缩小C ++ 11中的转换:“转换后的实际值”是什么?

时间:2014-02-13 11:52:49

标签: c++ c++11 language-lawyer

以下代码在C ++ 11中是否合法?

int16_t x {0xaabb};
int64_t xxxx {0xaaaabbbbccccdddd};

代码来自“The C ++ Programming Language”第4版(第150页)。

我们知道,列表初始化不允许缩小转换,在标准的缩小转换定义中,我们有:

  

缩小转换是隐式转换    - [...]
   - 从整数类型或未范围的枚举类型到不能表示原始类型的所有值的整数类型,除非源是常量表达式,并且转换后的实际值将适合目标类型并将生成原始值转换回原始类型时。

检查缩小转换样本代码的规则,我证明示例代码是非法的,因为0xaabb0xaaaabbbbccccdddd无法分别在int16_tint64_t中表示。这是对的吗?

但我不太明白措辞“除了源是一个常量表达式而转换后的实际值将适合目标类型并且在转换回原来的值时会生成原始值原始类型“。我想知道在什么情况下转换后的实际值不能适合目标类型。由于整数类型之间的转换始终有效(尽管在目标类型已签名并且源值无法在目标类型中表示的情况下实现定义,但无论如何它都不是未定义的行为),“值是否始终为真”转换后 符合目标类型“?从这个角度来看,我开始质疑我对示例代码缩小转换的判断。如果是这种情况,为什么标准在某种情况下总是如此?为什么不说“除了源是常量表达式之外,转换后的实际值在转换回原始类型时会产生原始值”?

有人可以帮我澄清一下吗?谢谢!

2 个答案:

答案 0 :(得分:5)

这是标准中的缺陷,请参阅CWG issue 1449。该文本已更改为

  

从整数类型或未范围的枚举类型到不能表示原始类型的所有值的整数类型,除非源是一个常量表达式,其整数提升后的值将适合目标类型

注意:问题的状态DRWP意味着正式,标准尚未更改,并且可以提出一个论点,即至少您的int64_t示例在C ++ 11中是合法的。然而,编译器已经实现了新规则,因为这已经是原始措辞的预期含义。

答案 1 :(得分:0)

让我们看一下如何将值转换为有符号整数:

  

4.7 / 3如果目标类型是有符号的,如果它可以用目标类型(和位域宽度)表示,则该值不变;否则,该值是实现定义的

因此,这些转换会提供实现定义的值。一个明智的实现将定义转换,为该位模式提供相应的负值,该值适合目标类型。

所以问题是,转换回文字的类型是否保留了值?这取决于文本类型的实现定义大小。如果int恰好有16位,则第一个将保留该值,但如果它更大则不会保留该值(在这种情况下0xaabb将被签名,并且转换将给出负值)。同样,如果int恰好有64位,或者int更小且long long正好有64位,则第二个将保留该值。

结论:这取决于。在具有32位int和64位long long的典型当前平台上,第一个将缩小而第二个不会缩小。 GCC同意,并使用-pedantic向第一个发出警告。