微禄: 2021年3月アーカイブ

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

取り敢えず、64ビットでの構造体のアラインメントなどを確認するだけのサンプルも作ってみました。


<注意点>

・メモリ効率を上げてシステムのパフォーマンスを改善しようと「#pragma pack」などを使用すると、アラインメントがズレたメンバにアクセスする際に性能低下 *1 を引き起こしたり、最悪の場合バスエラー *2 が発生する恐れがあります。

・前回の32ビットとの違いは、st13~st15の配列の要素数のみです。

*1:インテルの場合、x86系(x64含む) *2:インテルの場合、Itanium系


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

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


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


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

D:\vc2008\x86x64>cl test.c

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


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

D:\vc2008\x86x64>test
sizeof check
diz01 = 16, &diz01 = 000000014000FB80, &diz01.no = 000000014000FB80, diz01.dat = 000000014000FB88
diz02 = 16, &diz02 = 000000014000FFE0, &diz02.no = 000000014000FFE0, diz02.dat = 000000014000FFE8
diz03 = 16, &diz03 = 000000014000F800, &diz03.no = 000000014000F800, diz03.dat = 000000014000F808
diz04 = 16, &diz04 = 000000014000FC00, &diz04.no = 000000014000FC00, diz04.dat = 000000014000FC08
diz05 = 16, &diz05 = 000000014000FB70, &diz05.no = 000000014000FB70, diz05.dat = 000000014000FB78
diz06 = 16, &diz06 = 000000014000FBD0, &diz06.no = 000000014000FBD0, diz06.dat = 000000014000FBD8

padding check
diz07 = 16, &diz07 = 000000014000FBF0, diz07.dat = 000000014000FBF0, &diz07.no = 000000014000FBF8
diz08 = 16, &diz08 = 000000014000F820, diz08.dat = 000000014000F820, &diz08.no = 000000014000F828
diz09 = 16, &diz09 = 000000014000FBE0, diz09.dat = 000000014000FBE0, &diz09.no = 000000014000FBE8
diz10 = 16, &diz10 = 000000014000FC20, diz10.dat = 000000014000FC20, &diz10.no = 000000014000FC28
diz11 = 16, &diz11 = 000000014000FC70, diz11.dat = 000000014000FC70, &diz11.no = 000000014000FC78
diz12 = 16, &diz12 = 000000014000FBC0, diz12.dat = 000000014000FBC0, &diz12.no = 000000014000FBC8

Alignment check
diz13 = 24, &diz13 = 000000014000FFC0, &diz13.no = 000000014000FFC0, diz13.dat = 000000014000FFD0
diz14 = 32, &diz14 = 000000014000FBA0, &diz14.no = 000000014000FBA0, diz14.dat = 000000014000FBB8
diz15 = 40, &diz15 = 000000014000FC40, &diz15.no = 000000014000FC40, diz15.dat = 000000014000FC60

Arithmetic check
diz21 = 16, &diz21 = 000000014000F810, &diz21.no = 000000014000F810, diz21.ptr = 000000014000F818
diz22 = 16, &diz22 = 000000014000FC10, &diz22.no = 000000014000FC10, diz22.ptr = 000000014000FC18
diz23 = 808, &diz23 = 000000014000F840, &diz23.no = 000000014000F840, diz23.ptr = 000000014000F848
diz24 = 808, &diz24 = 000000014000FC80, &diz24.no = 000000014000FC80, diz24.ptr = 000000014000FC88

sizeof(WORD) + 100 * sizeof(PVOID) = 802
sizeof(DWORD) + 100 * sizeof(PVOID) = 804
FIELD_OFFSET(struct st21, ptr) + 100 * sizeof(PVOID) = 808
FIELD_OFFSET(struct st22, ptr) + 100 * sizeof(PVOID) = 808

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


/*---- test.c ------------------- 64ビット お試しソース ------------------*/

#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[9];
    void *dat[1];
} diz13;

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

struct st15 {
    long long no[4];
    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));
}

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

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

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));
}

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

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

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

64ビット化に関して色々と検索していると、「移植に関する問題のチェックリスト」なるマイクロソフトドキュメントを見つけ、簡単そうな問題点を拾ってコンパイルするだけのサンプルを作ってみました。

ただ最近までは、配列の添え字の確からしさを含め処理する事が、プログラマの努めだった筈なのに? 添え字の"-1"って、普通のソフトウエアでは有り得ない?


<ポインタ算術演算の注意点>

①符号無しと符号付きの演算には注意

 この問題は x が符号無しのために発生します(式全体が符号無しになる)が、y が負の値でない限り成功します。
 64ビットの Windows では、この32ビットの符号無し負の値は、大きな64ビットの正の数値になり、間違った結果が得られます。
 (この問題を解決するには、x を符号付きの値として宣言するか、式を明示的に LONG 型にキャストします。と在りますが・・・)

②16進定数と符号無しの値を使用する場合には注意

 64ビットシステムでは、条件式は真に成りません。
 (UINT64)(TEST_SIZE - 1) = 0x0000000000000fff ⇒ ~((UINT_PTR)(TEST_SIZE - 1)) = 0xfffffffffffff000
 ~(TEST_SIZE - 1) = 0xfffff000        ⇒ (UINT_PTR)(~(TEST_SIZE - 1)) = 0x00000000fffff000

③NOT演算には注意

 この問題は、~(b - 1) が 0x0000 0000 xxxx xxxx を生成し、0xFFFF FFFF xxxx xxxx とは成らないことです。
 コンパイラはこれを検出しません。

④バッファサイズを計算する場合には注意

 ポインタの演算ではポインタをPCHARにキャストする。とありますが、

 何故これが移植に関する問題点に挙がっているのか、良く分かりません。8バイトどうしの減算結果が4バイトに収まる保証は無い、のは確かです。

 だとしても、32ビットでも当該事項が指摘されていないのが不可解です。バッファサイズと言うなら、"1"ではなく"4"ですよね?
 これも、プログラマとして想定内だと思うのですが・・・。

⑤64ビットの Windows では、0xFFFFFFFF は -1 と同じでは無いことに注意

 32ビット機の場合:p[index - 1] == p[0xffffffff] == p[-1]
 64ビット機の場合:p[index - 1] == p[0x00000000ffffffff] != p[-1]、(index が4バイトの時)

以上の様な説明書きが、ドキュメントに在りました。


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


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

D:\vc2008\x86x64>cl test32.c

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

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

D:\vc2008\x86x64>cl test64.c

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


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

D:\vc2008\x86x64>test32
①-1:pVar2 = 0012FF7C, pVar1 = 0012FF6C, y = 2, x = 3
①-2:pVar2 = 0012FF5C, pVar1 = 0012FF6C, y = -2, x = 3
②:Equal, ~((UINT_PTR)(TEST_SIZE - 1)) = 0xfffff000, (UINT_PTR)(~(TEST_SIZE - 1)) = 0xfffff000
③:a = 0x12141210
④:len = 0x1
⑤:Equal, p[index - 1] = 0, p[-1] = 0

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

/*---- そのまま64ビット化 --------------- お試し結果 ---------------------*/

D:\vc2008\x86x64>test64
①-1:pVar2 = 000000000012FEE0, pVar1 = 000000000012FED0, y = 2, x = 3
①-2:pVar2 = 000000040012FEC0, pVar1 = 000000000012FED0, y = -2, x = 3
②:NOT equal, ~((UINT_PTR)(TEST_SIZE - 1)) = 0xfffffffffffff000, (UINT_PTR)(~(TEST_SIZE - 1)) = 0xfffff000
③:a = 0x12141210
④:len = 0xffffffff
⑤:例外発生 ← コメント化
⑥:index - 1 = 0xffffffff, -1 = 0xffffffff

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

/*---- 手直し64ビット化 ----------------- お試し結果 ---------------------*/

D:\vc2008\x86x64>test64
①-1:pVar2 = 000000000012FED0, pVar1 = 000000000012FEC0, y = 2, x = 3
①-2:pVar2 = 000000040012FEB0, pVar1 = 000000000012FEC0, y = -2, x = 3
①-3:pVar2 = 000000000012FEB0, pVar1 = 000000000012FEC0, y = -2, x = 3
②:NOT equal, ~((UINT_PTR)(TEST_SIZE - 1)) = 0xfffffffffffff000, (UINT_PTR)(~(TEST_SIZE - 1)) = 0xfffff000
③:a = 0x9012141210
④:len = 0xfffffffc
⑤:Equal, p[index - 1] = 0, p[-1] = 0
⑥:index - 1 = 0xffffffffffffffff, -1 = 0xffffffff
⑦:ptr2 = 000000000012FEF8, ptr1 = 000000000012FEFC, ptr2 - ptr1 = FFFFFFFFFFFFFFFF

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


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

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

