无符号整数会提升为有符号吗?表达式的类型是什么uint16_t-1 *uint16_t-1

问题描述

对于uint32_tuint64_t的结果是预期的,但是uint8_tuint16_t的促销却很奇怪。在c ++ 14 / c ++ 17,gcc和clang,64位linux,sizeof(int) == 4上进行测试。

#include <cstdint>    
using namespace std;

static_assert( uint8_t(-1)*uint8_t(-1) == 0xfe01);  // OK,but why not 1?
static_assert( uint8_t(-1)*uint8_t(-1) == 1);       // error: static assertion failed
static_assert( uint16_t(-1)*uint16_t(-1) == 1);     // error: static_assert expression is not an integral constant expression
static_assert( uint32_t(-1)*uint32_t(-1) == 1);     // OK
static_assert( uint64_t(-1)*uint64_t(-1) == 1);     // OK

在以下情况下,std::uint16_t是否被提升为int?

static_assert( uint16_t(-1)*uint16_t(-1) == uint16_t(uint16_t(-1)*uint16_t(-1)));

编译器消息为:

error: static_assert expression is not an integral constant expression
static_assert( uint16_t(-1)*uint16_t(-1) == uint16_t(uint16_t(-1)*uint16_t(-1)));

note: value 4294836225 is outside the range of representable values of type 'int'
static_assert( uint16_t(-1)*uint16_t(-1) == uint16_t(uint16_t(-1)*uint16_t(-1)));

更有趣的是,对于std::uint8_t的相同断言是正确的,但是失败

static_assert( uint8_t(-1)*uint8_t(-1) == uint8_t(uint8_t(-1)*uint8_t(-1)));  //error: static_assert failed
static_assert( uint8_t(-1)*uint8_t(-1) == 0xfe01);  // does not fail

因此,看起来uint8_t被提升为uint16_t,但是uint16_t被提升为 signed intuint32_t未被提升为uint64_t

任何人都可以告诉我为什么要进行这些促销活动,它是在标准中指定的,还是在不同的实现上可能有所不同?

解决方法

看起来uint8_t被提升为uint16_t,但是uint16_t被提升为signed int。 uint32_t未被提升为uint64_t

不,那是不正确的。仅将比int窄的类型提升为int,因此,如果int的位数超过16位,则uint8_tuint16_t都将提升为int。

对于uint8_t(-1)*uint8_t(-1),它等效于0xFF*0xFF,结果将为0xFE01

OTOH uint16_t(-1)*uint16_t(-1)0xFFFF*0xFFFF相同,结果为0xFFFE0001 = 4294836225,并且超出int的范围。和签名溢出是未定义的行为

,

无符号整数会提升为有符号吗?

取决于操作数的大小与int的大小有关。但是,是的,这很典型。

static_assert( uint8_t(-1)*uint8_t(-1) == 0xfe01);  // OK,but why not 1?

它不是1,因为uint8_t(-1)是255,而255 * 255是65025。在具有32位int的系统上,该值在可表示的值之内。

所以看起来uint8_t被提升为uint16_t

不。提升总是发生在int或更高等级的整数上。在uint8_t为16位的系统上,int可以提升为16位类型,但是由于uint8_t的所有值都可以用带符号的int表示,因此将是结果促销活动。

在不同的实现上可以有所不同吗?

在不同的语言实现中,可表示值的范围有所不同,这会影响升级后的类型。

是否在标准中指定

是的

您知道如何抑制升迁为带符号的int并将其提升为无符号的int吗?

否,无法更改促销。但是您可以将值显式转换为所需的类型,以便不进行升级。

,

算术运算符不接受小于int的类型作为参数。
对于较小的参数,将积分提升为int

这是结果不一致的原因:

  • 当乘以小于int的类型时,您将获得晋升,
  • 当乘以更大的类型时,您不会(如果它们相同)。

确切的规则太复杂了,无法总结而不会出错,但是在那些CppReference文章中对此进行了描述:

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...