32ビット⇒64ビット化の問題では無く、アラインメントの話だと思うけど

|

64ビット化擬きの真似事の続きの続きの続きです。

MSドキュメントの「移植に関する問題のチェックリスト」に書かれている以下の問題点は、本当に64ビット化に関する問題なのか? と首を傾げたくなります。(それとも、隠れている意図を見つけられないだけ?)

単に「アラインメント」と「パディング」の説明書き、だと思うのですが・・・。

struct xx {
   DWORD NumberOfPointers;
   PVOID Pointers[1];
};

NG:malloc(sizeof(DWORD)+100*sizeof(PVOID));
OK:malloc(FIELD_OFFSET(struct xx, Pointers) +100*sizeof(PVOID));

これって、単なる偶然(チョンボ?)の一致ですよね。だって、32ビットの「WORD」でも同じ問題が発生しますから。

そこで、32ビットでの構造体のアラインメントなどを確認するだけのサンプルを作ってみました。

尚、構造体のメンバを「あなた」が適切な順序で並べる事が出来れば、パディングを限り無く0に近付ける事が可能らしいです。


<注意点>

・構造体のサイズには、本来のサイズとアラインメント調整されたサイズとが有ります。

・構造体のアラインメントは、メンバのアラインメント最大値と同じ。

・Cコンパイラの構造体サイズは、メンバの中で最大サイズのアラインメントを整数倍した値と同じ。

・sizeof 演算子の戻り値は、構造体メンバのアラインメント最大値を整数倍に切り上げた値で、本来のサイズではありません。

・つまり、構造体の本来のサイズは電卓を叩けば分かります。アラインメント調整されたサイズは sizeof() を使えば直ぐ分かります。


【32ビット、構造体のアラインメントデータ】

アラインメント機能32ビット確認
構造体タグsizeofalignmentpadding
本来サイズ 出力結果 メンバ最大 構造体サイズ メンバ間 最終メンバの後
st01
st02
st03
st04 12 16 16
st05
st06 12 16 16
st07
st08
st09
st10 12 16 16
st11
st12 12 16 16
st13 12 12
st14 14 16 16
st15 20 24 24
st21
st22
st23 402 404 404
st24 404 404 404


お試し環境
  WindowsXP 32bit Edition、Windows7 64bit Edition
  Visual C++ 2008 cross x64、native x64


/*---- 32ビット ------------------- コマンドライン -----------------------*/

D:\vc2008\x86x64>cl test.c

/*----------------------------------------------------------------------------*/


/*---- 32ビットデータ -------------------- お試し結果 --------------------*/

D:\vc2008\x86x64>test
sizeof check
diz01 = 8, &diz01 = 0040E0A0, &diz01.no = 0040E0A0, diz01.dat = 0040E0A4
diz02 = 8, &diz02 = 0040E2F0, &diz02.no = 0040E2F0, diz02.dat = 0040E2F4
diz03 = 8, &diz03 = 0040DEE0, &diz03.no = 0040DEE0, diz03.dat = 0040DEE4
diz04 = 16, &diz04 = 0040E0F0, &diz04.no = 0040E0F0, diz04.dat = 0040E0F8
diz05 = 8, &diz05 = 0040E098, &diz05.no = 0040E098, diz05.dat = 0040E09C
diz06 = 16, &diz06 = 0040E0D0, &diz06.no = 0040E0D0, diz06.dat = 0040E0D8

padding check
diz07 = 8, &diz07 = 0040E0E8, diz07.dat = 0040E0E8, &diz07.no = 0040E0EC
diz08 = 8, &diz08 = 0040DEF0, diz08.dat = 0040DEF0, &diz08.no = 0040DEF4
diz09 = 8, &diz09 = 0040E0E0, diz09.dat = 0040E0E0, &diz09.no = 0040E0E4
diz10 = 16, &diz10 = 0040E110, diz10.dat = 0040E110, &diz10.no = 0040E118
diz11 = 8, &diz11 = 0040E138, diz11.dat = 0040E138, &diz11.no = 0040E13C
diz12 = 16, &diz12 = 0040E0C0, diz12.dat = 0040E0C0, &diz12.no = 0040E0C8

Alignment check
diz13 = 12, &diz13 = 0040E2E0, &diz13.no = 0040E2E0, diz13.dat = 0040E2E8
diz14 = 16, &diz14 = 0040E0B0, &diz14.no = 0040E0B0, diz14.dat = 0040E0BC
diz15 = 24, &diz15 = 0040E120, &diz15.no = 0040E120, diz15.dat = 0040E130

Arithmetic check
diz21 = 8, &diz21 = 0040DEE8, &diz21.no = 0040DEE8, diz21.ptr = 0040DEEC
diz22 = 8, &diz22 = 0040E100, &diz22.no = 0040E100, diz22.ptr = 0040E104
diz23 = 404, &diz23 = 0040DF00, &diz23.no = 0040DF00, diz23.ptr = 0040DF04
diz24 = 404, &diz24 = 0040E140, &diz24.no = 0040E140, diz24.ptr = 0040E144

sizeof(WORD) + 100 * sizeof(PVOID) = 402
sizeof(DWORD) + 100 * sizeof(PVOID) = 404
FIELD_OFFSET(struct st21, ptr) + 100 * sizeof(PVOID) = 404
FIELD_OFFSET(struct st22, ptr) + 100 * sizeof(PVOID) = 404

/*----------------------------------------------------------------------------*/


/*---- test.c ----------------------- お試しソース -------------------------*/

#include <stdio.h>
#include <windows.h>

// sizeof check
struct st01 {
    char no;
    void *dat[1];
} diz01;

struct st02 {
    short no;
    void *dat[1];
} diz02;