#define TEST_SIZE 0x1000UL

int main(char argc, char *argv[])
{
    ULONG x = 3;
    LONG y = 2;
    LONG z;
    LONG *pVar1 = &y;
    LONG *pVar2 = &z;

    UINT_PTR a = 0x12345678;
    ULONG b = 0xabcdef;

    LONG c;
    LONG d;
    ULONG len;
    LONG *ptr1 = &c;
    LONG *ptr2 = &d;

    DWORD index = 0;
    CHAR *p = "ABC";

    pVar2 = pVar1 + y * (x - 1);
    printf("\n①-1:pVar2 = %p, pVar1 = %p, y = %d, x = %d\n", pVar2, pVar1, y, x);
    y = -2;
    pVar2 = pVar1 + y * (x - 1);
    printf("①-2:pVar2 = %p, pVar1 = %p, y = %d, x = %d\n", pVar2, pVar1, y, x);

    if(~((UINT_PTR)(TEST_SIZE - 1)) == (UINT_PTR)(~(TEST_SIZE - 1))) { // warning C4127: 条件式が定数です。
        printf("②:Equal, ~((UINT_PTR)(TEST_SIZE - 1)) = %#x, (UINT_PTR)(~(TEST_SIZE - 1)) = %#x\n", ~((UINT_PTR)(TEST_SIZE - 1)), (UINT_PTR)(~(TEST_SIZE - 1)));
    } else {
        printf("②:NOT equal, ~((UINT_PTR)(TEST_SIZE - 1)) = %#llx, (UINT_PTR)(~(TEST_SIZE - 1)) = %#llx\n", ~((UINT_PTR)(TEST_SIZE - 1)), (UINT_PTR)(~(TEST_SIZE - 1)));
    }

    a = a & ~(b - 1);
    printf("③:a = %#x\n", a);

    len = ptr2 - ptr1;
    printf("④:len = %#x\n", len);

    if(p[index - 1] == p[-1]) {
        printf("⑤:Equal, p[index - 1] = %#x, p[-1] = %#x\n", p[index - 1], p[-1]); // On 32-bit machines : p[index-1] == p[0xffffffff] == p[-1]
    } else {
        printf("⑤:NOT equal, p[index - 1] = %#llx, p[-1] = %#llx\n", p[index - 1], p[-1]);
    }
}

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

/*---- test64.c --------------- そのまま64ビット化ソース -----------------*/

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

#define TEST_SIZE 0x1000UL

int main(char argc, char *argv[])
{
    ULONG x = 3;
    LONG y = 2;
    LONG z;
    LONG *pVar1 = &y;
    LONG *pVar2 = &z;

    UINT_PTR a = 0x9012345678;
    ULONG b = 0xabcdef;

    LONG c;
    LONG d;
    ULONG len;
    LONG *ptr1 = &c;
    LONG *ptr2 = &d;

    DWORD index = 0;
    CHAR *p = "ABC";

    pVar2 = pVar1 + y * (x - 1);
    printf("\n①-1:pVar2 = %p, pVar1 = %p, y = %d, x = %d\n", pVar2, pVar1, y, x);
    y = -2;
    pVar2 = pVar1 + y * (x - 1);
    printf("①-2:pVar2 = %p, pVar1 = %p, y = %d, x = %d\n", pVar2, pVar1, y, x);

    if(~((UINT_PTR)(TEST_SIZE - 1)) == (UINT_PTR)(~(TEST_SIZE - 1))) { // warning C4127: 条件式が定数です。
        printf("②:Equal, ~((UINT_PTR)(TEST_SIZE - 1)) = %#x, (UINT_PTR)(~(TEST_SIZE - 1)) = %#x\n", ~((UINT_PTR)(TEST_SIZE - 1)), (UINT_PTR)(~(TEST_SIZE - 1)));
    } else {
        printf("②:NOT equal, ~((UINT_PTR)(TEST_SIZE - 1)) = %#llx, (UINT_PTR)(~(TEST_SIZE - 1)) = %#llx\n", ~((UINT_PTR)(TEST_SIZE - 1)), (UINT_PTR)(~(TEST_SIZE - 1)));
    }

    a = a & ~(b - 1);
    printf("③:a = %#llx\n", a);

    len = ptr2 - ptr1; // warning C4242: '=' : '__int64' から 'ULONG' への変換です。データが失われる可能性があります。
    printf("④:len = %#x\n", len);
/*
    if(p[index - 1] == p[-1]) { // // causes access violation on 64-bit Windows!
        printf("⑤:Equal, p[index - 1] = %#x, p[-1] = %#x\n", p[index - 1], p[-1]);
    } else {
        printf("⑤:NOT equal, p[index - 1] = %#llx, p[-1] = %#llx\n", p[index - 1], p[-1]); // // On 64-bit machines : p[index-1] == p[0x00000000ffffffff] != p[-1]
    }
*/
    printf("⑥:index - 1 = %#llx, -1 = %#llx\n", index - 1, -1);
}

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

/*---- test64.c ---------------- 手直し64ビット化ソース ------------------*/

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

#define TEST_SIZE 0x1000UL

int main(char argc, char *argv[])
{
    ULONG x = 3;
    LONG y = 2;
    LONG z;
    LONG *pVar1 = &y;
    LONG *pVar2 = &z;

    UINT_PTR a = 0x9012345678;
    ULONG b = 0xabcdef;

    LONG c;
    LONG d;
    ULONG len;
    LONG *ptr1 = &c;
    LONG *ptr2 = &d;

    DWORD_PTR index = 0;
    CHAR *p = "ABC";

    pVar2 = pVar1 + y * (x - 1);
    printf("\n①-1:pVar2 = %p, pVar1 = %p, y = %d, x = %d\n", pVar2, pVar1, y, x);
    y = -2;
    pVar2 = pVar1 + y * (x - 1);
    printf("①-2:pVar2 = %p, pVar1 = %p, y = %d, x = %d\n", pVar2, pVar1, y, x);
    pVar2 = (LONG)(pVar1 + y * (x - 1)); // warning C4305: '型キャスト' : 'LONG *' から 'LONG' へ切り詰めます。warning C4047: '=' : 間接参照のレベルが 'LONG *' と 'LONG' で異なっています。
    printf("①-3:pVar2 = %p, pVar1 = %p, y = %d, x = %d\n", pVar2, pVar1, y, x);

    if(~((UINT_PTR)(TEST_SIZE - 1)) == (UINT_PTR)(~(TEST_SIZE - 1))) { // warning C4127: 条件式が定数です。
        printf("②:Equal, ~((UINT_PTR)(TEST_SIZE - 1)) = %#x, (UINT_PTR)(~(TEST_SIZE - 1)) = %#x\n", ~((UINT_PTR)(TEST_SIZE - 1)), (UINT_PTR)(~(TEST_SIZE - 1)));
    } else {
        printf("②:NOT equal, ~((UINT_PTR)(TEST_SIZE - 1)) = %#llx, (UINT_PTR)(~(TEST_SIZE - 1)) = %#llx\n", ~((UINT_PTR)(TEST_SIZE - 1)), (UINT_PTR)(~(TEST_SIZE - 1)));
    }

    a = a & ~((UINT_PTR)b - 1);
    printf("③:a = %#llx\n", a);

    len = (PCHAR)ptr2 - (PCHAR)ptr1; // warning C4242: '=' : '__int64' から 'ULONG' への変換です。データが失われる可能性があります。
    printf("④:len = %#x\n", len);

    if(p[index - 1] == p[-1]) {
        printf("⑤:Equal, p[index - 1] = %#x, p[-1] = %#x\n", p[index - 1], p[-1]);
    } else {
        printf("⑤:NOT equal, p[index - 1] = %#llx, p[-1] = %#llx\n", p[index - 1], p[-1]);
    }
    printf("⑥:index - 1 = %#llx, -1 = %#llx\n", index - 1, -1);

    printf("⑦:ptr2 = %p, ptr1 = %p, ptr2 - ptr1 = %p\n", ptr2, ptr1, ptr2 - ptr1);
}

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

