这是一个滥用void*
ptr(这本身就是一个糟糕的编码实践)的示例,但是当我查看内存细节时它会变得很有趣。
#include <iostream>
using namespace std;
typedef struct {
long a;
void print() {
std::cout << a;
}
} st;
int main() {
int t[2] = {1,2};
void* p = t;
st* spt = (st*) p;
spt->print();
return 0;
}
由于long
为64位,而int
为32位,因此t {1,2}
中的两个整数构成long a
中的struct
空间{1}}。
但我的问题是,由于现在{1,2}
组成a
,二进制内存对齐应该是00000000000000000000000000000001 00000000000000000000000000000010
,它应该以十进制格式给出4294967298
。但是,实际打印输出为8589934593
,即00000000000000000000000000000010 00000000000000000000000000000001
。似乎1
和2
的位置实际上是交换的。
为什么会这样?
答案 0 :(得分:2)
在little-endian机器上,library(gsubfn)
## Function to pass to gsubfn (use backref to get reference to orignal string)
## x is original string, y is first group (numbers), z is last (characters)
f <- function(x, y, z) {
n <- as.numeric(y)
if(is.na(n)) n <- as.numeric(substr(y, 1, nchar(y)-1))*-1 # case: [-]\\d+-
if (n == 0) return( '0' )
if (n == 1) return( z )
if (n == -1) return( paste0("-", z) )
return( paste0(n, z) )
}
A[, lapply(1:ncol(A), function(i) suppressWarnings(
gsubfn('([-\\d]+)(.*)', f, paste0(A[[i]], B[[i]]), backref=2))) ]
# V1 V2
# 1: -a d
# 2: 3b 0
# 3: -4c -f
数组在内存中按以下字节顺序排列
{ 1, 2 }
当重新解释为64位little-endian值时,它会生成01 00 00 00 02 00 00 00 // addresses increase from left to right
。
在big-endian机器上,相同的数组布局为
8589934593
当重新解释为64位大端值时,它会生成00 00 00 01 00 00 00 02 // addresses increase from left to right
。
因此,您的实验只是表明您在小端机器上运行代码。这就是它的全部内容。
答案 1 :(得分:1)
有趣的事实。在数字上,答案可以简化为的指数
2^n + 1: n=33
哪个
2^(33)+1 = 8589934593
,以二进制表示为
1000000000000000000000000000000001
可爱的二进制文件;有32个零,在这种情况下为n-1。
答案 2 :(得分:0)
我以更便携的方式重写代码,它需要c ++ 11:
#include <cstdint>
#include <iostream>
int main()
{
union {
uint32_t t[2];
uint64_t a;
} val;
val.t[0] = 1;
val.t[1] = 2;
std::cout << val.a << ", " << std::hex << val.a << '\n';
}
我的amd64机器上的输出是:
8589934593,200000001
似乎完全有效,等于uint64_t(2) << 32 | uint64_t(1)