C++ 中的 Sign Extension 是编译器选项,还是依赖于编译器或依赖于目标?
Is Sign Extension in C++ a compiler option, or compiler dependent or target dependent?
以下代码已在 3 个不同的编译器和 3 个不同的处理器上编译并给出了 2 个不同的结果:
typedef unsigned long int u32;
typedef signed long long s64;
int main ()
{ u32 Operand1,Operand2;
s64 Result;
Operand1=95;
Operand2=100;
Result= (s64)(Operand1-Operand2);}
结果产生 2 个结果:
任何一个
-5
或 4294967291
我明白 (Operand1-Operand2)
的操作是在 32 位无符号计算中完成的,然后当转换为 s64
符号扩展在第一种情况下正确完成但没有正确完成第二种情况。
我的问题是符号扩展是否可以通过编译器选项来控制,或者它依赖于编译器或者它可能依赖于目标。
符号扩展依赖于平台,其中平台是编译器、目标硬件体系结构和操作系统的组合。
此外,正如 Paul R 提到的,内置类型的宽度(如 unsigned long
)也取决于平台。使用 <cstdint>
中的类型来获取固定宽度的类型。尽管如此,它们只是依赖于平台的定义,因此它们的符号扩展行为仍然取决于平台。
Here is a good almost-duplicate question about type sizes. And here 很好 table 关于字体大小的关系。
您的问题是您假设 unsigned long int
是 32 位宽而 signed long long
是 64 位宽。 这个假设是错误的。
We can visualize what's going on by using types that have a guaranteed (by the standard) bit width:
int main() {
{
uint32_t large = 100, small = 95;
int64_t result = (small - large);
std::cout << "32 and 64 bits: " << result << std::endl;
} // 4294967291
{
uint32_t large = 100, small = 95;
int32_t result = (small - large);
std::cout << "32 and 32 bits: " << result << std::endl;
} // -5
{
uint64_t large = 100, small = 95;
int64_t result = (small - large);
std::cout << "64 and 64 bits: " << result << std::endl;
} // -5
return 0;
}
在这三种情况中的每一种情况下,表达式 small - large
都会产生 unsigned 整数类型(根据宽度)的结果。这个结果是用模运算计算出来的。
在第一种情况下,因为无符号结果可以存储在更宽的有符号整数中,所以不执行值的转换。
在其他情况下,结果不能存储在有符号整数中。因此执行了实现定义的转换,这通常意味着将无符号值的位模式解释为有符号值。因为结果是 "large",最高位将被设置,当被视为有符号值时(在二进制补码下)相当于 "small" 负值。
突出 Lưu Vĩnh Phúc 的评论:
Operand1-Operand2
is unsigned therefore when casting to s64 it's always zero extension. [..]
符号扩展只在第一种情况下进行,因为只有在这种情况下才有扩大转换,而且确实总是零扩展。
引自 the standard,强调我的。关于small - large
:
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2^n$
where n is the number of bits used to represent the unsigned type). [..]
§ 4.7/2
关于从无符号到有符号的转换:
If the destination type [of the integral conversion] is signed, the value is unchanged if it can be represented in the destination type; otherwise, the value is implementation-defined.
§ 4.7/3
类型提升,相应的符号扩展由C++语言指定。
没有指定但与平台相关的是所提供的整数类型的范围。它甚至符合标准,char
、short int
、int
、long int
和 long long int
都具有相同的范围,前提是该范围满足 C++ 标准要求对于 long long int
。在这样的平台上,不会发生扩大或缩小,但有符号<->无符号转换仍然可以改变值。
以下代码已在 3 个不同的编译器和 3 个不同的处理器上编译并给出了 2 个不同的结果:
typedef unsigned long int u32;
typedef signed long long s64;
int main ()
{ u32 Operand1,Operand2;
s64 Result;
Operand1=95;
Operand2=100;
Result= (s64)(Operand1-Operand2);}
结果产生 2 个结果:
任何一个
-5
或 4294967291
我明白 (Operand1-Operand2)
的操作是在 32 位无符号计算中完成的,然后当转换为 s64
符号扩展在第一种情况下正确完成但没有正确完成第二种情况。
我的问题是符号扩展是否可以通过编译器选项来控制,或者它依赖于编译器或者它可能依赖于目标。
符号扩展依赖于平台,其中平台是编译器、目标硬件体系结构和操作系统的组合。
此外,正如 Paul R 提到的,内置类型的宽度(如 unsigned long
)也取决于平台。使用 <cstdint>
中的类型来获取固定宽度的类型。尽管如此,它们只是依赖于平台的定义,因此它们的符号扩展行为仍然取决于平台。
Here is a good almost-duplicate question about type sizes. And here 很好 table 关于字体大小的关系。
您的问题是您假设 unsigned long int
是 32 位宽而 signed long long
是 64 位宽。 这个假设是错误的。
We can visualize what's going on by using types that have a guaranteed (by the standard) bit width:
int main() {
{
uint32_t large = 100, small = 95;
int64_t result = (small - large);
std::cout << "32 and 64 bits: " << result << std::endl;
} // 4294967291
{
uint32_t large = 100, small = 95;
int32_t result = (small - large);
std::cout << "32 and 32 bits: " << result << std::endl;
} // -5
{
uint64_t large = 100, small = 95;
int64_t result = (small - large);
std::cout << "64 and 64 bits: " << result << std::endl;
} // -5
return 0;
}
在这三种情况中的每一种情况下,表达式 small - large
都会产生 unsigned 整数类型(根据宽度)的结果。这个结果是用模运算计算出来的。
在第一种情况下,因为无符号结果可以存储在更宽的有符号整数中,所以不执行值的转换。
在其他情况下,结果不能存储在有符号整数中。因此执行了实现定义的转换,这通常意味着将无符号值的位模式解释为有符号值。因为结果是 "large",最高位将被设置,当被视为有符号值时(在二进制补码下)相当于 "small" 负值。
突出 Lưu Vĩnh Phúc 的评论:
Operand1-Operand2
is unsigned therefore when casting to s64 it's always zero extension. [..]
符号扩展只在第一种情况下进行,因为只有在这种情况下才有扩大转换,而且确实总是零扩展。
引自 the standard,强调我的。关于small - large
:
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo
2^n$
where n is the number of bits used to represent the unsigned type). [..]§ 4.7/2
关于从无符号到有符号的转换:
If the destination type [of the integral conversion] is signed, the value is unchanged if it can be represented in the destination type; otherwise, the value is implementation-defined.
§ 4.7/3
类型提升,相应的符号扩展由C++语言指定。
没有指定但与平台相关的是所提供的整数类型的范围。它甚至符合标准,char
、short int
、int
、long int
和 long long int
都具有相同的范围,前提是该范围满足 C++ 标准要求对于 long long int
。在这样的平台上,不会发生扩大或缩小,但有符号<->无符号转换仍然可以改变值。