64ビット化擬きの真似事の続きです。64ビットWindows環境で、「固定精度整数型」「ポインター精度整数型」「固定精度ポインター型」を含めたデータサイズをチェックするだけのサンプルを作ってみました。

★POINTER_32、POINTER_64 型は、有効に活用できる場面があるのか思い当たりませんが・・・。


<注意点>

・[再出]ボイド型ポインタ(void *、別名汎用ポインタ)の参照先変数への読み書きは出来ません。⇒「error C2100: 間接指定演算子 (*) の使い方が正しくありません。」

・[再出]マイクロソフトのドキュメントでは、HWND、HINSTANCE、HDC の3つともボイド型ポインタだろうと思うのですが、コンパイルエラーはそうではないと言っているようです(永遠にお手上げ?)。


【データモデルについて】

short や int やlong のデータサイズ、そしてポインタのサイズなどを、コンパイラ(やOS)の抽象化データモデルと呼ぶそうです。データモデルが変わるとデータサイズも必然的に変わってきます。

32ビットシステムでは一般的に、int, long, pointer のサイズが4バイトである事を示すILP32を採用しています。64ビットシステムではデータモデルが同一では無く、Windowsの場合はIL32P64(単にP64とも)と表現されるモデルを採用しています。

個人的には、Unix系のLP64モデルを好ましく思いますが、一部にはILP64モデルも存在します。int と long の2つ、無駄な感じがします。

Cコンパイラのデータモデル(ビット数)
データモデルcharshortintlonglong longpointer
C++標準  -  16以上 16以上 32以上 64以上  - 
ILP32(Win32) *1 16 32 32 64 32
P64(Win64) *2 16 32 32 64 64
LP64(macOS) *3 16 32 64 64 64

 *1:一般的な32ビット環境 *2:Windows64ビット環境でLLP64とも
 *3:Unix系全般


【64ビットWindows環境のデータ型一覧】

基本型
タイプ定義データ幅ポインタ幅
char 1バイト 8バイト
short 2バイト 8バイト
int 4バイト 8バイト
long 4バイト 8バイト

 「long long」型は不使用が良いかと

固定精度整数型
タイプ定義データ幅ポインタ幅
DWORD32 32ビット符号無し整数 4バイト 8バイト
DWORD64 64ビット符号無し整数 8バイト 8バイト
INT32 32ビット符号付き整数 4バイト 8バイト
UINT32 32ビット符号無し整数 4バイト 8バイト
INT64 64ビット符号付き整数 8バイト 8バイト
UINT64 64ビット符号無し整数 8バイト 8バイト
LONG32 32ビット符号付き整数 4バイト 8バイト
ULONG32 32ビット符号無し整数 4バイト 8バイト
LONG64 64ビット符号付き整数 8バイト 8バイト
ULONG64 64ビット符号無し整数 8バイト 8バイト

 

ポインタ精度整数型
タイプ定義データ幅ポインタ幅
DWORD_PTR ポインタ有効ビット数の符号無し整数 8バイト 8バイト
INT_PTR ポインタ有効ビット数の符号付き整数 8バイト 8バイト
UINT_PTR ポインタ有効ビット数の符号無し整数 8バイト 8バイト
LONG_PTR ポインタ有効ビット数の符号付き整数 8バイト 8バイト
ULONG_PTR ポインタ有効ビット数の符号無し整数 8バイト 8バイト
SIZE_T ポインタが参照できる符号無し最大バイト数 *1 8バイト 8バイト
SSIZE_T ポインタが参照できる符号付き最大バイト数 *1 8バイト 8バイト
HALF_PTR ポインタ有効ビット数半分の符号付き整数 *2 4バイト 8バイト
UHALF_PTR ポインタ有効ビット数半分の符号無し整数 *2 4バイト 8バイト

 *1:ポインタの範囲全体にまたがる必要があるカウントに使用。
 *2:32ビットシステムでは16ビット、64ビットシステムでは32ビット。

文字列型
タイプ定義データ幅ポインタ幅
PSTR 1バイト文字列のポインタ 1バイト 8バイト
LPSTR 1バイト文字列のポインタ 1バイト 8バイト
PCSTR 1バイト文字列のポインタ 1バイト 8バイト
LPCSTR 1バイト文字列のポインタ 1バイト 8バイト
PWSTR 2バイト文字列のポインタ *1 2バイト 8バイト
LPWSTR 2バイト文字列のポインタ *1 2バイト 8バイト
PCWSTR 2バイト文字列のポインタ *1 2バイト 8バイト
LPCWSTR 2バイト文字列のポインタ *1 2バイト 8バイト
PTSTR 1バイト文字列のポインタ 1バイト 8バイト
LPTSTR 1バイト文字列のポインタ 1バイト 8バイト
PCTSTR 1バイト文字列のポインタ 1バイト 8バイト
LPCTSTR 1バイト文字列のポインタ 1バイト 8バイト

 *1:UNICODE文字列に対応。

ウインドウ型
タイプ定義データ幅ポインタ幅
LPARAM ポインタ有効ビット数の符号付き整数 8バイト 8バイト
WPARAM ポインタ有効ビット数の符号付き整数 8バイト 8バイト
LRESULT ポインタ有効ビット数の符号付き整数 8バイト 8バイト
LPVOID ボイドのポインタ 無効 *1 8バイト
HANDLE ボイドのポインタ 無効 *1 8バイト
HWND ‐?‐ *2 無効? 8バイト
HINSTANCE ‐?‐ *2 無効? 8バイト
HDC ‐?‐ *2 無効? 8バイト

 *1:アクセス不可を示す。
 *2:'HWND__' 'HINSTANCE__' 'HDC__' は、今のところ(永久に?)不明、アクセス不可?

固定精度ポインタ型
タイプ定義データ幅ポインタ幅
POINTER_32 32ビットポインタ *1 指定サイズ依存 4バイト
POINTER_64 64ビットポインタ *2 指定サイズ依存 8バイト

 *1:32ビットシステムではネイティブポインタ、64ビットシステムでは切り捨てられた64ビットポインタ。
 *2:64ビットシステムではネイティブポインタ、32ビットシステムでは符号拡張32ビットポインタ。


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


/*---- 64ビットデータ型確認 ---------------- コマンドライン --------------*/

D:\vc2008\x86x64>cl test.c

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


/*-------------------------------- お試し結果 ------------------------------*/

D:\vc2008\x86x64>test
基本型
sizeof(a) = 1, sizeof(char *) = 8, a = 0x12
sizeof(b) = 2, sizeof(short *) = 8, b = 0x1234
sizeof(c) = 4, sizeof(int *) = 8, c = 0x12345678
sizeof(d) = 4, sizeof(long *) = 8, d = 0x12345678

固定精度整数型
sizeof(f) = 4, sizeof(DWORD32 *) = 8, f = 0x12345678
sizeof(g) = 8, sizeof(DWORD64 *) = 8, g = 0x1234567890abcdef
sizeof(h) = 4, sizeof(INT32 *) = 8, h = 0x12345678
sizeof(i) = 4, sizeof(UINT32 *) = 8, i = 0x12345678
sizeof(j) = 8, sizeof(INT64 *) = 8, j = 0x1234567890abcd12
sizeof(k) = 8, sizeof(UINT64 *) = 8, k = 0x1234567812345678
sizeof(l) = 4, sizeof(LONG32 *) = 8, l = 0x12345678
sizeof(m) = 4, sizeof(ULONG32 *) = 8, m = 0x12345678
sizeof(n) = 8, sizeof(LONG64 *) = 8, n = 0x1234567890ab1234
sizeof(o) = 8, sizeof(ULONG64 *) = 8, o = 0x1234567812345678

ポインタ精度整数型
sizeof(p) = 8, sizeof(DWORD_PTR *) = 8, p = 0x1234567890abcdef
sizeof(q) = 8, sizeof(INT_PTR *) = 8, q = 0x1234567890abcdef
sizeof(r) = 8, sizeof(UINT_PTR *) = 8, r = 0x1234567890abcdef
sizeof(s) = 8, sizeof(LONG_PTR *) = 8, s = 0x1234567890abcdef
sizeof(t) = 8, sizeof(ULONG_PTR *) = 8, t = 0x1234567890abcdef
sizeof(u) = 8, sizeof(SIZE_T *) = 8, u = 0x1234567890abcdef
sizeof(v) = 8, sizeof(SSIZE_T *) = 8, v = 0x1234567890abcdef
sizeof(w) = 4, sizeof(HALF_PTR *) = 8, w = 0x12345678
sizeof(x) = 4, sizeof(UHALF_PTR *) = 8, x = 0x12345678

