如何使用C ++快速将uint32_t
转换为int32_t
?
有些尝试:
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?
答案 0 :(得分:5)
union {
int32_t i;
uint32_t u;
} u;
u.i = ...;
printf("%" PRIu32 "\n", u.u);
这和memcpy(&uint_var, &int_var, sizeof uint_var)
是在不调用未定义行为的情况下进行此类转换的两种标准方法。
另见:
答案 1 :(得分:5)
int32_t x = (int32_t)y;
不是溢出而不是UB。 溢出是算术运算产生超出可表示值范围的结果的时间。但是,转换不是算术运算。
这种情况是实现定义的行为。我所知道的所有实现都将行为定义为不对表示进行任何更改。
请注意,此处不需要演员表。你可以写int32_t x = y;
。
实际上,这更简单,并将始终有效。如此多的代码依赖于此,没有供应商会定义任何其他行为(并不是他们有任何理由这样做)。
int32_t x = *(int32_t*)&y
不是UB。它不违反严格别名,因为允许类型的签名版本为无符号版本设置别名。保证此代码生成int32_t
,其表示形式与对应的uint32_t
相同(即"包装",因为这些类型保证是2'补码)。
答案 2 :(得分:1)
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
int makesigned(unsigned x) {
if (x <= (unsigned) INT_MAX) {
return (int) x;
}
/* assume 2's complement */
if (x >= (unsigned) INT_MIN) {
return 0 - (int)(-x);
}
abort();
return 0;
}
int main(void) {
assert(makesigned(0) == 0);
assert(makesigned(INT_MAX) == INT_MAX);
assert(makesigned(UINT_MAX) == -1);
assert(makesigned(INT_MIN) == INT_MIN);
return 0;
}