关于内存对齐的一些困惑

some confusions about Memory Alignment

#define     MCARD_CLS_TYPE_HD           1
#define     MCARD_SN_LEN                13

typedef struct mcard_ipc_list       
{                                   
    struct mcard_node *owner;

    struct
    {
        struct mcard_ipc_list *next;
        struct mcard_ipc_list *prev;
    } node;

    char sn_buf[MCARD_SN_LEN];  //13 byte

    struct len_str sn;          //8 byte                            
    struct mcard_smss smss[MCARD_CLS_TYPE_MIN + 1]; //16*3 byte
} _mcard_ipc_list;


struct mcard_smss           *smss = NULL;
struct mcard_node           *mnode = NULL;
...
smss = mnode->ipc_head.list->smss + MCARD_CLS_TYPE_HD;

问题是 smss 中的数据在 MFC 应用程序中不正确,但在 win32 控制台应用程序中正常!

我在VS2010的watchwindows中看到了变量的地址

win32控制台应用程序的结果:

smss                            0x0068af61
&mnode->ipc_head.list->smss[1]  0x0068af61  
&mnode->ipc_head.list->smss[0]  0x0068af51 
mnode->ipc_head.list->sn_buf    0x005aaf3c

MFC应用程序的结果:

smss                            0x00b1ad54 
&mnode->ipc_head.list->smss[1]  0x00b1ad51 
&mnode->ipc_head.list->smss[0]  0x00b1ad41 
mnode->ipc_head.list->sn_buf    0x00b1ad2c

对于 MFC 应用程序,很明显 smss 不等于 &mnode->ipc_head.list->smss[1] 但具有偏移量 0x3 !

我们看到 mnode->ipc_head.list->sn_buf 占用 13 字节,未对齐!

其实我已经解决了这个问题,有两个方法:

(1)

#pragma pack(push, 1)
#pragma pack(pop)

(2)

#define     MCARD_SN_LEN                16

但是,当需要字节对齐时,我仍然对 win32 控制台应用程序和 MFC 应用程序之间的区别感到困惑!

问题:

  1. mnode->ipc_head.list->sn_buf&mnode->ipc_head.list->smss[0] 之间的距离 21 字节 在 win32 控制台应用程序和 MFC 应用程序中,不是 24 字节,因为 (13 + 3) + 8 表示 24!但是为什么?

  2. 变量定义后内存地址应该是一定的,当然变量定义后已经在内存中对齐了!而smss = mnode->ipc_head.list->smss + MCARD_CLS_TYPE_HD;只是一个赋值语句, 为什么MFC应用程序的结果不是0x00b1ad51而是0x00b1ad54?而且这种现象是可以重现的!

所以,如果有人可以帮助我吗?


更新:

嗯,我写了一个 MFC 演示来解决第二个问题。

struct mcard_smss *smss = NULL;
smss = (struct mcard_smss *)0x00b1ad51;

但是我在vs2010中watch windows看到的smss的值不是0x00b1ad54而是0x00b1ad51!

改变了,太棒了!我不知道为什么

继续评论,因为编译器可以在 struct 中设置字段的大小和填充,您可以使用 offsetof 宏(stddef.h) 来确定成员在宏中的偏移量:

size_t offsetof(type, member);

offsetof 的手册页描述了它的用法并提供了示例。

The macro offsetof() returns the offset of the field member from the
start of the structure type.

This  macro  is useful because the sizes of the fields that compose a 
structure can vary across implementations, and compilers may insert 
different numbers of padding bytes between fields.  Consequently, an 
element's offset is not necessarily given by the sum of the sizes of 
the previous elements.

A compiler error will result if member is not aligned to a byte boundary
(i.e., it is a bit field).

很高兴对您有所帮助,如果您还有其他问题,请告诉我。