文字列型
sizeof(*sa) = 1, sizeof(PSTR) = 8, *sa = 1
sizeof(*sb) = 1, sizeof(LPSTR) = 8, *sb = 2
sizeof(*sc) = 1, sizeof(PCSTR) = 8, *sc = A
sizeof(*sd) = 1, sizeof(LPCSTR) = 8, *sd = A
sizeof(*se) = 2, sizeof(PWSTR) = 8, *se = 3
sizeof(*sf) = 2, sizeof(LPWSTR) = 8, *sf = 4
sizeof(*sg) = 2, sizeof(PCWSTR) = 8, *sg = A
sizeof(*sh) = 2, sizeof(LPCWSTR) = 8, *sh = A
sizeof(*si) = 1, sizeof(PTSTR) = 8, *si = 5
sizeof(*sj) = 1, sizeof(LPTSTR) = 8, *sj = 6
sizeof(*sk) = 1, sizeof(PCTSTR) = 8, *sk = A
sizeof(*sl) = 1, sizeof(LPCTSTR) = 8, *sl = A

ウインドウ型
sizeof(wa) = 8, sizeof(LPARAM *) = 8, wa = 0x1234567890abcdef
sizeof(wb) = 8, sizeof(WPARAM *) = 8, wb = 0x1234567890abcdef
sizeof(wc) = 8, sizeof(LRESULT *) = 8, wc = 0x1234567890abcdef
sizeof(wd) = 8, sizeof(LPVOID *) = 8
sizeof(we) = 8, sizeof(HANDLE *) = 8
sizeof(wf) = 8, sizeof(HWND *) = 8
sizeof(wg) = 8, sizeof(HINSTANCE *) = 8
sizeof(wh) = 8, sizeof(HDC *) = 8

固定精度ポインタ型
sizeof(ya) = 4, sizeof(char *) = 8, *ya = 0x12
sizeof(yb) = 4, sizeof(int *) = 8, *yb = 0x12345678
sizeof(yc) = 4, sizeof(void *) = 8
sizeof(za) = 8, sizeof(short *) = 8, *za = 0x1234
sizeof(zb) = 8, sizeof(long *) = 8, *zb = 0x12345678
sizeof(zc) = 8, sizeof(void *) = 8

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


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

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

