printfの%dにdouble型を渡すと無関係な値が表示される
%dは整数用の書式指定子です。double型の値を%dに渡すと、コンパイルは通り実行もできますが、表示される数値はまったく無関係な値になります。
なぜエラーが出ないのか
出力: -1758341768
(エラーなし)- Cは何も報告しません。コンパイルも実行も正常に完了するためです
出力: -1758341768- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 #include <stdio.h> 2 3 int main(void) { 4 double price = 19.99; 5 printf("%d\n", price); ^ 6 return 0; 7 }
%dは4バイトの整数として引数を読み取りますが、double型は8バイトで浮動小数点用のレジスタに渡されるため、まったく無関係な値が表示されます。double型には%fを使います。
直し方: d を f にします。
パターン2
1 #include <stdio.h> 2 3 int main(void) { 4 double temp = 36.5; 5 printf("%d\n", temp); ^ 6 return 0; 7 }
エラーも警告も出ないまま、表示される数値だけが無関係なものになります。コンパイラは書式指定子と引数の型の対応まではチェックしないことがあります。
直し方: d を f にします。
パターン3
1 #include <stdio.h> 2 3 int main(void) { 4 double pi = 3.14159; 5 printf("%d\n", pi); ^ 6 return 0; 7 }
書式指定子は必ず渡す値の型に合わせます。整数を表示したいときは%dと int型、小数を表示したいときは%fと double型を組み合わせます。
直し方: d を f にします。
パターン4
1 #include <stdio.h> 2 3 int main(void) { 4 double weight = 62.4; 5 printf("%d\n", weight); ^ 6 return 0; 7 }
double型をprintf("%d", ...)で渡すと、無関係な整数値が表示されます。
直し方: d を f にします。
パターン5
1 #include <stdio.h> 2 3 int main(void) { 4 double rate = 4.75; 5 printf("%d\n", rate); ^ 6 return 0; 7 }
書式指定子は必ず渡す値の型に合わせます。double型には%fを使います。
直し方: d を f にします。
よくある誤解
エラーも警告も出ないことがあります。%dは引数を4バイトの整数として読み取りますが、double型は8バイトで浮動小数点用のレジスタに渡されるため、ビット列としてまったく噛み合いません。書式指定子は必ず渡す値の型に合わせる必要があります。
実務での勘所
この不整合の正体は、CPUがdouble型の引数と整数型の引数を別々の場所(多くの64ビット環境ではdoubleは専用の浮動小数点レジスタ、整数は別のレジスタやスタック)に置いて関数に渡していることです。printfのような可変長引数を受け取る関数は、書式指定子(%dや%f)を見て初めて「次はどちらの置き場所から読むべきか」を判断します。%dを指定すると、実際にはdoubleが置かれていない整数用の置き場所から値を読んでしまうため、渡した値とはまったく無関係なビット列が表示されます。