将uint32_t转换为int32_t,不会有溢出或过度复杂的风险

Dem*_*emi 8 c++ undefined-behavior

我怎样才能最好地转换uint32_tint32_t快速地与包装,在C++?

一些尝试:

uint32_t y = UINT32_MAX;
int32_t x = (int32_t)y; // UB on overflow
int32_t x = *(int32_t*)&y; // does this violate strict aliasing?
Run Code Online (Sandbox Code Playgroud)

M.M*_*M.M 7

int32_t x = (int32_t)y;不是溢出而不是UB. 溢出是指算术运算产生超出可表示值范围的结果.但是,转换不是算术运算.

这种情况是实现定义的行为.我所知道的所有实现都将行为定义为不对表示进行任何更改.

请注意,此处不需要演员表.你可以写int32_t x = y;.实际上,这更简单,并将始终有效.如此多的代码依赖于此,没有供应商会定义任何其他行为(并不是他们有任何理由这样做).


int32_t x = *(int32_t*)&y不是UB.它不违反严格别名,因为允许类型的签名版本为无符号版本设置别名.这个代码保证产生int32_t与相应的相同的表示uint32_t(即"包装",因为这些类型保证是2的补码).


a3f*_*a3f 5

union { 
  int32_t i; 
  uint32_t u;
} u;
u.i = ...;
printf("%" PRIu32 "\n", u.u);
Run Code Online (Sandbox Code Playgroud)

memcpy(&uint_var, &int_var, sizeof uint_var)是在不调用未定义行为的情况下进行此类转换的两种标准方法.

也可以看看:

  • 我会坚持纠正.根据C99,7.18.1.1,`int32_t`保证是2的补码,并且与7.18.2.1一起,不能有陷阱表示.谢谢你的启发. (2认同)
  • 在C++中,读取union的成员与写入的最后一个成员不同是未定义的行为.(这个问题最初是双重标记的,但实际上是一个C++问题) (2认同)