struct st03 {
    int no;
    void *dat[1];
} diz03;

struct st04 {
    long long no;
    void *dat[1];
} diz04;

struct st05 {
    float no;
    void *dat[1];
} diz05;

struct st06 {
    double no;
    void *dat[1];
} diz06;

// padding check
struct st07 {
    void *dat[1];
    char no;
} diz07;

struct st08 {
    void *dat[1];
    short no;
} diz08;

struct st09 {
    void *dat[1];
    int no;
} diz09;

struct st10 {
    void *dat[1];
    long long no;
} diz10;

struct st11 {
    void *dat[1];
    float no;
} diz11;

struct st12 {
    void *dat[1];
    double no;
} diz12;

// Alignment check
struct st13 {
    char no[5];
    void *dat[1];
} diz13;

struct st14 {
    short no[5];
    void *dat[1];
} diz14;

struct st15 {
    long long no[2];
    void *dat[1];
} diz15;

// Arithmetic check
struct st21 {
    WORD no;
    PVOID ptr[1];
} diz21;

struct st22 {
    DWORD no;
    PVOID ptr[1];
} diz22;

struct st23 {
    WORD no;
    PVOID ptr[100];
} diz23;

struct st24 {
    DWORD no;
    PVOID ptr[100];
} diz24;

int main(int argc, char *argv[])
{
    printf("sizeof check\n");
    printf("diz01 = %d, &diz01 = %p, &diz01.no = %p, diz01.dat = %p\n", sizeof(diz01), &diz01, &diz01.no, diz01.dat);
    printf("diz02 = %d, &diz02 = %p, &diz02.no = %p, diz02.dat = %p\n", sizeof(diz02), &diz02, &diz02.no, diz02.dat);
    printf("diz03 = %d, &diz03 = %p, &diz03.no = %p, diz03.dat = %p\n", sizeof(diz03), &diz03, &diz03.no, diz03.dat);
    printf("diz04 = %d, &diz04 = %p, &diz04.no = %p, diz04.dat = %p\n", sizeof(diz04), &diz04, &diz04.no, diz04.dat);
    printf("diz05 = %d, &diz05 = %p, &diz05.no = %p, diz05.dat = %p\n", sizeof(diz05), &diz05, &diz05.no, diz05.dat);
    printf("diz06 = %d, &diz06 = %p, &diz06.no = %p, diz06.dat = %p\n", sizeof(diz06), &diz06, &diz06.no, diz06.dat);

    printf("\npadding check\n");
    printf("diz07 = %d, &diz07 = %p, diz07.dat = %p, &diz07.no = %p\n", sizeof(diz07), &diz07, diz07.dat, &diz07.no);
    printf("diz08 = %d, &diz08 = %p, diz08.dat = %p, &diz08.no = %p\n", sizeof(diz08), &diz08, diz08.dat, &diz08.no);
    printf("diz09 = %d, &diz09 = %p, diz09.dat = %p, &diz09.no = %p\n", sizeof(diz09), &diz09, diz09.dat, &diz09.no);
    printf("diz10 = %d, &diz10 = %p, diz10.dat = %p, &diz10.no = %p\n", sizeof(diz10), &diz10, diz10.dat, &diz10.no);
    printf("diz11 = %d, &diz11 = %p, diz11.dat = %p, &diz11.no = %p\n", sizeof(diz11), &diz11, diz11.dat, &diz11.no);
    printf("diz12 = %d, &diz12 = %p, diz12.dat = %p, &diz12.no = %p\n", sizeof(diz12), &diz12, diz12.dat, &diz12.no);

    printf("\nAlignment check\n");
    printf("diz13 = %d, &diz13 = %p, &diz13.no = %p, diz13.dat = %p\n", sizeof(diz13), &diz13, &diz13.no, diz13.dat);
    printf("diz14 = %d, &diz14 = %p, &diz14.no = %p, diz14.dat = %p\n", sizeof(diz14), &diz14, &diz14.no, diz14.dat);
    printf("diz15 = %d, &diz15 = %p, &diz15.no = %p, diz15.dat = %p\n", sizeof(diz15), &diz15, &diz15.no, diz15.dat);

    printf("\nArithmetic check\n");
    printf("diz21 = %d, &diz21 = %p, &diz21.no = %p, diz21.ptr = %p\n", sizeof(diz21), &diz21, &diz21.no, diz21.ptr);
    printf("diz22 = %d, &diz22 = %p, &diz22.no = %p, diz22.ptr = %p\n", sizeof(diz22), &diz22, &diz22.no, diz22.ptr);
    printf("diz23 = %d, &diz23 = %p, &diz23.no = %p, diz23.ptr = %p\n", sizeof(diz23), &diz23, &diz23.no, diz23.ptr);
    printf("diz24 = %d, &diz24 = %p, &diz24.no = %p, diz24.ptr = %p\n", sizeof(diz24), &diz24, &diz24.no, diz24.ptr);

    printf("\n");
    printf("sizeof(WORD) + 100 * sizeof(PVOID) = %d\n", sizeof(WORD) + 100 * sizeof(PVOID));
    printf("sizeof(DWORD) + 100 * sizeof(PVOID) = %d\n", sizeof(DWORD) + 100 * sizeof(PVOID));

    printf("FIELD_OFFSET(struct st21, ptr) + 100 * sizeof(PVOID) = %d\n", FIELD_OFFSET(struct st21, ptr) + 100 * sizeof(PVOID));
    printf("FIELD_OFFSET(struct st22, ptr) + 100 * sizeof(PVOID) = %d\n", FIELD_OFFSET(struct st22, ptr) + 100 * sizeof(PVOID));
}

/*----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
/*============================================================================*/