首页 > 试题广场 >

在一个64位的操作系统中定义如下结构体以及对应的fool函数

[单选题]
在一个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()程序的执行结果为()


  • 1,0,0
  • 1,1,0
  • 0,1,1
  • 0,0,1
st_task:
id        value     timestamp
0000|0000|0000 0000|0000 0000 0000 0000 (physical)

a: 
0000 0000 0001 0001   (logic)
0001 0001 0000 0000   (physical)


st_task:
id        value     timestamp
0001|0001|0000 0000|0000 0000 0000 0000
1        |0        |0

发表于 2015-09-10 10:36:45 回复(2)
答案:A
考点:字节对齐,低地址到高地址
    因为字节对齐的原因,所以id占用4个字节,value和timestamp分别是4个字节、8个字节。虽然id占用四个字节的地址,但是只有低两位地址的数值有效(字节对齐的机制,即value存储时的地址对4(自身对齐值)求余应为0)。所以id为 0001 0001,高四位无效,所以为0001,value与timestamp分别为0.
    比如:地址从0x0000开始,id存储地址本来为0x0000-0x0001,但value存储地址要从0x0004开始,因为0x0004%4==0,所以id存储地址为0x0000-0x0003, value存储地址为0x0004-0x0007, timestamp存储地址为0x0008-0x000F. 所以id == 0x00010001,去掉高4位,id=0x0001,其余为0.
编辑于 2015-08-10 20:09:44 回复(11)
答案是:A

前面解释的都有些问题。
看如下:输出的是1,0,0和10001。
uint64_t占用8字节,那么a可以表示为0x0000000000010001。而在注意的是,在task是字节对齐的。所以对于前四个字节,分别是是01000100 00000000 0000000000000000,而id对应前两个字节所以是1,而value对应四个字节是00000000,后面的也是如此,也就是0100之后的0100只是起了填充的作用,所以当你打出task时会输出0x10001。
    typedef short uint16_t;
    typedef int uint32_t;
    typedef long long uint64_t;
    struct st_task
    {
        uint16_t id;
        uint32_t value;
        uint64_t timestamp;
    };
    st_task task = {};
    uint64_t a = 0x00010001;
    memcpy(&task, &a, sizeof(uint64_t));
    printf("%11u,%11u,%11u \n", task.id, task.value, task.timestamp);
    printf("0x%x\n", task);

发表于 2015-07-03 10:59:39 回复(7)
A
根据4字节对齐原则,id占用4字节,value占用4字节,timestamp占用8字节
a高位补0则为 0x 0000 0000 0001 0001
复制给结构体时:
低位4个字节复制到id --> id为1
高为4个字节复制到value --> value为0
timestamp不改变
如果8字节对齐,那么就更容易了,直接a覆盖到id上,答案还是A
编辑于 2015-03-10 14:14:22 回复(10)
首先是结构的内存对齐,所以2,3字节是padding的,value是4-7,timestamp是8-15
然后就是小端对齐,所以从a的低字节开始填入结构体的内存空间
发表于 2015-08-22 22:33:13 回复(4)
我是菜青虫,连答案都看不懂^==^
发表于 2017-01-20 10:20:43 回复(0)
答案:C
uint64_t a = 0x00010001; a是一个64位无符号数,通过内存拷贝,最高16位拷贝给task.id,为0,然后接着32位拷贝给task.valus,为1,最后16位拷贝给task.timestamp,为1
发表于 2015-01-28 11:30:30 回复(1)
1字节     uint8_t
2字节     uint16_t
4字节     uint32_t
8字节     uint64_t
发表于 2015-08-16 12:19:10 回复(0)
发表于 2023-05-02 00:17:21 回复(0)
本题目融合了内存的存储模式:逻辑低位对应放在内存的高位地址,我们接下来要搞清楚一个地址所对应的内存大小为多少?64位机器,一个地址存放1字节的内容。对于0x0001 0001而言,它所占用的内存大小为4字节,证明00、01、00、01各自存在一个地址上,所以存放的状态为01 00 01 00。对于st_task,它包含有3个成员,成员按照高地址向低地址逐个排放,注意字节对齐!unit16_t是要占用2字节,而uint32_t占用4字节,注意此时考虑字节对齐问题,unit32_t这个成员不能紧靠uint16_t存放,要空2个字节的位置。而uint64_t是占用8个字节,可以紧靠uint32_t存放。接下来,我们看如何进行拷贝数据。高位放高位,0x0001 0001一共2字节,结果全放在了uint16_t的所占据的4字节范围内,注意虽然uint16_t占用了4字节,但受其数据类型的限制,只能有高位地址的内存。而此时高位的存放状态是0x0100 0100,只有前面的0100被使用再转换成逻辑格式位0001,即为1。而uint32、uint64压根就没见着0x0001 0001所复制过来的数据,因此它们都是0.
发表于 2021-09-03 12:07:02 回复(0)
1   uint64_t a = 0x00010001; 是16进制的,所以变成二进制是0000|0000|0000|0001|0000|0000|0000|00001
2   由于id占16为bit,计算机是小端 0000|0000|0000|00001 左边这个就给它了,右边0000|0000|0000|0001这个由于字节对齐,是在补位里面的,所以uint32_t value;  uint64_t timestamp;全是0
发表于 2021-08-21 15:29:32 回复(0)
id低地址,timestamp高地址。0x00010001为低地址正好为四个字节,对应id。而高位全为0,对应value, timestamp。
发表于 2021-05-25 13:30:10 回复(0)
http://m.blog.csdn.net/article/details?id=8510401 在结构体中,成员数据对齐满足以下规则:   a、结构体中的第一个成员的首地址也即是结构体变量的首地址。         b、结构体中的每一个成员的首地址相对于结构体的首地址的偏移量(offset)是该成员数据类型大小的整数倍。         c、结构体的总大小是最大数据类型的的整数倍 大小端: 对于0x11223344,肯定是左边大,右边小 小端是小的在低址,大端是大的在低址 小端 44332211 低址–高址 大 端 11223344 高址–低址 所以id占0,1 value占4,5,6,7 2,3作为补齐, 0x00010001不够8个字节,所以需要扩充,0000 0000 0001 0001,因为是小端,所以id为01 00,value为0000 然后输入结果%11u表示11位,id只有8位 0000 首先是结构的内存对齐,所以2,3字节是padding的,value是4-7,timestamp是8-15 然后就是小端对齐,所以从a的低字节开始填入结构体的内存空间
编辑于 2017-05-14 21:37:26 回复(0)
这题有问题,谁哪知道到底按照多少个字节对齐?别跟我说默认,如果什么条件都默认了,那还要if...else干屁呢,要条件编译干屁呢?程序员都不确定自己的代码在哪个平台跑,怎么能假定对齐标准呢?
发表于 2016-04-07 23:31:12 回复(0)

