C/C++ casting在底层有什么作用?
C/C++ What does casting do in the low level?
有人告诉我类型转换 C 转换只会改变系统解释信息的方式(例如,将 char
'A'
转换为 int
return 65
当使用 cout
打印它时,因为在
记忆它保持为 01000001
).
但是,我注意到,当将浮点数转换为相同宽度的整数时,该值是守恒的并且没有改变,就像仅改变解释一样。
例如,设 X
为双精度浮点数:
double X = 3.14159;
就我现在而言,在检查 &X
时我们会发现(由 decimal to binary converter 转换):
01000000 00001001 00100001 11111001 11110000 00011011 10000110 01101110
但是,正如你们中的一些人已经知道的那样,在执行以下操作时:
long long Y = (long long)X;
Y
将是 3
,X
的截断版本,而不是 4614256650576692846
,它在查看 [= 处的二进制值时将获得的值21=] 如果寻找 long long
.
所以,我认为很明显他们错了,但是,转换在低级别是如何工作的?是否检测到该值是否会更改?您将如何编码以获得 Y = 4614256650576692846
而不是 Y = 3
?
转换将尝试尽可能精确地保留值。
您可以使用 memcpy()
复制位模式。
#include <iostream>
#include <cstring>
int main() {
double X = 3.14159;
long long Y;
memcpy(&Y, &X, sizeof(Y));
std::cout << Y << '\n';
return 0;
}
如果你想得到Y = 4614256650576692846
,你可以使用:
double X = 3.14159;
long long Y = *( (long long*)(&X) );
这会将一个双指针转换为一个 long long 指针,然后编译器认为 (long long*)(&X)
是一个 long long 存储的地方。
但我不建议您这样做,因为结果取决于 double
在您的机器上的存储方式,并且不能保证结果是 4614256650576692846。
转换让编译器决定如何更改数据,以便它在尊重请求的数据类型的同时尽可能有用。
int
到 char
的转换只是将解释从 65
更改为 'A'
。
但是,当我们有一个可能想要保存的值时,编译器将使用特殊指令进行转换。
例如,当从 double
转换为 long long
时,处理器将使用 CVTTSD2SI
指令,该指令将 FP 寄存器的值加载并截断为通用值:
double a = 3.14159;
long long b = (long long)a;
将进行反汇编(为了便于理解,我去掉了堆栈指针):
movsd xmm0, QWORD PTR [a]
cvttsd2si rax, xmm0
mov QWORD PTR [b], rax
因此,使用原始值的方法将如所选答案中所述:取消对 double
的指针的引用并将其放入 long long
变量中,或者如其他所述,使用 memcpy().
有人告诉我类型转换 C 转换只会改变系统解释信息的方式(例如,将 char
'A'
转换为 int
return 65
当使用 cout
打印它时,因为在
记忆它保持为 01000001
).
但是,我注意到,当将浮点数转换为相同宽度的整数时,该值是守恒的并且没有改变,就像仅改变解释一样。
例如,设 X
为双精度浮点数:
double X = 3.14159;
就我现在而言,在检查 &X
时我们会发现(由 decimal to binary converter 转换):
01000000 00001001 00100001 11111001 11110000 00011011 10000110 01101110
但是,正如你们中的一些人已经知道的那样,在执行以下操作时:
long long Y = (long long)X;
Y
将是 3
,X
的截断版本,而不是 4614256650576692846
,它在查看 [= 处的二进制值时将获得的值21=] 如果寻找 long long
.
所以,我认为很明显他们错了,但是,转换在低级别是如何工作的?是否检测到该值是否会更改?您将如何编码以获得 Y = 4614256650576692846
而不是 Y = 3
?
转换将尝试尽可能精确地保留值。
您可以使用 memcpy()
复制位模式。
#include <iostream>
#include <cstring>
int main() {
double X = 3.14159;
long long Y;
memcpy(&Y, &X, sizeof(Y));
std::cout << Y << '\n';
return 0;
}
如果你想得到Y = 4614256650576692846
,你可以使用:
double X = 3.14159;
long long Y = *( (long long*)(&X) );
这会将一个双指针转换为一个 long long 指针,然后编译器认为 (long long*)(&X)
是一个 long long 存储的地方。
但我不建议您这样做,因为结果取决于 double
在您的机器上的存储方式,并且不能保证结果是 4614256650576692846。
转换让编译器决定如何更改数据,以便它在尊重请求的数据类型的同时尽可能有用。
int
到 char
的转换只是将解释从 65
更改为 'A'
。
但是,当我们有一个可能想要保存的值时,编译器将使用特殊指令进行转换。
例如,当从 double
转换为 long long
时,处理器将使用 CVTTSD2SI
指令,该指令将 FP 寄存器的值加载并截断为通用值:
double a = 3.14159;
long long b = (long long)a;
将进行反汇编(为了便于理解,我去掉了堆栈指针):
movsd xmm0, QWORD PTR [a]
cvttsd2si rax, xmm0
mov QWORD PTR [b], rax
因此,使用原始值的方法将如所选答案中所述:取消对 double
的指针的引用并将其放入 long long
变量中,或者如其他所述,使用 memcpy().