C言語のprintf関数について質問です。



#include <stdio.h>

int main(void) {
int a = 0;
printf("a = %d, foo = %d\n", a); return 1;
}


上記のようなプログラムを実行したところ、
コンパイルエラーとはならず
下記のような結果が出力されました。

$ a = 0, foo = -1074283144

書式文字列で指定した変数の数と
実際に引数で指定した変数の数が違う場合、
不一致している部分にはどんな値が
*言語仕様上*入るのでしょうか?

参考になるウェブサイトでも良いので
教えてください。

回答の条件
  • 1人2回まで
  • 登録:
  • 終了:2007/07/21 20:25:55
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:tombe No.3

回答回数38ベストアンサー獲得回数7

ポイント50pt

個定数引数の場合はプロトタイプ記述でコンパイラに検知させる手段がありますが、可変引数の場合は引数の数をコンパイラにチェックさせる手段はありません。

歴史的にはプロトタイプ記述は割と最近できた言語仕様で、初期のC言語にはプロトタイプ記述も無く、個定数引数の場合でも引数の数の整合性をチェックするのはコンパイラの仕事では無く、プログラマの注意力に委ねられていたのです。C言語とは本来そのような言語です。

従って、この問題も言語仕様として規約があるわけではありませんし、コンパイルエラーにならないのも同じ理由です。

C言語の引数はスタック渡しですので、引数の数が足りなくても多過ぎても、単に関数側がスタックに引数が積まれているものと*信用している*に過ぎません。

例えば、n個の引数を期待している関数に(n-1)個の引数しか渡さなかった場合、呼ばれた関数はとにかく1~n番目のスタックを引数とみなします。

n番目のスタックは値がセットされていませんので、不定値、つまりその時たまたまn番目のスタックに入っている値をprintfが利用するだけの話です。

【3個の引数が正しく渡される場合】

printf("a = %d, b = %d, c = %d\n", 1,2,3);

スタックの状態

┌─┐

│1│

├─┤

│2│

├─┤

│3│

└─┘


【引数が足りない場合】

printf("a = %d, b = %d, c = %d\n", 1,2);

スタックの状態

┌─┐

│1│

├─┤

│2│

├─┤

│?│←何が入っているか保証されないが、printfはとにかくこの中の値を書式印刷する

└─┘

その他の回答2件)

id:KUROX No.1

回答回数3542ベストアンサー獲得回数140

ポイント10pt

フォーマット文字列の解釈やデータ引数との対応については、コンパイラはいっさいチェックしません

http://www.h4.dion.ne.jp/~zero1341/win90/901.htm

----------------------------------------------------

値は不確定になるのが仕様のはずですが・・。

言語仕様? printfの関数仕様では決まってないはずで

実装はコンパイラや処理系によって違うはず。

「未定義」

id:Bookmarker No.2

回答回数191ベストアンサー獲得回数34

ポイント20pt

コンパイルエラーとはならず

一般的には、書式文字列と可変個の引数が一致しているかは検査されません

gcc 等の一部のコンパイラなどは警告してくれる場合はあります。

書式文字列で指定した変数の数と実際に引数で指定した変数の数が違う場合

引数が足らない場合の動作は未定義です。

何か出力されるかもしれないし、プログラムが異常終了するかもしれません。

id:tombe No.3

回答回数38ベストアンサー獲得回数7ここでベストアンサー

ポイント50pt

個定数引数の場合はプロトタイプ記述でコンパイラに検知させる手段がありますが、可変引数の場合は引数の数をコンパイラにチェックさせる手段はありません。

歴史的にはプロトタイプ記述は割と最近できた言語仕様で、初期のC言語にはプロトタイプ記述も無く、個定数引数の場合でも引数の数の整合性をチェックするのはコンパイラの仕事では無く、プログラマの注意力に委ねられていたのです。C言語とは本来そのような言語です。

従って、この問題も言語仕様として規約があるわけではありませんし、コンパイルエラーにならないのも同じ理由です。

C言語の引数はスタック渡しですので、引数の数が足りなくても多過ぎても、単に関数側がスタックに引数が積まれているものと*信用している*に過ぎません。

例えば、n個の引数を期待している関数に(n-1)個の引数しか渡さなかった場合、呼ばれた関数はとにかく1~n番目のスタックを引数とみなします。

n番目のスタックは値がセットされていませんので、不定値、つまりその時たまたまn番目のスタックに入っている値をprintfが利用するだけの話です。

【3個の引数が正しく渡される場合】

printf("a = %d, b = %d, c = %d\n", 1,2,3);

スタックの状態

┌─┐

│1│

├─┤

│2│

├─┤

│3│

└─┘


【引数が足りない場合】

printf("a = %d, b = %d, c = %d\n", 1,2);

スタックの状態

┌─┐

│1│

├─┤

│2│

├─┤

│?│←何が入っているか保証されないが、printfはとにかくこの中の値を書式印刷する

└─┘

  • id:fuentebella
    処理系(OS, コンパイラ)は何をお使いでしょうか? たしか printf(3)は「引数は合わせないといけない」「エラーになる」というような表現しかなかったような。。
  • id:Bookmarker
    > コンパイルエラーにならないのも同じ理由です。

    違うと思います。そもそも検査不可能です。
    (書式文字列が即値の文字列リテラルの場合は可能ですが。)

    > C言語の引数はスタック渡しです

    決まっていないと思います。
    (そもそもスタックがあるとは限らないらしいし。)

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません