【问题标题】:Narrowing conversions in C++11: what is the "actual value after conversion"?C++11 中的缩小转换:什么是“转换后的实际值”?
【发布时间】:2014-03-12 06:51:40
【问题描述】:

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

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

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

众所周知,列表初始化是不允许窄化转换的,在标准对窄化转换的定义中,我们有:

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

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

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

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

【问题讨论】:

  • 我认为问题在于0xaabb 可以被认为是一个“正”常量,但是当分配给int16_t 时,它变成了一个负数。嗯,我刚刚回复了一个不再在这里的评论,但我会留下这个,因为它可能会澄清问题。
  • 您能否改进标题,以便在问题列表中将此问题与其他问题区分开来?
  • 根据经验,它应该是合法的,因为 GCC 会发出警告(因此编译器明显意识到了这个问题),但它不会发出错误。如果它确实是非法的,编译应该会因错误(而不是警告)而中断。
  • @Damon:你的结论不符合。该标准不要求编译器在遇到非法代码时停止编译。所需要的只是诊断出错误,并发出警告。 GCC 上-pedantic-errors 的目的是将此类警告提升为错误。
  • @Damon 标准中没有这样的要求,GCC(就像其他编译器一样)在设计上接受了一些在标准 C++ 中无效的东西,只有一个警告。

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


【解决方案1】:

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

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

注意:问题的状态 DRWP 表示官方尚未更改标准,并且可以提出至少您的 int64_t 示例在 C++11 中是合法的。不过,编译器已经实施了新规则,因为这已经是原始措辞的预期含义。

【讨论】:

  • 非常感谢您提供的信息。我仍然不清楚“will fit into”和“can be represented in”之间的区别。如果它们的意思相同,那么int64_t 示例应该是缩小转换范围。如果它们不一样,那么确切的区别是什么?
  • @goodbyeera 除非我读错了,否则它们的意思是一样的,所以int16_tint64_t 的例子都是基于新措辞的缩小转换。
【解决方案2】:

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

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

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

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

结论:视情况而定。在具有 32 位 int 和 64 位 long long 的典型当前平台上,第一个会变窄,而第二​​个不会。 GCC 同意,并使用-pedantic 对第一个发出警告。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多