关于内存对齐的一些困惑
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 应用程序之间的区别感到困惑!
问题:
mnode->ipc_head.list->sn_buf
和 &mnode->ipc_head.list->smss[0]
之间的距离 是 21
字节
在 win32 控制台应用程序和 MFC 应用程序中,不是 24
字节,因为 (13 + 3) + 8
表示 24
!但是为什么?
变量定义后内存地址应该是一定的,当然变量定义后已经在内存中对齐了!而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).
很高兴对您有所帮助,如果您还有其他问题,请告诉我。
#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 应用程序之间的区别感到困惑!
问题:
mnode->ipc_head.list->sn_buf
和&mnode->ipc_head.list->smss[0]
之间的距离 是21
字节 在 win32 控制台应用程序和 MFC 应用程序中,不是24
字节,因为(13 + 3) + 8
表示24
!但是为什么?变量定义后内存地址应该是一定的,当然变量定义后已经在内存中对齐了!而
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).
很高兴对您有所帮助,如果您还有其他问题,请告诉我。