int main(int argc, char *argv[])
{
// 基本型
    char a = 0x12;
    short b = 0x1234;
    int c = 0x12345678;
    long d = 0x12345678;

// 固定精度整数型
    DWORD32 f = 0x12345678;
    DWORD64 g = 0x1234567890abcdef;
    INT32 h = 0x12345678;
    UINT32 i = 0x12345678;
    INT64 j = 0x1234567890abcdef;
    UINT64 k = 0x1234567890abcdef;
    LONG32 l = 0x12345678;
    ULONG32 m = 0x12345678;
    LONG64 n = 0x1234567890abcdef;
    ULONG64 o = 0x1234567890abcdef;

// ポインタ精度整数型
    DWORD_PTR p = 0x1234567890abcdef;
    INT_PTR q = 0x1234567890abcdef;
    UINT_PTR r = 0x1234567890abcdef;
    LONG_PTR s = 0x1234567890abcdef;
    ULONG_PTR t = 0x1234567890abcdef;
    SIZE_T u = 0x1234567890abcdef;
    SSIZE_T v = 0x1234567890abcdef;
    HALF_PTR w = 0x12345678;
    UHALF_PTR x = 0x12345678;

// 文字列型
    PSTR sa = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    LPSTR sb = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    PCSTR sc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    LPCSTR sd = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    PWSTR se = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    LPWSTR sf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    PCWSTR sg = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    LPCWSTR sh = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    PTSTR si = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    LPTSTR sj = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    PCTSTR sk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    LPCTSTR sl = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

// ウインドウ型
    LPARAM wa = 0x1234567890abcdef;
    WPARAM wb = 0x1234567890abcdef;
    LRESULT wc = 0x1234567890abcdef;
    LPVOID wd = (LPVOID)0x1234567890abcdef;
    HANDLE we = (HANDLE)0x1234567890abcdef;
    HWND wf = (HWND)0x1234567890abcdef;
    HINSTANCE wg = (HINSTANCE)0x1234567890abcdef;
    HDC wh = (HDC)0x1234567890abcdef;

// 固定精度ポインタ型
    char *POINTER_32 ya = (char *)0x1234567890abcdef; // warning C4244: '初期化中' : 'char *' から 'char *' への変換です。データが失われる可能性があります。
    int *POINTER_32 yb = (int *)0x1234567890abcdef;  // warning C4244: '初期化中' : 'int *' から 'int *' への変換です。データが失われる可能性があります。
    void *POINTER_32 yc = (void *)0x1234567890abcdef; // warning C4244: '初期化中' : 'void *' から 'void *' への変換です。データが失われる可能性があります。
    short *POINTER_64 za = (short *)0x1234567890abcdef;
    long *POINTER_64 zb = (long *)0x1234567890abcdef;
    void *POINTER_64 zc = (void *)0x1234567890abcdef;


// ウインドウ型チェック
    wd = &p;
    we = &q;
    wf = (HWND)&r;
    wg = (HINSTANCE)&s;
    wh = (HDC)&t;

//  *wd = 0x11; error C2100: 間接指定演算子 (*) の使い方が正しくありません。warning C4047: '=' : 間接参照のレベルが 'LPVOID' と 'int' で異なっています。
//  *we = 0x22; error C2100: 間接指定演算子 (*) の使い方が正しくありません。warning C4047: '=' : 間接参照のレベルが 'HANDLE' と 'int' で異なっています。
//  *wf = 0x33; error C2440: '=' : 'int' から 'HWND__' に変換できません。
//  *wg = 0x44; error C2440: '=' : 'int' から 'HINSTANCE__' に変換できません。
//  *wh = 0x55; error C2440: '=' : 'int' から 'HDC__' に変換できません。

// 固定精度ポインタ型チェック
    ya = (char *)&j; // warning C4244: '=' : 'char *' から 'char *' への変換です。データが失われる可能性があります。
    yb = (int *)&k; // warning C4244: '=' : 'int *' から 'int *' への変換です。データが失われる可能性があります。
    yc = &g;  // warning C4244: '=' : 'DWORD64 *' から 'void *' への変換です。データが失われる可能性があります。
    za = (short *)&n;
    zb = (long *)&o;
    zc = &g;

    *ya = 0x12;  // warning C4826: 'char *' から 'char *' への変換は符号拡張されています。これは、予期しない実行時の動作を発生させる可能性があります。
    *yb = 0x12345678; // warning C4826: 'int *' から 'int *' への変換は符号拡張されています。これは、予期しない実行時の動作を発生させる可能性があります。
//  *yc = 0x1234567890abcdef; error C2100: 間接指定演算子 (*) の使い方が正しくありません。warning C4047: '=' : 間接参照のレベルが 'void *' と '__int64' で異なっています。
    *za = 0x1234;
    *zb = 0x12345678;
//  *zc = 0x1234567890abcdef; error C2100: 間接指定演算子 (*) の使い方が正しくありません。warning C4047: '=' : 間接参照のレベルが 'void *' と '__int64' で異なっています。

// 文字列型チェック
    *sa = '1';
    *sb = '2';
//  *sc = '3'; error C2166: 左辺値は const オブジェクトに指定されています。
//  *sd = '4'; error C2166: 左辺値は const オブジェクトに指定されています。
    *se = '3';
    *sf = '4';
//  *sg = '7'; error C2166: 左辺値は const オブジェクトに指定されています。
//  *sh = '8'; error C2166: 左辺値は const オブジェクトに指定されています。
    *si = '5';
    *sj = '6';
//  *sk = '1'; error C2166: 左辺値は const オブジェクトに指定されています。
//  *sl = '2'; error C2166: 左辺値は const オブジェクトに指定されています。


// 基本型データ出力
    printf("基本型\n");
    printf("sizeof(a) = %d, sizeof(char *) = %d, a = %#x\n", sizeof(a), sizeof(char *), a);
    printf("sizeof(b) = %d, sizeof(short *) = %d, b = %#x\n", sizeof(b), sizeof(short *), b);
    printf("sizeof(c) = %d, sizeof(int *) = %d, c = %#x\n", sizeof(c), sizeof(int *), c);
    printf("sizeof(d) = %d, sizeof(long *) = %d, d = %#x\n", sizeof(d), sizeof(long *), d);

// 固定精度整数型データ出力
    printf("\n固定精度整数型\n");
    printf("sizeof(f) = %d, sizeof(DWORD32 *) = %d, f = %#x\n", sizeof(f), sizeof(DWORD32 *), f);
    printf("sizeof(g) = %d, sizeof(DWORD64 *) = %d, g = %#llx\n", sizeof(g), sizeof(DWORD64 *), g);
    printf("sizeof(h) = %d, sizeof(INT32 *) = %d, h = %#x\n", sizeof(h), sizeof(INT32 *), h);
    printf("sizeof(i) = %d, sizeof(UINT32 *) = %d, i = %#x\n", sizeof(i), sizeof(UINT32 *), i);
    printf("sizeof(j) = %d, sizeof(INT64 *) = %d, j = %#llx\n", sizeof(j), sizeof(INT64 *), j);
    printf("sizeof(k) = %d, sizeof(UINT64 *) = %d, k = %#llx\n", sizeof(k), sizeof(UINT64 *), k);
    printf("sizeof(l) = %d, sizeof(LONG32 *) = %d, l = %#x\n", sizeof(l), sizeof(LONG32 *), l);
    printf("sizeof(m) = %d, sizeof(ULONG32 *) = %d, m = %#x\n", sizeof(m), sizeof(ULONG32 *), m);
    printf("sizeof(n) = %d, sizeof(LONG64 *) = %d, n = %#llx\n", sizeof(n), sizeof(LONG64 *), n);
    printf("sizeof(o) = %d, sizeof(ULONG64 *) = %d, o = %#llx\n", sizeof(o), sizeof(ULONG64 *), o);

// ポインタ精度整数型データ出力
    printf("\nポインタ精度整数型\n");
    printf("sizeof(p) = %d, sizeof(DWORD_PTR *) = %d, p = %#llx\n", sizeof(p), sizeof(DWORD_PTR *), p);
    printf("sizeof(q) = %d, sizeof(INT_PTR *) = %d, q = %#llx\n", sizeof(q), sizeof(INT_PTR *), q);
    printf("sizeof(r) = %d, sizeof(UINT_PTR *) = %d, r = %#llx\n", sizeof(r), sizeof(UINT_PTR *), r);
    printf("sizeof(s) = %d, sizeof(LONG_PTR *) = %d, s = %#llx\n", sizeof(s), sizeof(LONG_PTR *), s);
    printf("sizeof(t) = %d, sizeof(ULONG_PTR *) = %d, t = %#llx\n", sizeof(t), sizeof(ULONG_PTR *), t);
    printf("sizeof(u) = %d, sizeof(SIZE_T *) = %d, u = %#llx\n", sizeof(u), sizeof(SIZE_T *), u);
    printf("sizeof(v) = %d, sizeof(SSIZE_T *) = %d, v = %#llx\n", sizeof(v), sizeof(SSIZE_T *), v);
    printf("sizeof(w) = %d, sizeof(HALF_PTR *) = %d, w = %#x\n", sizeof(w), sizeof(HALF_PTR *), w);
    printf("sizeof(x) = %d, sizeof(UHALF_PTR *) = %d, x = %#x\n", sizeof(x), sizeof(UHALF_PTR *), x);

// 文字列型データ出力
    printf("\n文字列型\n");
    printf("sizeof(*sa) = %d, sizeof(PSTR) = %d, *sa = %c\n", sizeof(*sa), sizeof(PSTR), *sa);
    printf("sizeof(*sb) = %d, sizeof(LPSTR) = %d, *sb = %c\n", sizeof(*sb), sizeof(LPSTR), *sb);
    printf("sizeof(*sc) = %d, sizeof(PCSTR) = %d, *sc = %c\n", sizeof(*sc), sizeof(PCSTR), *sc);
    printf("sizeof(*sd) = %d, sizeof(LPCSTR) = %d, *sd = %c\n", sizeof(*sd), sizeof(LPCSTR), *sd);
    printf("sizeof(*se) = %d, sizeof(PWSTR) = %d, *se = %c\n", sizeof(*se), sizeof(PWSTR), *se);
    printf("sizeof(*sf) = %d, sizeof(LPWSTR) = %d, *sf = %c\n", sizeof(*sf), sizeof(LPWSTR), *sf);
    printf("sizeof(*sg) = %d, sizeof(PCWSTR) = %d, *sg = %c\n", sizeof(*sg), sizeof(PCWSTR), *sg);
    printf("sizeof(*sh) = %d, sizeof(LPCWSTR) = %d, *sh = %c\n", sizeof(*sh), sizeof(LPCWSTR), *sh);
    printf("sizeof(*si) = %d, sizeof(PTSTR) = %d, *si = %c\n", sizeof(*si), sizeof(PTSTR), *si);
    printf("sizeof(*sj) = %d, sizeof(LPTSTR) = %d, *sj = %c\n", sizeof(*sj), sizeof(LPTSTR), *sj);
    printf("sizeof(*sk) = %d, sizeof(PCTSTR) = %d, *sk = %c\n", sizeof(*sk), sizeof(PCTSTR), *sk);
    printf("sizeof(*sl) = %d, sizeof(LPCTSTR) = %d, *sl = %c\n", sizeof(*sl), sizeof(LPCTSTR), *sl);

// ウインドウ型データ出力
    printf("\nウインドウ型\n");
    printf("sizeof(wa) = %d, sizeof(LPARAM *) = %d, wa = %#llx\n", sizeof(wa), sizeof(LPARAM *), wa);
    printf("sizeof(wb) = %d, sizeof(WPARAM *) = %d, wb = %#llx\n", sizeof(wb), sizeof(WPARAM *), wb);
    printf("sizeof(wc) = %d, sizeof(LRESULT *) = %d, wc = %#llx\n", sizeof(wc), sizeof(LRESULT *), wc);
    printf("sizeof(wd) = %d, sizeof(LPVOID *) = %d\n", sizeof(wd), sizeof(LPVOID *));
    printf("sizeof(we) = %d, sizeof(HANDLE *) = %d\n", sizeof(we), sizeof(HANDLE *));
    printf("sizeof(wf) = %d, sizeof(HWND *) = %d\n", sizeof(wf), sizeof(HWND *));
    printf("sizeof(wg) = %d, sizeof(HINSTANCE *) = %d\n", sizeof(wg), sizeof(HINSTANCE *));
    printf("sizeof(wh) = %d, sizeof(HDC *) = %d\n", sizeof(wh), sizeof(HDC *));

// 固定精度ポインタ型データ出力
    printf("\n固定精度ポインタ型\n");
    printf("sizeof(ya) = %d, sizeof(char *) = %d, *ya = %#x\n", sizeof(ya), sizeof(char *), *ya); // warning C4826: 'char *' から 'char *' への変換は符号拡張されています。これは、予期しない実行時の動作を発生させる可能性があります。
    printf("sizeof(yb) = %d, sizeof(int *) = %d, *yb = %#x\n", sizeof(yb), sizeof(int *), *yb);  // warning C4826: 'int *' から 'int *' への変換は符号拡張されています。これは、予期しない実行時の動作を発生させる可能性があります。
//  printf("sizeof(yc) = %d, sizeof(void *) = %d, *yc = %d\n", sizeof(yc), sizeof(void *), *yc); error C2100: 間接指定演算子 (*) の使い方が正しくありません。
    printf("sizeof(yc) = %d, sizeof(void *) = %d\n", sizeof(yc), sizeof(void *));
    printf("sizeof(za) = %d, sizeof(short *) = %d, *za = %#x\n", sizeof(za), sizeof(short *), *za);
    printf("sizeof(zb) = %d, sizeof(long *) = %d, *zb = %#x\n", sizeof(zb), sizeof(long *), *zb);
//  printf("sizeof(zc) = %d, sizeof(void *) = %d, *zc = %d\n", sizeof(zc), sizeof(void *), *zc); error C2100: 間接指定演算子 (*) の使い方が正しくありません。
    printf("sizeof(zc) = %d, sizeof(void *) = %d\n", sizeof(zc), sizeof(void *));

    return(0);
}

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

昨年末からの煽られたコロナ禍で、再度の非常事態宣言。暇が有り過ぎて、64ビット化擬きの真似事をしてみる事に。

