kgbook
kgbook

Reputation: 388

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 24bytes 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

Upvotes: 0

Views: 113

Answers (1)

David C. Rankin
David C. Rankin

Reputation: 84609

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.

Upvotes: 3

Related Questions