发表于 2025-08-16 10:50:07 回复(0)
在线蹲各路大神详细易懂的解答,脑子不好,上面大神的解释看不懂
发表于 2022-08-10 14:16:23 回复(0)
因为a为16进制,所以a中每个数位转化为2进制的话占4位,16进制a共8位,所以2进制为32位,结构体中元素按32位对齐,所以a只够赋值给id,而id一共有16位,按从低到高赋值,高16位(在16进制a中为高4位)就无效了,所以最终id = 0001 = 1,答案A正确
发表于 2019-04-06 18:10:55 回复(0)

考点:对齐+低地址到高地址

uint64_t占用8字节,那么a可以表示为0x0000000000010001。而在注意的是,在task是字节对齐的。所以对于前四个字节,分别是是1000
1000 00000000
0000000000000000,而id对应前两个字节所以是0x0001,而value对应四个字节是00000000
发表于 2015-08-06 21:18:57 回复(1)
B.
### 问题分析

我们需要分析在 64 位系统中,`fool()` 函数执行后的输出结果。重点关注结构体的内存布局和 `memcpy` 的行为。

---

### 1. **结构体 `st_task` 的内存布局(64 位系统)**
```c
struct st_task {
    uint16_t id;        // 2 字节
    uint32_t value;     // 4 字节
    uint64_t timestamp; // 8 字节
};
```
- **对齐规则**(64 位系统):
  - `uint16_t`(2 字节):对齐到 2 字节。
  - `uint32_t`(4 字节):对齐到 4 字节。
  - `uint64_t`(8 字节):对齐到 8 字节。
- **内存布局**:
  - `id`:偏移量 0,占用 2 字节。
  - `value`:偏移量 4(因为 `uint32_t` 需要 4 字节对齐,跳过 2 字节填充),占用 4 字节。
  - `timestamp`:偏移量 8(自然对齐),占用 8 字节。
- **结构体总大小**:16 字节(2 + 2填充 + 4 + 8)。

---

### 2. **`fool()` 函数的行为**
```c
void fool() {
    st_task task = {};                // 初始化所有成员为 0
    uint64_t a = 0x00010001;          // a = 0x0000000000010001
    memcpy(&task, &a, sizeof(uint64_t)); // 将 a 的 8 字节拷贝到 task 的起始地址
    printf("%11u,%11u,%11u", task.id, task.value, task.timestamp);
}
```
- **`memcpy` 的作用**:
  - 将 `a` 的 8 字节(`0x0000000000010001`)拷贝到 `task` 的起始地址(覆盖 `id` 和 `value` 的部分)。
- **拷贝后的内存内容**:
  - 低地址 → 高地址:
    ```
    0x01 0x00 0x01 0x00 0x00 0x00 0x00 0x00 | ... (timestamp 保持为 0)
    ```
  - 解释:
    - `id`(2 字节):`0x0001`(低字节序,实际存储为 `0x01 0x00`)。
    - `value`(4 字节):`0x00000001`(接下来的 4 字节,`0x01 0x00 0x00 0x00`)。
    - `timestamp`(8 字节):未被覆盖,保持为 0。

---

### 3. **成员值的解析**
- `task.id`:
  - 读取前 2 字节:`0x0001` → **`1`**。
- `task.value`:
  - 读取接下来的 4 字节:`0x00000001` → **`1`**。
- `task.timestamp`:
  - 未被 `memcpy` 覆盖,保持为 `0`。

---

### 4. **输出结果**
```c
printf("%11u,%11u,%11u", task.id, task.value, task.timestamp);
```
- 格式化输出:
  - `%11u`:右对齐,宽度 11。
- 结果:
  ```
          1,          1,          0
  ```

---

### 验证(假设小端序)
- `a = 0x0000000000010001` 在内存中的字节序(小端):
  ```
  低地址 -> 0x01 0x00 0x01 0x00 0x00 0x00 0x00 0x00
  ```
- 拷贝到 `task` 后的内存:
  ```
  id:     0x01 0x00       (1)
  padding:0x?? 0x??       (填充,未被覆盖)
  value:  0x01 0x00 0x00 0x00 (1)
  timestamp: 0x00...     (0)
  ```

---

### 最终答案
程序输出:
```
          1,          1,          0
```

发表于 2025-07-16 12:44:46 回复(0)
SB题目,没有说明主机序是小端序
发表于 2025-05-27 18:47:32 回复(0)