だけど、ハードやOSはとっくに64ビット化して10年以上経つのに、64ビットアプリケーションってMSオフィス以外殆ど存在しない状況? だったりして。

なんたって仮想マシンWOW64(Windows 32 On Windows 64)の出来が良過ぎたのか? それとも一般には未だに32ビットアプリで十分なのか? いやいや特殊職以外64ビットアプリなんて抑々不必要?

そんなこんなで、ウィキペディアで64ビットの項目を読んでみると、何とも驚いた事に!

C言語およびC++では、char型を除く組み込みの整数型(short型やint型、long型)は、最低限のビット数や大小関係しか規定していない。C99規格およびC++11規格では、int32_t や int64_t などビット数を規定した固定幅整数型(stdint.h および cstdint にて定義される)を追加し、また64ビット以上の値を表現できることが保証されるlong long型を追加した。

まったくぅ、だからC++は愛想を尽かされるんだよ。基本データ型のサイズ位さっさと規定しろよ! って言いたくなりますよね?

更には、プログラマはしばしば、ポインタとint或いはlongが同じ大きさであるという前提でコードを書いてきた問題があります、と。
つまり、多くのコードが32ビット環境を前提として書かれてきたため、64ビット環境ではこの仮定が度々問題を引き起こす可能性が有りますよ。

そんな訳で先ずは、32ビットWindows環境のデータサイズを確認しようとしたところ、以前の「Windowsプログラムのいろはは、DOS窓でWin32API」で書いたように、素人には64ビット化は任せられないとマイクロソフトが想定したかどうかは分かりませんが、Windows環境に「固定精度整数型」「ポインター精度整数型」「固定精度ポインター型」という3つの新しいデータ型を追加していました。

これらのデータ型を使用すると、64ビット化の準備を整えることが出来るそうです。試しに、これらを含めたデータサイズをチェックするだけのサンプルを作ってみました。


<注意点>

・固定精度整数型は、32ビット用と64ビット用のプログラムで同じ長さ(サイズ)に成ります。

・ポインター精度整数型は、32ビット用にコンパイルされれば32ビット長に、64ビット用にコンパイルされれば64ビット長になります。

・固定精度ポインター型は、長さを32ビットまたは64ビットに明示的に指定します。

・ボイド型ポインタ(void *、別名汎用ポインタ)の参照先変数への読み書きは出来ません。⇒「error C2100: 間接指定演算子 (*) の使い方が正しくありません。」

・POINTER_32、POINTER_64 の型に long long や double なども指定可能だと思いますが、確かめていません。

・マイクロソフトのドキュメントには、新しいデータ型を採用する事で、コードの堅牢性が向上します。(コードを)安全にするには、新しいデータ型を使用します。とあります。

・ドキュメントでは、HWND、HINSTANCE、HDC の3つもボイド型ポインタだろうと思うのですが、コンパイルエラーはそうではないと言っているような(永遠にお手上げ?)。


【32ビットWindows環境のデータ型一覧】

基本型
タイプ定義データ幅ポインタ幅
char 1バイト 4バイト
short 2バイト 4バイト
int 4バイト 4バイト
long 4バイト 4バイト

 「long long」型は不使用が良いかと

固定精度整数型
タイプ定義データ幅ポインタ幅
DWORD32 32ビット符号無し整数 4バイト 4バイト
DWORD64 64ビット符号無し整数 8バイト 4バイト
INT32 32ビット符号付き整数 4バイト 4バイト
UINT32 32ビット符号無し整数 4バイト 4バイト
INT64 64ビット符号付き整数 8バイト 4バイト
UINT64 64ビット符号無し整数 8バイト 4バイト
LONG32 32ビット符号付き整数 4バイト 4バイト
ULONG32 32ビット符号無し整数 4バイト 4バイト
LONG64 64ビット符号付き整数 8バイト 4バイト
ULONG64 64ビット符号無し整数 8バイト 4バイト

 

ポインタ精度整数型
タイプ定義データ幅ポインタ幅
DWORD_PTR ポインタ有効ビット数の符号無し整数 4バイト 4バイト
INT_PTR ポインタ有効ビット数の符号付き整数 4バイト 4バイト
UINT_PTR ポインタ有効ビット数の符号無し整数 4バイト 4バイト
LONG_PTR ポインタ有効ビット数の符号付き整数 4バイト 4バイト
ULONG_PTR ポインタ有効ビット数の符号無し整数 4バイト 4バイト
SIZE_T ポインタが参照できる符号無し最大バイト数 *1 4バイト 4バイト
SSIZE_T ポインタが参照できる符号付き最大バイト数 *1 4バイト 4バイト
HALF_PTR ポインタ有効ビット数半分の符号付き整数 *2 2バイト 4バイト
UHALF_PTR ポインタ有効ビット数半分の符号無し整数 *2 2バイト 4バイト

 *1:ポインタの範囲全体にまたがる必要があるカウントに使用。
 *2:32ビットシステムでは16ビット、64ビットシステムでは32ビット。

文字列型
タイプ定義データ幅ポインタ幅
PSTR 1バイト文字列のポインタ 1バイト 4バイト
LPSTR 1バイト文字列のポインタ 1バイト 4バイト
PCSTR 1バイト文字列のポインタ 1バイト 4バイト
LPCSTR 1バイト文字列のポインタ 1バイト 4バイト
PWSTR 2バイト文字列のポインタ *1 2バイト 4バイト
LPWSTR 2バイト文字列のポインタ *1 2バイト 4バイト
PCWSTR 2バイト文字列のポインタ *1 2バイト 4バイト
LPCWSTR 2バイト文字列のポインタ *1 2バイト 4バイト
PTSTR 1バイト文字列のポインタ 1バイト 4バイト
LPTSTR 1バイト文字列のポインタ 1バイト 4バイト
PCTSTR 1バイト文字列のポインタ 1バイト 4バイト
LPCTSTR 1バイト文字列のポインタ 1バイト 4バイト

 *1:UNICODE文字列に対応。

ウインドウ型
タイプ定義データ幅ポインタ幅
LPARAM ポインタ有効ビット数の符号付き整数 4バイト 4バイト
WPARAM ポインタ有効ビット数の符号付き整数 4バイト 4バイト
LRESULT ポインタ有効ビット数の符号付き整数 4バイト 4バイト
LPVOID ボイドのポインタ 無効 *1 4バイト
HANDLE ボイドのポインタ 無効 *1 4バイト
HWND ‐?‐ *2 無効? 4バイト
HINSTANCE ‐?‐ *2 無効? 4バイト
HDC ‐?‐ *2 無効? 4バイト

 *1:アクセス不可を示す。
 *2:'HWND__' 'HINSTANCE__' 'HDC__' は、今のところ(永久に?)不明、アクセス不可?

固定精度ポインタ型
タイプ定義データ幅ポインタ幅
POINTER_32 32ビットポインタ *1 指定サイズ依存 4バイト
POINTER_64 64ビットポインタ *2 *3 指定サイズ依存 8バイト

 *1:32ビットシステムではネイティブポインタ、64ビットシステムでは切り捨てられた64ビットポインタ。
 *2:64ビットシステムではネイティブポインタ、32ビットシステムでは符号拡張32ビットポインタ。
 *3:32ビットシステムでは上位ポインタのビット状態を想定するのは安全ではありません。


お試し環境
  WindowsXP 32bit Edition
  Visual C++ 2008


/*---- 32ビットデータ型確認 ---------------- コマンドライン --------------*/

D:\vc2008\x86x64>cl test.c

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


/*-------------------------------- お試し結果 ------------------------------*/

D:\vc2008\x86x64>test
基本型
sizeof(a) = 1, sizeof(char *) = 4, a = 0x12
sizeof(b) = 2, sizeof(short *) = 4, b = 0x1234
sizeof(c) = 4, sizeof(int *) = 4, c = 0x12345678
sizeof(d) = 4, sizeof(long *) = 4, d = 0x12345678

固定精度整数型
sizeof(f) = 4, sizeof(DWORD32 *) = 4, f = 0x12345678
sizeof(g) = 8, sizeof(DWORD64 *) = 4, g = 0x1234567890abcdef
sizeof(h) = 4, sizeof(INT32 *) = 4, h = 0x12345678
sizeof(i) = 4, sizeof(UINT32 *) = 4, i = 0x12345678
sizeof(j) = 8, sizeof(INT64 *) = 4, j = 0x1234567890abcd12
sizeof(k) = 8, sizeof(UINT64 *) = 4, k = 0x1234567812345678
sizeof(l) = 4, sizeof(LONG32 *) = 4, l = 0x12345678
sizeof(m) = 4, sizeof(ULONG32 *) = 4, m = 0x12345678
sizeof(n) = 8, sizeof(LONG64 *) = 4, n = 0x1234567890ab1234
sizeof(o) = 8, sizeof(ULONG64 *) = 4, o = 0x1234567812345678

