C 奇怪的填充问题是从数组缓冲区(来自原始套接字)加载结构。如何修复?

C 奇怪的填充问题是从数组缓冲区(来自原始套接字)加载结构。如何修复?,c,sockets,C,Sockets,我为ARP头定义了以下结构: typedef uint8_t MacAddress[6]; typedef struct { MacAddress Destination; MacAddress Source; uint16_t Type; } EthernetHeader; typedef struct { uint16_t HardwareType; uint16_t ProtocolType; uint8_t Har

我为ARP头定义了以下结构:

typedef uint8_t MacAddress[6];

typedef struct
{
    MacAddress Destination;
    MacAddress Source;
    uint16_t Type;
} EthernetHeader;

typedef struct
{
    uint16_t    HardwareType;
    uint16_t    ProtocolType;

    uint8_t     HardwareAddressLength;
    uint8_t     ProtocolAddressLength;
    uint16_t    Operation;

    MacAddress  SenderHardwareAddress;
    uint32_t    SenderProtocolAddress;
    MacAddress  TargetHardwareAddress;
    uint32_t    TargetProtocolAddress;
} ArpHeader;
我的问题是,
SenderProtocolAddress
在右边填充了2个字节,因此它实际上读取了自身的一半和
targethardweaddress
的一部分。同样的事情也会发生在目标上,除了这次将
TargetProtocolAddress
填充到右边的4位之外(全部为零,因为它超出了缓冲区的实际内容)


我不知道为什么会发生这种情况,因为Ethernet结构与我制作的MacAddress类型读取得很好,并且直到最后4个数据段都完全按照预期读取。我不知道,这里出了什么问题?

您可以使用编译器特定的对齐属性/pragmas,但我认为最好不要以这种方式使用结构除非你真的需要表演


只需在结构和缓冲区之间编写函数来marshall。您也不必担心这种方式的平台端性。

您可以使用编译器特定的对齐属性/pragmas,但我认为最好不要以这种方式使用结构,除非您真的需要性能


只需在结构和缓冲区之间编写函数来marshall。您也不必担心这种方式的平台端性。

您可以使用编译器特定的对齐属性/pragmas,但我认为最好不要以这种方式使用结构,除非您真的需要性能


只需在结构和缓冲区之间编写函数来marshall。您也不必担心这种方式的平台端性。

您可以使用编译器特定的对齐属性/pragmas,但我认为最好不要以这种方式使用结构,除非您真的需要性能


只需将函数写入结构和缓冲区之间的marshall。这样也不必担心平台端性。

如果使用gcc,请在结构的定义中添加
\uuuu属性((打包))
,通知编译器不要填充

请注意,在某些体系结构上,在未对齐的地址上访问某些类型/大小是不合适的(例如,某些ARMv6实现)


正如Frank所说,可以创建一个大的缓冲区并使用偏移量来消除这些类型的问题。另一方面,您必须跟踪偏移量的大小。

如果您使用的是gcc,请在结构的定义中添加
\uuu attribute\uuuuuuu((打包))
,以通知编译器不要填充

请注意,在某些体系结构上,在未对齐的地址上访问某些类型/大小是不合适的(例如,某些ARMv6实现)


正如Frank所说,可以创建一个大的缓冲区并使用偏移量来消除这些类型的问题。另一方面,您必须跟踪偏移量的大小。

如果您使用的是gcc,请在结构的定义中添加
\uuu attribute\uuuuuuu((打包))
,以通知编译器不要填充

请注意,在某些体系结构上,在未对齐的地址上访问某些类型/大小是不合适的(例如,某些ARMv6实现)


正如Frank所说,可以创建一个大的缓冲区并使用偏移量来消除这些类型的问题。另一方面,您必须跟踪偏移量的大小。

如果您使用的是gcc,请在结构的定义中添加
\uuu attribute\uuuuuuu((打包))
,以通知编译器不要填充

请注意,在某些体系结构上,在未对齐的地址上访问某些类型/大小是不合适的(例如,某些ARMv6实现)


正如Frank所说,可以创建一个大的缓冲区并使用偏移量来消除这些类型的问题。另一方面,您必须跟踪偏移量的大小。

这是因为
SenderProtocolAddress
未与32位地址对齐。在它之前(以及
TargetProtocolAddress
之前)添加一个2字节的填充。如果在
SenderProtocolAddress
之前添加2个字节,它将不会读取实际的ip地址。发生的情况是[6字节MAC][2字节未读取][4字节ip地址]。出于某种原因,我需要让它读取当前跳过的2个字节。哦,对了,编译器会自动执行此操作,这就是为什么您会得到这些错误的值。然后在声明之前使用
#pragma pack(push,1)
,在声明之后使用
#pragma pack(pop)
。您的意思是“向右填充4个字节?”正如Barak所说,如果您通过一个操作读取整个内容,则需要对结构进行打包。如果您使用的是gcc,请在结构的定义中添加
\uuuuu attribute\uuuuu((打包))
,以通知编译器不要填充(编辑:注意,在某些体系结构中,在未对齐的地址上访问某些类型/大小是不合适的)这是因为
SenderProtocolAddress
未与32位地址对齐。请在其前面(以及
TargetProtocolAddress
之前)添加一个2字节的填充。如果在
SenderProtocolAddress
之前添加2个字节,它将不会读取实际的ip地址。发生的情况是[6字节MAC][2字节未读取][4字节ip地址]。出于某种原因,我需要让它读取当前跳过的2个字节。哦,对了,编译器会自动执行此操作,这就是为什么您会得到这些错误的值。然后在声明之前使用
#pragma pack(push,1)
,在声明之后使用
#pragma pack(pop)
。您的意思是“向右填充4个字节?”正如Barak所说,如果您通过一个操作读取整个内容,则需要对结构进行打包。如果您使用的是gcc,请在结构的定义中添加
\uuuuu attribute\uuuuu((打包))
,以通知编译器不要填充(编辑:注意,在某些体系结构中,在未对齐的地址上访问某些类型/大小是不合适的)这是因为
SenderProtocolAddress
未与32位地址对齐