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