ポインタ精度整数型
sizeof(p) = 4, sizeof(DWORD_PTR *) = 4, p = 0x12345678
sizeof(q) = 4, sizeof(INT_PTR *) = 4, q = 0x12345678
sizeof(r) = 4, sizeof(UINT_PTR *) = 4, r = 0x12345678
sizeof(s) = 4, sizeof(LONG_PTR *) = 4, s = 0x12345678
sizeof(t) = 4, sizeof(ULONG_PTR *) = 4, t = 0x12345678
sizeof(u) = 4, sizeof(SIZE_T *) = 4, u = 0x12345678
sizeof(v) = 4, sizeof(SSIZE_T *) = 4, v = 0x12345678
sizeof(w) = 2, sizeof(HALF_PTR *) = 4, w = 0x1234
sizeof(x) = 2, sizeof(UHALF_PTR *) = 4, x = 0x1234

文字列型
sizeof(*sa) = 1, sizeof(PSTR) = 4, *sa = 1
sizeof(*sb) = 1, sizeof(LPSTR) = 4, *sb = 2
sizeof(*sc) = 1, sizeof(PCSTR) = 4, *sc = A
sizeof(*sd) = 1, sizeof(LPCSTR) = 4, *sd = A
sizeof(*se) = 2, sizeof(PWSTR) = 4, *se = 3
sizeof(*sf) = 2, sizeof(LPWSTR) = 4, *sf = 4
sizeof(*sg) = 2, sizeof(PCWSTR) = 4, *sg = A
sizeof(*sh) = 2, sizeof(LPCWSTR) = 4, *sh = A
sizeof(*si) = 1, sizeof(PTSTR) = 4, *si = 5
sizeof(*sj) = 1, sizeof(LPTSTR) = 4, *sj = 6
sizeof(*sk) = 1, sizeof(PCTSTR) = 4, *sk = A
sizeof(*sl) = 1, sizeof(LPCTSTR) = 4, *sl = A

ウインドウ型
sizeof(wa) = 4, sizeof(LPARAM *) = 4, wa = 0x12345678
sizeof(wb) = 4, sizeof(WPARAM *) = 4, wb = 0x12345678
sizeof(wc) = 4, sizeof(LRESULT *) = 4, wc = 0x12345678
sizeof(wd) = 4, sizeof(LPVOID *) = 4
sizeof(we) = 4, sizeof(HANDLE *) = 4
sizeof(wf) = 4, sizeof(HWND *) = 4
sizeof(wg) = 4, sizeof(HINSTANCE *) = 4
sizeof(wh) = 4, sizeof(HDC *) = 4

固定精度ポインタ型
sizeof(ya) = 4, sizeof(char *) = 4, *ya = 0x12
sizeof(yb) = 4, sizeof(int *) = 4, *yb = 0x12345678
sizeof(yc) = 4, sizeof(void *) = 4
sizeof(za) = 8, sizeof(short *) = 4, *za = 0x1234
sizeof(zb) = 8, sizeof(long *) = 4, *zb = 0x12345678
sizeof(zc) = 8, sizeof(void *) = 4

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


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

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

