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ビット、構造体のアラインメントデータ】
構造体タグ | sizeof | alignment | padding | |||
---|---|---|---|---|---|---|
本来サイズ | 出力結果 | メンバ最大 | 構造体サイズ | メンバ間 | 最終メンバの後 | |
st01 | 5 | 8 | 4 | 8 | 3 | 0 |
st02 | 6 | 8 | 4 | 8 | 2 | 0 |
st03 | 8 | 8 | 4 | 8 | 0 | 0 |
st04 | 12 | 16 | 8 | 16 | 0 | 4 |
st05 | 8 | 8 | 4 | 8 | 0 | 0 |
st06 | 12 | 16 | 8 | 16 | 0 | 4 |
st07 | 5 | 8 | 4 | 8 | 0 | 3 |
st08 | 6 | 8 | 4 | 8 | 0 | 2 |
st09 | 8 | 8 | 4 | 8 | 0 | 0 |
st10 | 12 | 16 | 8 | 16 | 4 | 0 |
st11 | 8 | 8 | 4 | 8 | 0 | 0 |
st12 | 12 | 16 | 8 | 16 | 4 | 0 |
st13 | 9 | 12 | 4 | 12 | 3 | 0 |
st14 | 14 | 16 | 4 | 16 | 2 | 0 |
st15 | 20 | 24 | 8 | 24 | 0 | 4 |
st21 | 6 | 8 | 4 | 8 | 2 | 0 |
st22 | 8 | 8 | 4 | 8 | 0 | 0 |
st23 | 402 | 404 | 4 | 404 | 2 | 0 |
st24 | 404 | 404 | 4 | 404 | 0 | 0 |
お試し環境
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));
}
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*============================================================================*/