面试题答案
一键面试1. struct Header
内存布局分析
- 位域分配方式:
version
占据4位,它从Header
结构体的起始字节的低4位开始存储。例如,如果Header
结构体起始地址为0x1000
,那么version
的值就存储在0x1000
这个字节的低4位。type
同样占据4位,紧跟在version
之后,使用起始字节的高4位。所以type
和version
共用第一个字节。length
占据16位,即2个字节。它从第二个字节开始存储,这样Header
结构体总共占用3个字节。
2. 大小计算
union Payload
大小:union
的大小是其最大成员的大小。normal
成员中data
数组大小为100字节,error
成员中errorCode
(假设int
为4字节)加上errorMsg
数组(50字节)总共为54字节。所以union Payload
的大小为100字节。
struct Packet
大小:struct Packet
包含一个struct Header
和一个union Payload
。struct Header
大小为3字节,union Payload
大小为100字节。在C语言中,结构体的大小需要考虑内存对齐。通常结构体的大小是其最大成员大小的整数倍。这里最大成员大小为union Payload
的100字节,所以struct Packet
的大小为100 + 3 = 103字节,为了满足对齐要求,实际大小为104字节(因为103不是4的倍数,而104是4的倍数,假设系统以4字节对齐)。
3. 不同系统间传输和解析数据
- 实现思路:
- 字节序转换:在发送端,将结构体中的多字节数据(如
length
和errorCode
)转换为网络字节序(大端序)。在接收端,将接收到的数据转换回主机字节序。 - 内存对齐:在发送端,确保结构体在内存中是按正确的对齐方式存储的,并且在接收端以相同的对齐方式解析。
- 字节序转换:在发送端,将结构体中的多字节数据(如
- 代码示例:
#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
// 假设要发送的Packet
struct Header {
unsigned int version: 4;
unsigned int type: 4;
unsigned int length: 16;
};
union Payload {
struct {
char data[100];
} normal;
struct {
int errorCode;
char errorMsg[50];
} error;
};
struct Packet {
struct Header h;
union Payload p;
};
// 发送函数
void sendPacket(struct Packet *packet, char *buffer) {
// 转换length到网络字节序
packet->h.length = htons(packet->h.length);
// 转换errorCode到网络字节序(如果是error类型)
if (packet->h.type == 1) { // 假设type为1表示error类型
packet->p.error.errorCode = htonl(packet->p.error.errorCode);
}
// 复制数据到buffer
memcpy(buffer, packet, sizeof(struct Packet));
}
// 接收函数
void receivePacket(char *buffer, struct Packet *packet) {
// 从buffer复制数据到packet
memcpy(packet, buffer, sizeof(struct Packet));
// 转换length到主机字节序
packet->h.length = ntohs(packet->h.length);
// 转换errorCode到主机字节序(如果是error类型)
if (packet->h.type == 1) {
packet->p.error.errorCode = ntohl(packet->p.error.errorCode);
}
}
在实际应用中,可以结合网络编程接口(如socket
)来使用上述函数进行数据的发送和接收。