int main(int argc, char *argv[])
{
// 基本型
    char a = 0x12;
    short b = 0x1234;
    int c = 0x12345678;
    long d = 0x12345678;

// 固定精度整数型
    DWORD32 f = 0x12345678;
    DWORD64 g = 0x1234567890abcdef;
    INT32 h = 0x12345678;
    UINT32 i = 0x12345678;
    INT64 j = 0x1234567890abcdef;
    UINT64 k = 0x1234567890abcdef;
    LONG32 l = 0x12345678;
    ULONG32 m = 0x12345678;
    LONG64 n = 0x1234567890abcdef;
    ULONG64 o = 0x1234567890abcdef;

// ポインタ精度整数型
    DWORD_PTR p = 0x12345678;
    INT_PTR q = 0x12345678;
    UINT_PTR r = 0x12345678;
    LONG_PTR s = 0x12345678;
    ULONG_PTR t = 0x12345678;
    SIZE_T u = 0x12345678;
    SSIZE_T v = 0x12345678;
    HALF_PTR w = 0x1234;
    UHALF_PTR x = 0x1234;

// 文字列型
    PSTR sa = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    LPSTR sb = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    PCSTR sc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    LPCSTR sd = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    PWSTR se = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    LPWSTR sf = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    PCWSTR sg = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    LPCWSTR sh = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    PTSTR si = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    LPTSTR sj = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    PCTSTR sk = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    LPCTSTR sl = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

// ウインドウ型
    LPARAM wa = 0x12345678;
    WPARAM wb = 0x12345678;
    LRESULT wc = 0x12345678;
    LPVOID wd = (LPVOID)0x12345678;
    HANDLE we = (HANDLE)0x12345678;
    HWND wf = (HWND)0x12345678;
    HINSTANCE wg = (HINSTANCE)0x12345678;
    HDC wh = (HDC)0x12345678;

// 固定精度ポインタ型
    char *POINTER_32 ya = (char *)0x12345678;
    int *POINTER_32 yb = (int *)0x12345678;
    void *POINTER_32 yc = (void *)0x12345678;
    short *POINTER_64 za = (short *)0x12345678; // warning C4826: 'short *' から 'short *' への変換は符号拡張されています。これは、予期しない実行時の動作を発生させる可能性があります。
    long *POINTER_64 zb = (long *)0x12345678; // warning C4826: 'long *' から 'long *' への変換は符号拡張されています。これは、予期しない実行時の動作を発生させる可能性があります。
    void *POINTER_64 zc = (void *)0x12345678; // warning C4826: 'void *' から 'void *' への変換は符号拡張されています。これは、予期しない実行時の動作を発生させる可能性があります。


// ウインドウ型チェック
    wd = &p;
    we = &q;
    wf = (HWND)&r;
    wg = (HINSTANCE)&s;
    wh = (HDC)&t;

//  *wd = 0x11; error C2100: 間接指定演算子 (*) の使い方が正しくありません。
//  *we = 0x22; error C2100: 間接指定演算子 (*) の使い方が正しくありません。
//  *wf = 0x33; error C2440: '=' : 'int' から 'HWND__' に変換できません。
//  *wg = 0x44; error C2440: '=' : 'int' から 'HINSTANCE__' に変換できません。
//  *wh = 0x55; error C2440: '=' : 'int' から 'HDC__' に変換できません。

// 固定精度ポインタ型チェック
    ya = (char *)&j;
    yb = (int *)&k;
    yc = &g;
    za = (short *)&n; // warning C4826: 'short *' から 'short *' への変換は符号拡張されています。これは、予期しない実行時の動作を発生させる可能性があります。
    zb = (long *)&o; // warning C4826: 'long *' から 'long *' への変換は符号拡張されています。これは、予期しない実行時の動作を発生させる可能性があります。
    zc = &g; // warning C4826: 'DWORD64 *' から 'void *' への変換は符号拡張されています。これは、予期しない実行時の動作を発生させる可能性があります。

    *ya = 0x12;
    *yb = 0x12345678;
//  *yc = 0x1234567890abcdef; error C2100: 間接指定演算子 (*) の使い方が正しくありません。
    *za = 0x1234;
    *zb = 0x12345678;
//  *zc = 0x1234567890abcdef; error C2100: 間接指定演算子 (*) の使い方が正しくありません。

// 文字列型チェック
    *sa = '1';
    *sb = '2';
//  *sc = '3'; error C2166: 左辺値は const オブジェクトに指定されています。
//  *sd = '4'; error C2166: 左辺値は const オブジェクトに指定されています。
    *se = '3';
    *sf = '4';
//  *sg = '7'; error C2166: 左辺値は const オブジェクトに指定されています。
//  *sh = '8'; error C2166: 左辺値は const オブジェクトに指定されています。
    *si = '5';
    *sj = '6';
//  *sk = '1'; error C2166: 左辺値は const オブジェクトに指定されています。
//  *sl = '2'; error C2166: 左辺値は const オブジェクトに指定されています。


// 基本型データ出力
    printf("基本型\n");
    printf("sizeof(a) = %d, sizeof(char *) = %d, a = %#x\n", sizeof(a), sizeof(char *), a);
    printf("sizeof(b) = %d, sizeof(short *) = %d, b = %#x\n", sizeof(b), sizeof(short *), b);
    printf("sizeof(c) = %d, sizeof(int *) = %d, c = %#x\n", sizeof(c), sizeof(int *), c);
    printf("sizeof(d) = %d, sizeof(long *) = %d, d = %#x\n", sizeof(d), sizeof(long *), d);

// 固定精度整数型データ出力
    printf("\n固定精度整数型\n");
    printf("sizeof(f) = %d, sizeof(DWORD32 *) = %d, f = %#x\n", sizeof(f), sizeof(DWORD32 *), f);
    printf("sizeof(g) = %d, sizeof(DWORD64 *) = %d, g = %#llx\n", sizeof(g), sizeof(DWORD64 *), g);
    printf("sizeof(h) = %d, sizeof(INT32 *) = %d, h = %#x\n", sizeof(h), sizeof(INT32 *), h);
    printf("sizeof(i) = %d, sizeof(UINT32 *) = %d, i = %#x\n", sizeof(i), sizeof(UINT32 *), i);
    printf("sizeof(j) = %d, sizeof(INT64 *) = %d, j = %#llx\n", sizeof(j), sizeof(INT64 *), j);
    printf("sizeof(k) = %d, sizeof(UINT64 *) = %d, k = %#llx\n", sizeof(k), sizeof(UINT64 *), k);
    printf("sizeof(l) = %d, sizeof(LONG32 *) = %d, l = %#x\n", sizeof(l), sizeof(LONG32 *), l);
    printf("sizeof(m) = %d, sizeof(ULONG32 *) = %d, m = %#x\n", sizeof(m), sizeof(ULONG32 *), m);
    printf("sizeof(n) = %d, sizeof(LONG64 *) = %d, n = %#llx\n", sizeof(n), sizeof(LONG64 *), n);
    printf("sizeof(o) = %d, sizeof(ULONG64 *) = %d, o = %#llx\n", sizeof(o), sizeof(ULONG64 *), o);

// ポインタ精度整数型データ出力
    printf("\nポインタ精度整数型\n");
    printf("sizeof(p) = %d, sizeof(DWORD_PTR *) = %d, p = %#x\n", sizeof(p), sizeof(DWORD_PTR *), p);
    printf("sizeof(q) = %d, sizeof(INT_PTR *) = %d, q = %#x\n", sizeof(q), sizeof(INT_PTR *), q);
    printf("sizeof(r) = %d, sizeof(UINT_PTR *) = %d, r = %#x\n", sizeof(r), sizeof(UINT_PTR *), r);
    printf("sizeof(s) = %d, sizeof(LONG_PTR *) = %d, s = %#x\n", sizeof(s), sizeof(LONG_PTR *), s);
    printf("sizeof(t) = %d, sizeof(ULONG_PTR *) = %d, t = %#x\n", sizeof(t), sizeof(ULONG_PTR *), t);
    printf("sizeof(u) = %d, sizeof(SIZE_T *) = %d, u = %#x\n", sizeof(u), sizeof(SIZE_T *), u);
    printf("sizeof(v) = %d, sizeof(SSIZE_T *) = %d, v = %#x\n", sizeof(v), sizeof(SSIZE_T *), v);
    printf("sizeof(w) = %d, sizeof(HALF_PTR *) = %d, w = %#x\n", sizeof(w), sizeof(HALF_PTR *), w);
    printf("sizeof(x) = %d, sizeof(UHALF_PTR *) = %d, x = %#x\n", sizeof(x), sizeof(UHALF_PTR *), x);

// 文字列型データ出力
    printf("\n文字列型\n");
    printf("sizeof(*sa) = %d, sizeof(PSTR) = %d, *sa = %c\n", sizeof(*sa), sizeof(PSTR), *sa);
    printf("sizeof(*sb) = %d, sizeof(LPSTR) = %d, *sb = %c\n", sizeof(*sb), sizeof(LPSTR), *sb);
    printf("sizeof(*sc) = %d, sizeof(PCSTR) = %d, *sc = %c\n", sizeof(*sc), sizeof(PCSTR), *sc);
    printf("sizeof(*sd) = %d, sizeof(LPCSTR) = %d, *sd = %c\n", sizeof(*sd), sizeof(LPCSTR), *sd);
    printf("sizeof(*se) = %d, sizeof(PWSTR) = %d, *se = %c\n", sizeof(*se), sizeof(PWSTR), *se);
    printf("sizeof(*sf) = %d, sizeof(LPWSTR) = %d, *sf = %c\n", sizeof(*sf), sizeof(LPWSTR), *sf);
    printf("sizeof(*sg) = %d, sizeof(PCWSTR) = %d, *sg = %c\n", sizeof(*sg), sizeof(PCWSTR), *sg);
    printf("sizeof(*sh) = %d, sizeof(LPCWSTR) = %d, *sh = %c\n", sizeof(*sh), sizeof(LPCWSTR), *sh);
    printf("sizeof(*si) = %d, sizeof(PTSTR) = %d, *si = %c\n", sizeof(*si), sizeof(PTSTR), *si);
    printf("sizeof(*sj) = %d, sizeof(LPTSTR) = %d, *sj = %c\n", sizeof(*sj), sizeof(LPTSTR), *sj);
    printf("sizeof(*sk) = %d, sizeof(PCTSTR) = %d, *sk = %c\n", sizeof(*sk), sizeof(PCTSTR), *sk);
    printf("sizeof(*sl) = %d, sizeof(LPCTSTR) = %d, *sl = %c\n", sizeof(*sl), sizeof(LPCTSTR), *sl);

// ウインドウ型データ出力
    printf("\nウインドウ型\n");
    printf("sizeof(wa) = %d, sizeof(LPARAM *) = %d, wa = %#x\n", sizeof(wa), sizeof(LPARAM *), wa);
    printf("sizeof(wb) = %d, sizeof(WPARAM *) = %d, wb = %#x\n", sizeof(wb), sizeof(WPARAM *), wb);
    printf("sizeof(wc) = %d, sizeof(LRESULT *) = %d, wc = %#x\n", sizeof(wc), sizeof(LRESULT *), wc);
    printf("sizeof(wd) = %d, sizeof(LPVOID *) = %d\n", sizeof(wd), sizeof(LPVOID *));
    printf("sizeof(we) = %d, sizeof(HANDLE *) = %d\n", sizeof(we), sizeof(HANDLE *));
    printf("sizeof(wf) = %d, sizeof(HWND *) = %d\n", sizeof(wf), sizeof(HWND *));
    printf("sizeof(wg) = %d, sizeof(HINSTANCE *) = %d\n", sizeof(wg), sizeof(HINSTANCE *));
    printf("sizeof(wh) = %d, sizeof(HDC *) = %d\n", sizeof(wh), sizeof(HDC *));

// 固定精度ポインタ型データ出力
    printf("\n固定精度ポインタ型\n");
    printf("sizeof(ya) = %d, sizeof(char *) = %d, *ya = %#x\n", sizeof(ya), sizeof(char *), *ya);
    printf("sizeof(yb) = %d, sizeof(int *) = %d, *yb = %#x\n", sizeof(yb), sizeof(int *), *yb);
//  printf("sizeof(yc) = %d, sizeof(void *) = %d, *yc = %d\n", sizeof(yc), sizeof(void *), *yc); error C2100: 間接指定演算子 (*) の使い方が正しくありません。
    printf("sizeof(yc) = %d, sizeof(void *) = %d\n", sizeof(yc), sizeof(void *));
    printf("sizeof(za) = %d, sizeof(short *) = %d, *za = %#x\n", sizeof(za), sizeof(short *), *za);
    printf("sizeof(zb) = %d, sizeof(long *) = %d, *zb = %#x\n", sizeof(zb), sizeof(long *), *zb);
//  printf("sizeof(zc) = %d, sizeof(void *) = %d, *zc = %d\n", sizeof(zc), sizeof(void *), *zc); error C2100: 間接指定演算子 (*) の使い方が正しくありません。
    printf("sizeof(zc) = %d, sizeof(void *) = %d\n", sizeof(zc), sizeof(void *));

    return(0);
}

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