【C言語】
size_t型のprintf書式は %zu,%zx

printf書式 size_t型 %zu,%zx

warning: format specifies type ‘int’ but the argument has type ‘unsigned long’

警告: %dは’int’型の書式だが、引数の型は’unsigned long’です。

[-Wformat]


sizeof()にキャストするな

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
//巨大な配列
//gcc -m32 32bitコンパイラではコンパイルできない
//gcc -m64 64bitコンパイラではコンパイルできる
typedef struct {
    int     id;
    char    buf[INT_MAX];
} big_data ;
int main(void){
    if(sizeof(big_data) > INT_MAX){
        //%d:gcc -m64で警告発生
        //キャストで警告抑止⇒問題の潜在化
        printf("NG %d byte\n",     sizeof(big_data));
        printf("NG %d byte\n",(int)sizeof(big_data));
    
        //%ld:gcc -m32で警告発生
        //%zu推奨10進
        //%zx推奨16進
        printf("NG %ld byte\n",sizeof(big_data));
        printf("OK %zu byte\n",sizeof(big_data));
        printf("OK %zx byte\n",sizeof(big_data));
    }
}

(1) 32bit(ILP32)コンパイラ時代は
size_t型を表すのに
%dでも
%ldで実行結果は同じでした。
コンパイル時警告は出たかも?
それ以前に巨大データはコンパイルできない?

(2) 64bit(LP64,LLP64)コンパイラ時代は
size_t型を表すのには
%zu(10進)か
%zu(16進)を使いましょう。
コンパイル時警告は出ません。

(3)コンパイラの警告を消すために
%d書式に対して(int)sizeofとキャストするのは止めましょう。
理由は以下の実行結果を参照してください。


■実行結果(gcc -m64)

NG -2147483644 byte
NG -2147483644 byte
NG 2147483652 byte
OK 2147483652 byte
OK 80000004 byte

せっかくコンパイラが警告を出しているのに、
キャストすると警告が抑止され
問題が潜在化します。

この例では巨大オブジェクトのサイズが
INT_MAXを超えたので負値になっています。

■実行結果(Visual Studio64bit版)

NG -2147483644 byte
NG -2147483644 byte
NG -2147483644 byte
OK 2147483652 byte
OK 80000004 byte

Visual Studio 64bit版では
longのサイズと
intのサイズが同じなので
書式 %ld でも負値になってしまいます。


参考:

長さ修飾子 (length modifier)