Cory Kang Cory Kang - 3 months ago 19
C Question

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;


the issue is that the data in
smss
is not correct in MFC application but ok in win32 console application!

I saw the the address of variables in the watch windows in VS2010.

the result of the win32 console application:

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


the result of the MFC application:

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


For MFC application, it's obvious that
smss
wa not equal to
&mnode->ipc_head.list->smss[1]
but has the offset
0x3
!

And we see that
mnode->ipc_head.list->sn_buf
occupy
13
bytes, not alligned!

i have solved the problem actually, and there is two methods:

(1)

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


(2)

#define MCARD_SN_LEN 16


However, i still confused about the the difference between win32 console application and MFC application when byte aligment needed!

issue:


  1. the distance between
    mnode->ipc_head.list->sn_buf
    and
    &mnode->ipc_head.list->smss[0]
    is
    21
    bytes
    both in win32 console application and MFC application, not
    24
    bytes because
    (13 + 3) + 8
    means
    24
    ! But why?

  2. the memory address should be certain afer the variable defined, of course they have been aligned in memory afer the variable defined! And
    smss = mnode->ipc_head.list->smss + MCARD_CLS_TYPE_HD;
    is just a Assignment Statements,
    why the result in MFC application is not
    0x00b1ad51
    but
    0x00b1ad54
    ? And the phenomenon is reproducible!



So, if any one can help me out?




update:

um, i wrote a MFC demo to figure the 2nd issue out.

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


However, the value of
smss
i saw in watch windows in vs2010 is not
0x00b1ad54
but
0x00b1ad51
!

Something changed and amazing! I don't know why

Answer

Continuing from the comment, since the compiler can set the size of the fields and padding within a struct, you can use offsetof macro (stddef.h) to determine the offset of a member within a macro:

size_t offsetof(type, member);

The man page for offsetof describes its use and provides an example.

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).

Glad it helped, let me know if you have any additional questions.

Comments