面试中有人问我这个问题,我真的不明白这里发生了什么。问题是“控制台中将显示什么?”
#include <iostream>
int main()
{
unsigned long long n = 0;
((char*)&n)[sizeof(unsigned long long)-1] = 0xFF;
n >>= 7*8;
std::cout << n;
}
Run Code Online (Sandbox Code Playgroud)
这是怎么回事,一步一步?
bol*_*lov 83
让我们一次完成这一步骤:
((char*)&n)
Run Code Online (Sandbox Code Playgroud)
这会将变量的地址n从转换unsigned long long*为char*。这是合法的,实际上通过char指针访问不同类型的对象是该语言接受的少数“类型调整”情况之一。实际上,这使您可以将对象的内存n作为字节数组来访问(char在C ++中为aka )
((char*)&n)[sizeof(unsigned long long)-1]
Run Code Online (Sandbox Code Playgroud)
您访问对象的最后一个字节n。切记sizeof以字节为单位返回数据类型的维数(在C ++中char具有字节的更改自我)
((char*)&n)[sizeof(unsigned long long)-1] = 0xFF;
Run Code Online (Sandbox Code Playgroud)
您可以设置的最后一个字节n的值0xFF。
由于n是0最初的布局内存n现在是:
00 .. 00 FF
Run Code Online (Sandbox Code Playgroud)
现在注意...我放在中间。这不是因为我懒于复制粘贴字节数所n具有的值,而是因为unsigned long long标准未将大小设置为固定尺寸。有一些限制,但具体实现因实施而异。因此,这是第一个“未知”。但是,在大多数现代体系结构上,它sizeof (unsigned long long)是8,因此我们将继续讨论这个问题,但是在认真的采访中,您应该提到这一点。
另一个“未知”是如何解释这些字节。无符号整数只是简单地以二进制编码。但这可以是小端或大端。x86的字节序不大,因此我们以它为例进行说明。再一次,在认真的采访中,您应该提到这一点。
n >>= 7*8;
Run Code Online (Sandbox Code Playgroud)
该右移值n56次。注意,现在我们谈论的是的值n,而不是内存中的字节。与我们的假设(大小8,小端排序)的存储器中的编码的值被0xFF000000 00000000如此移位它7*8倍将导致值0xFF是255。
因此,假设sizeof(unsigned long long)是,8并且使用一点字节序编码的程序将打印255到控制台。
如果我们谈论的是大端系统,则将最后一个字节设置为后的内存布局0xff仍然相同:00 ... 00 FF,但是现在编码的值为0xFF。因此,结果n >>= 7*8;将为0。在大端系统中,程序将打印0到控制台。
如评论中所指出的,还有其他假设:
char是8位。尽管sizeof(char)可以保证为1,但不必具有8位。我所知道的所有现代系统都有以8位字节分组的位。
整数不必大或小端。可能还有其他排列方式,例如中端排列。如今,除了大尾数之外,其他东西都被认为是深奥的。