概念:

在计算机运算中,内存地址是一种用于软件和硬件等不同层级中的数据概念,用来访问电脑主存中的数据; 分为逻辑地址和物理地址,逻辑地址指程序中的地址(或者叫虚地址);而在8086的实模式下,将某一段寄存器左移4位,然后与地址ADDR相加后直接送到内存总线上,这个相加后的地址就是内存单元的物理地址。

表示形式

我们应用层一般都是关注逻辑地址,接下来介绍一下逻辑地址的表示形式; 逻辑地址一般用16进值表示,对于32位机,即用0x00000000至0xffffffff表示;对于64位机,即用0x0000000000000000至0xffffffffffffffff表示;在内存中每两位表示一个字节;

这个怎么理解?
转化为二进制:
32位机有32根地址线,可以产生
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
...
11111111 11111111 11111111 11111111 
结论:32位机,有2的32次方个地址,每个地址由32根地址线组成;转化为16进制,就是16的8次方个地址 = 2的32次方个地址;每个地址用16进制表示就是0x00000000~0xffffffff其中的一个;
64位机可以自己算算?
结论:64位机,有2的64次方个地址,每个地址由64根地址线组成;转化为16进制,就是16的16次方个地址 = 2的64次方个地址;每个地址用16进制表示就是0x0000000000000000~0xffffffffffffffff其中的一个;

字节对齐

如果没有自定义字节对齐的话,32位机是4字节对齐,64位机是8字节对齐;

题目

在一个64位的操作系统中定义如下结构体:
struct st_task
{
    uint16_t id;
    uint32_t value;
    uint64_t timestamp;
};
同时定义fool函数如下:
void fool()
{
    st_task task = {};
    uint64_t a = 0x00010001;
    memcpy(&task, &a, sizeof(uint64_t));
    printf("%11u,%11u,%11u", task.id, task.value, task.timestamp);
}
上述fool()程序的执行结果为(A)
A、1,0,0
B、1,1,0
C、0,1,1
D、0,0,1

解释:
感觉题目少说了个条件——机器的大小端,看答案,机器应该是大端,也就是数据地位保存在内存高地址。就题目来说,64为系统,值是0x00000000 00010001,在内存中则是这样01 00 01 00 00 00 00 00,所以把a内存拷贝到task后,task的前64个位就是前面这个,id占前面两个字节,所以id的内存是01 00,所以id是1。