同时转换 bitwidth 和 signed/unsigned,哪个转换先执行?
Casting both bitwidth and signed/unsigned, which conversion is executed first?
考虑以下代码:
int32_t x = -2;
cout << uint64_t(x) << endl;
第二行中的转换基本上包含两个原子步骤。位宽从 32 位增加到 64 位,解释从有符号变为无符号。如果用 g++ 编译并执行,则得到 18446744073709551614。这表明首先处理位宽的增加(作为带符号的扩展),然后更改 signed/unsigned 解释,即上面的代码等同于编写:
int32_t x = -2;
cout << uint64_t(int64_t(x)) << endl;
让我感到困惑的是,也可以先将 x 解释为无符号的 32 位位向量,然后将其零扩展为 64 位,即
int32_t x = -2;
cout << uint64_t(uint32_t(x)) << endl;
这将产生 4294967294。有人可以确认 g++ 的行为是标准所要求的并且没有定义实现吗?如果您能向我推荐标准中实际涉及手头问题的规范,我将非常兴奋。我也尝试过,但惨遭失败。
提前致谢!
您正在查找标准第 4.7 节。特别是,第 2 段说:
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type).
在给定的示例中,我们有 18446744073709551614 = -2 mod 264.
正如@aschepler 所说,标准 4.7 §2( 整数转换 )确保结果将是 与源一致的最小无符号整数
整数(模 2n,其中 n 是用于表示无符号类型的位数)
所以在你的情况下,它将是 0xFFFFFFFFFFFFFFFE == 18446744073709551614
但这是标准规定的一步转换(编译器实际做的超出范围)
如果您想先无符号转换为 uint32_t,然后再转换为 uint64_t,您必须指定 2 个转换:static_cast<uint64_t>(static_cast<uint32_t>(-2))
根据 4.7 §2,首先将给出 0xFFFFFFFE = 4294967294,但由于此数字已经是有效的 uint64_t,因此第二次转换时未更改。
您所观察到的是标准所要求的,并且在任何符合标准的编译器上都可以观察到(前提是定义了 uint32_t
和 uint64_t
,因为 这部分 不需要...)
这是一个老问题,但我最近遇到了这个问题。我正在使用 char
,它恰好在我的计算机中签名。我想将两个值乘以
char a, b;
uint16 ans = uint16(a) * uint16(b);
但是,因为转换,当a < 0
时,答案是错误的。
由于char的符号是implementation-dependent,也许我们应该尽可能使用uint8
而不是char
。
考虑以下代码:
int32_t x = -2;
cout << uint64_t(x) << endl;
第二行中的转换基本上包含两个原子步骤。位宽从 32 位增加到 64 位,解释从有符号变为无符号。如果用 g++ 编译并执行,则得到 18446744073709551614。这表明首先处理位宽的增加(作为带符号的扩展),然后更改 signed/unsigned 解释,即上面的代码等同于编写:
int32_t x = -2;
cout << uint64_t(int64_t(x)) << endl;
让我感到困惑的是,也可以先将 x 解释为无符号的 32 位位向量,然后将其零扩展为 64 位,即
int32_t x = -2;
cout << uint64_t(uint32_t(x)) << endl;
这将产生 4294967294。有人可以确认 g++ 的行为是标准所要求的并且没有定义实现吗?如果您能向我推荐标准中实际涉及手头问题的规范,我将非常兴奋。我也尝试过,但惨遭失败。
提前致谢!
您正在查找标准第 4.7 节。特别是,第 2 段说:
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type).
在给定的示例中,我们有 18446744073709551614 = -2 mod 264.
正如@aschepler 所说,标准 4.7 §2( 整数转换 )确保结果将是 与源一致的最小无符号整数 整数(模 2n,其中 n 是用于表示无符号类型的位数)
所以在你的情况下,它将是 0xFFFFFFFFFFFFFFFE == 18446744073709551614
但这是标准规定的一步转换(编译器实际做的超出范围)
如果您想先无符号转换为 uint32_t,然后再转换为 uint64_t,您必须指定 2 个转换:static_cast<uint64_t>(static_cast<uint32_t>(-2))
根据 4.7 §2,首先将给出 0xFFFFFFFE = 4294967294,但由于此数字已经是有效的 uint64_t,因此第二次转换时未更改。
您所观察到的是标准所要求的,并且在任何符合标准的编译器上都可以观察到(前提是定义了 uint32_t
和 uint64_t
,因为 这部分 不需要...)
这是一个老问题,但我最近遇到了这个问题。我正在使用 char
,它恰好在我的计算机中签名。我想将两个值乘以
char a, b;
uint16 ans = uint16(a) * uint16(b);
但是,因为转换,当a < 0
时,答案是错误的。
由于char的符号是implementation-dependent,也许我们应该尽可能使用uint8
而不是char
。