C 网络编程中的数据对齐

C 网络编程中的数据对齐,c,networking,alignment,C,Networking,Alignment,关于数据对齐,我有点困惑。在x86上,我们通常认为对齐是理所当然的。然而,我在一个非常严格的系统上编程,如果我试图访问未对齐的数据,就会出错 我的问题是: 首先,我将向您展示我拥有的一些结构: struct sniff_ethernet { u_char ether_dhost[6]; /* Destination host address */ u_char ether_shost[6]; /* Source host address */ u_short ether_type;

关于数据对齐,我有点困惑。在x86上,我们通常认为对齐是理所当然的。然而,我在一个非常严格的系统上编程,如果我试图访问未对齐的数据,就会出错

我的问题是:

首先,我将向您展示我拥有的一些结构:

struct sniff_ethernet {
  u_char ether_dhost[6]; /* Destination host address */
  u_char ether_shost[6]; /* Source host address */
  u_short ether_type; /* IP? ARP? RARP? etc */
};

struct sniff_ip {
  u_char ip_vhl;  /* version << 4 | header length >> 2 */
  u_char ip_tos;  /* type of service */
  u_short ip_len;  /* total length */
  u_short ip_id;  /* identification */
  u_short ip_off;  /* fragment offset field */
  u_char ip_ttl;  /* time to live */
  u_char ip_p;  /* protocol */
  u_short ip_sum;  /* checksum */
  struct in_addr ip_src,ip_dst; /* source and dest address */
 };
让我们假设数据包是几百个字节。我通常要做的是将数据包转换成几个结构指针,以便直接访问数据

struct sniff_ethernet *seth = (struct sniff_ethernet *) packet;
struct sniff_ip *sip = (struct sniff_ip *) (packet + 14); // 14 is the size of an ethernet header
嗯。所以一切看起来都很好,对吗?在x86上,一切似乎都正常工作。在任何其他具有严格对齐的架构上,我在访问某些值时遇到问题,这通常会导致sigbus。例如:

sip->ip_len = 0x32AA;


导致错误。我猜是因为演员的记忆不一致。在执行此类强制转换时,处理此问题的最佳方法通常是什么?

简单的方法是使用
memcpy

struct sniff_ip sip;
memcpy(&sip, packet + 14, sizeof(sip));
这假设您的两台机器使用相同的字节顺序,并且仔细考虑了结构填充

更难、更通用的处理方法是从单个字节构造值:

u_short val;
int offset = 14 + offsetof(sniff_ip, ip_len);
val = packet[offset] + (packet[offset+1] << 8); // assuming little endian packet
u_short val;
int offset=14+offsetof(嗅探ip,ip长度);

val=packet[offset]+(packet[offset+1]而不是使用
+
是,但这假设结构最初是使用网络顺序(大端)填充的。我从问题中得到的印象是,它们是使用x86(小端)顺序填充的。从问题中,“pcap将向我返回指向数据包的指针”表示代码正在接收数据包;以太网类型和IP头中的字段都是大端,而不是小端。x86与非x86的问题在于对齐要求,而不是字节顺序;x86则不是(默认情况下)需要对齐,但其他一些指令集体系结构(例如SPARC,它在默认情况下恰好是big-endian)确实需要对齐。在gcc中,您有_属性_((压缩))来告诉编译器在没有任何填充的情况下紧密对齐结构。
__属性__((压缩))
在这种情况下没有区别,因为这些结构没有填充。
struct sniff_ip sip;
memcpy(&sip, packet + 14, sizeof(sip));
u_short val;
int offset = 14 + offsetof(sniff_ip, ip_len);
val = packet[offset] + (packet[offset+1] << 8); // assuming little endian packet