long long 类型在内存中的表示
long long type representation in memory
我想从 8 字节类型中提取字节,例如 char func(long long number, size_t offset)
所以对于偏移量 n,我将得到第 n
个字节(0 <= n <= 7)。在这样做的同时,我意识到我不知道 8 字节变量在内存中的实际表示方式。我希望你能帮我弄清楚。
我首先写了一个简短的 python 脚本来在每个字节
中打印由 A
s(ascii 值 65)组成的数字
sumx = 0
for x in range(8):
sumx += (ord('A')*256**x)
print('x {} sumx {}'.format(x,sumx))
输出为
x 0 sumx 65
x 1 sumx 16705
x 2 sumx 4276545
x 3 sumx 1094795585
x 4 sumx 280267669825
x 5 sumx 71748523475265
x 6 sumx 18367622009667905
x 7 sumx 4702111234474983745
在我看来,每个数字都是一串 A
后跟 0。接下来我写了一个简短的 C++ 代码来提取第 n
个字节
#include <iostream>
#include <array>
char func0(long long number, size_t offset)
{
offset <<= 3;
return (number & (0x00000000000000FF << offset)) >> offset;
}
char func1(long long unsigned number, size_t offset)
{
char* ptr = (char*)&number;
return ptr[offset];
}
int main()
{
std::array<long long,8> arr{65,16705,4276545,1094795585,280267669825,71748523475265,18367622009667905,4702111234474983745};
for (int i = 0; i < arr.size(); i++)
for (int j = 0; j < sizeof(long long unsigned); j++)
std::cout << "char " << j << " in number " << i << " (" << arr[i] << ") func0 " << func0(arr[i], j) << " func1 " << func1(arr[i], j) << std::endl;
return 0;
}
这是程序输出(注意从第 5 个字节开始的区别)
~ # g++ -std=c++11 prog.cpp -o prog; ./prog
char 0 in number 0 (65) func0 A func1 A
char 1 in number 0 (65) func0 func1
char 2 in number 0 (65) func0 func1
char 3 in number 0 (65) func0 func1
char 4 in number 0 (65) func0 func1
char 5 in number 0 (65) func0 func1
char 6 in number 0 (65) func0 func1
char 7 in number 0 (65) func0 func1
char 0 in number 1 (16705) func0 A func1 A
char 1 in number 1 (16705) func0 A func1 A
char 2 in number 1 (16705) func0 func1
char 3 in number 1 (16705) func0 func1
char 4 in number 1 (16705) func0 func1
char 5 in number 1 (16705) func0 func1
char 6 in number 1 (16705) func0 func1
char 7 in number 1 (16705) func0 func1
char 0 in number 2 (4276545) func0 A func1 A
char 1 in number 2 (4276545) func0 A func1 A
char 2 in number 2 (4276545) func0 A func1 A
char 3 in number 2 (4276545) func0 func1
char 4 in number 2 (4276545) func0 func1
char 5 in number 2 (4276545) func0 func1
char 6 in number 2 (4276545) func0 func1
char 7 in number 2 (4276545) func0 func1
char 0 in number 3 (1094795585) func0 A func1 A
char 1 in number 3 (1094795585) func0 A func1 A
char 2 in number 3 (1094795585) func0 A func1 A
char 3 in number 3 (1094795585) func0 A func1 A
char 4 in number 3 (1094795585) func0 func1
char 5 in number 3 (1094795585) func0 func1
char 6 in number 3 (1094795585) func0 func1
char 7 in number 3 (1094795585) func0 func1
char 0 in number 4 (280267669825) func0 A func1 A
char 1 in number 4 (280267669825) func0 A func1 A
char 2 in number 4 (280267669825) func0 A func1 A
char 3 in number 4 (280267669825) func0 A func1 A
char 4 in number 4 (280267669825) func0 func1 A
char 5 in number 4 (280267669825) func0 func1
char 6 in number 4 (280267669825) func0 func1
char 7 in number 4 (280267669825) func0 func1
char 0 in number 5 (71748523475265) func0 A func1 A
char 1 in number 5 (71748523475265) func0 A func1 A
char 2 in number 5 (71748523475265) func0 A func1 A
char 3 in number 5 (71748523475265) func0 A func1 A
char 4 in number 5 (71748523475265) func0 func1 A
char 5 in number 5 (71748523475265) func0 func1 A
char 6 in number 5 (71748523475265) func0 func1
char 7 in number 5 (71748523475265) func0 func1
char 0 in number 6 (18367622009667905) func0 A func1 A
char 1 in number 6 (18367622009667905) func0 A func1 A
char 2 in number 6 (18367622009667905) func0 A func1 A
char 3 in number 6 (18367622009667905) func0 A func1 A
char 4 in number 6 (18367622009667905) func0 func1 A
char 5 in number 6 (18367622009667905) func0 func1 A
char 6 in number 6 (18367622009667905) func0 func1 A
char 7 in number 6 (18367622009667905) func0 func1
char 0 in number 7 (4702111234474983745) func0 A func1 A
char 1 in number 7 (4702111234474983745) func0 A func1 A
char 2 in number 7 (4702111234474983745) func0 A func1 A
char 3 in number 7 (4702111234474983745) func0 A func1 A
char 4 in number 7 (4702111234474983745) func0 func1 A
char 5 in number 7 (4702111234474983745) func0 func1 A
char 6 in number 7 (4702111234474983745) func0 func1 A
char 7 in number 7 (4702111234474983745) func0 A func1 A
此代码有 2 个函数,func1
return 是预期值,func0
我认为它应该 return 与 func1
相同的值] 但它没有,我不确定为什么。基本上我理解 8 字节类型,如 8 字节数组,func1
在某种意义上清楚地表明这是这种情况。我不确定为什么使用位移位到达第 n
个字节不起作用,我不确定我是否完全理解 8 字节变量在内存中的排列方式
这是一种极其复杂的方法来做一些非常简单的事情。您甚至不需要考虑字节序问题,因为您不需要访问 long long
的内存表示只是为了获取一个字节。
获取第 n 个字节只是屏蔽掉所有其他字节并将该值转换为 unsigned char
的问题。所以像这样:
unsigned char nth_byte(unsigned long long int value, int n)
{
//Assert that n is on the range [0, 8)
value = value >> (8 * n); //Move the desired byte into the first byte.
value = value & 0xFF; //Mask away everything that isn't the first byte.
return unsigned char(value); //Return the first byte.
}
问题出在代码中
0x00000000000000FF << offset
左边的数字0xFF
只是一个整数(不管你放了多少个零)左移得到一个整数(实际上是整数大小...移动超过大小整数不是可移植代码)。
改用:
0xFFull << offset
解决了这个问题(因为后缀 ull
告诉它应该被视为 unsigned long long
)。
当然,正如另一个答案中所说,(number >> (offset * 8)) & 0xFF
更简单并且有效。
func0 中的问题是您的十六进制文字虽然包含 8 个字节的数据,但由于您没有指定精度而被解释为 long。使用 0xffULL (0xff unsigned long long) 而不是 0x00000000000000ff 应该可以得到你想要的。
线索是它在前 32 位上工作得很好,然后就崩溃了。不过,我无法解释 7th A 是从哪里来的。
分析变量的底层内存表示的正确方法是使用 memcpy 并复制到 char
数组(参考:C aliasing rules and memcpy):
#include <cstring>
char get_char(long long num, size_t offs)
{
char array[sizeof(long long)];
memcpy(array, &num, sizeof(long long));
return array[offs];
}
那么对于下面的例子:
int main()
{
long long var = 0x7766554433221100;
for (size_t idx = 0; idx < sizeof(long long); ++idx)
std::cout << '[' << idx << ']' << '=' << std::hex << static_cast<int>(get_char(var, idx)) << '\n';
}
在小端系统上我们得到:
[0]=0
[1]=11
[2]=22
[3]=33
[4]=44
[5]=55
[6]=66
[7]=77
在大端系统上我们得到:
[0]=77
[1]=66
[2]=55
[3]=44
[4]=33
[5]=22
[6]=11
[7]=0
我想从 8 字节类型中提取字节,例如 char func(long long number, size_t offset)
所以对于偏移量 n,我将得到第 n
个字节(0 <= n <= 7)。在这样做的同时,我意识到我不知道 8 字节变量在内存中的实际表示方式。我希望你能帮我弄清楚。
我首先写了一个简短的 python 脚本来在每个字节
A
s(ascii 值 65)组成的数字
sumx = 0
for x in range(8):
sumx += (ord('A')*256**x)
print('x {} sumx {}'.format(x,sumx))
输出为
x 0 sumx 65
x 1 sumx 16705
x 2 sumx 4276545
x 3 sumx 1094795585
x 4 sumx 280267669825
x 5 sumx 71748523475265
x 6 sumx 18367622009667905
x 7 sumx 4702111234474983745
在我看来,每个数字都是一串 A
后跟 0。接下来我写了一个简短的 C++ 代码来提取第 n
个字节
#include <iostream>
#include <array>
char func0(long long number, size_t offset)
{
offset <<= 3;
return (number & (0x00000000000000FF << offset)) >> offset;
}
char func1(long long unsigned number, size_t offset)
{
char* ptr = (char*)&number;
return ptr[offset];
}
int main()
{
std::array<long long,8> arr{65,16705,4276545,1094795585,280267669825,71748523475265,18367622009667905,4702111234474983745};
for (int i = 0; i < arr.size(); i++)
for (int j = 0; j < sizeof(long long unsigned); j++)
std::cout << "char " << j << " in number " << i << " (" << arr[i] << ") func0 " << func0(arr[i], j) << " func1 " << func1(arr[i], j) << std::endl;
return 0;
}
这是程序输出(注意从第 5 个字节开始的区别)
~ # g++ -std=c++11 prog.cpp -o prog; ./prog
char 0 in number 0 (65) func0 A func1 A
char 1 in number 0 (65) func0 func1
char 2 in number 0 (65) func0 func1
char 3 in number 0 (65) func0 func1
char 4 in number 0 (65) func0 func1
char 5 in number 0 (65) func0 func1
char 6 in number 0 (65) func0 func1
char 7 in number 0 (65) func0 func1
char 0 in number 1 (16705) func0 A func1 A
char 1 in number 1 (16705) func0 A func1 A
char 2 in number 1 (16705) func0 func1
char 3 in number 1 (16705) func0 func1
char 4 in number 1 (16705) func0 func1
char 5 in number 1 (16705) func0 func1
char 6 in number 1 (16705) func0 func1
char 7 in number 1 (16705) func0 func1
char 0 in number 2 (4276545) func0 A func1 A
char 1 in number 2 (4276545) func0 A func1 A
char 2 in number 2 (4276545) func0 A func1 A
char 3 in number 2 (4276545) func0 func1
char 4 in number 2 (4276545) func0 func1
char 5 in number 2 (4276545) func0 func1
char 6 in number 2 (4276545) func0 func1
char 7 in number 2 (4276545) func0 func1
char 0 in number 3 (1094795585) func0 A func1 A
char 1 in number 3 (1094795585) func0 A func1 A
char 2 in number 3 (1094795585) func0 A func1 A
char 3 in number 3 (1094795585) func0 A func1 A
char 4 in number 3 (1094795585) func0 func1
char 5 in number 3 (1094795585) func0 func1
char 6 in number 3 (1094795585) func0 func1
char 7 in number 3 (1094795585) func0 func1
char 0 in number 4 (280267669825) func0 A func1 A
char 1 in number 4 (280267669825) func0 A func1 A
char 2 in number 4 (280267669825) func0 A func1 A
char 3 in number 4 (280267669825) func0 A func1 A
char 4 in number 4 (280267669825) func0 func1 A
char 5 in number 4 (280267669825) func0 func1
char 6 in number 4 (280267669825) func0 func1
char 7 in number 4 (280267669825) func0 func1
char 0 in number 5 (71748523475265) func0 A func1 A
char 1 in number 5 (71748523475265) func0 A func1 A
char 2 in number 5 (71748523475265) func0 A func1 A
char 3 in number 5 (71748523475265) func0 A func1 A
char 4 in number 5 (71748523475265) func0 func1 A
char 5 in number 5 (71748523475265) func0 func1 A
char 6 in number 5 (71748523475265) func0 func1
char 7 in number 5 (71748523475265) func0 func1
char 0 in number 6 (18367622009667905) func0 A func1 A
char 1 in number 6 (18367622009667905) func0 A func1 A
char 2 in number 6 (18367622009667905) func0 A func1 A
char 3 in number 6 (18367622009667905) func0 A func1 A
char 4 in number 6 (18367622009667905) func0 func1 A
char 5 in number 6 (18367622009667905) func0 func1 A
char 6 in number 6 (18367622009667905) func0 func1 A
char 7 in number 6 (18367622009667905) func0 func1
char 0 in number 7 (4702111234474983745) func0 A func1 A
char 1 in number 7 (4702111234474983745) func0 A func1 A
char 2 in number 7 (4702111234474983745) func0 A func1 A
char 3 in number 7 (4702111234474983745) func0 A func1 A
char 4 in number 7 (4702111234474983745) func0 func1 A
char 5 in number 7 (4702111234474983745) func0 func1 A
char 6 in number 7 (4702111234474983745) func0 func1 A
char 7 in number 7 (4702111234474983745) func0 A func1 A
此代码有 2 个函数,func1
return 是预期值,func0
我认为它应该 return 与 func1
相同的值] 但它没有,我不确定为什么。基本上我理解 8 字节类型,如 8 字节数组,func1
在某种意义上清楚地表明这是这种情况。我不确定为什么使用位移位到达第 n
个字节不起作用,我不确定我是否完全理解 8 字节变量在内存中的排列方式
这是一种极其复杂的方法来做一些非常简单的事情。您甚至不需要考虑字节序问题,因为您不需要访问 long long
的内存表示只是为了获取一个字节。
获取第 n 个字节只是屏蔽掉所有其他字节并将该值转换为 unsigned char
的问题。所以像这样:
unsigned char nth_byte(unsigned long long int value, int n)
{
//Assert that n is on the range [0, 8)
value = value >> (8 * n); //Move the desired byte into the first byte.
value = value & 0xFF; //Mask away everything that isn't the first byte.
return unsigned char(value); //Return the first byte.
}
问题出在代码中
0x00000000000000FF << offset
左边的数字0xFF
只是一个整数(不管你放了多少个零)左移得到一个整数(实际上是整数大小...移动超过大小整数不是可移植代码)。
改用:
0xFFull << offset
解决了这个问题(因为后缀 ull
告诉它应该被视为 unsigned long long
)。
当然,正如另一个答案中所说,(number >> (offset * 8)) & 0xFF
更简单并且有效。
func0 中的问题是您的十六进制文字虽然包含 8 个字节的数据,但由于您没有指定精度而被解释为 long。使用 0xffULL (0xff unsigned long long) 而不是 0x00000000000000ff 应该可以得到你想要的。
线索是它在前 32 位上工作得很好,然后就崩溃了。不过,我无法解释 7th A 是从哪里来的。
分析变量的底层内存表示的正确方法是使用 memcpy 并复制到 char
数组(参考:C aliasing rules and memcpy):
#include <cstring>
char get_char(long long num, size_t offs)
{
char array[sizeof(long long)];
memcpy(array, &num, sizeof(long long));
return array[offs];
}
那么对于下面的例子:
int main()
{
long long var = 0x7766554433221100;
for (size_t idx = 0; idx < sizeof(long long); ++idx)
std::cout << '[' << idx << ']' << '=' << std::hex << static_cast<int>(get_char(var, idx)) << '\n';
}
在小端系统上我们得到:
[0]=0
[1]=11
[2]=22
[3]=33
[4]=44
[5]=55
[6]=66
[7]=77
在大端系统上我们得到:
[0]=77
[1]=66
[2]=55
[3]=44
[4]=33
[5]=22
[6]=11
[7]=0