web-dev-qa-db-ja.com

#include <stdio.h>がprintf()を使用する必要がないのはなぜですか?

セッションの記録:

>type lookma.c
int main() {
  printf("%s", "no stdio.h");
}

>cl lookma.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

lookma.c
Microsoft (R) Incremental Linker Version 8.00.50727.762
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:lookma.exe
lookma.obj

>lookma
no stdio.h
30
Constantin

厳密なコンプライアンスモード(「理論上」を意味します)では、スコープ内の関数のプロトタイプ宣言なしで可変数の引数を取る関数を呼び出すと、未定義の動作(不正)を呼び出します。つまり、コンパイラは、#include <stdio.h>からのプロトタイプまたは同等の宣言なしでprintf()を使用するプログラムで、好きなことを何でも行うことができます。 「好きなもの」には、オプションの1つとして正しく機能することが含まれます。それはあなたの例で選択されたオプションのようです。

実際には、コードは、printf()関数の正式な宣言がなくても、ほとんどの実用的なコンパイラで問題なく動作します。

Qrdlが指摘したように、CコンパイラがCライブラリとリンクしているため、関数が見つかりました。

C99および「暗黙のint」に関するChris Youngのコメントは正確ですが、「可変引数関数にはスコープ内にプロトタイプが必要」というルールはC89とC99の両方に適用されます。ほとんどのコンパイラは、デフォルトでは厳密なC99互換モードでは機能しません。そのようにコンパイルできないコードが多すぎるためです。

クリス・ヤングはコメントしました:

明確にするために、私のコメントは暗黙の宣言を削除するC99に関するものでした。 「implicit int」とは、foo(void)などの宣言を許可するC89機能を指していると思います。 int foo(void);を意味し、C99も削除されました。

もちろん、クリスは正しいです。 C99標準から2つの「暗黙の宣言」機能が削除されました。標準のまえがきとして、次のようにリストされています。

  • 暗黙のintを削除
  • 暗黙の関数宣言を削除する

私は十分にはっきりと考えていませんでした(したがって、書いていない)。それにもかかわらず、C89とC99の両方で、可変数の引数を取る関数のスコープにプロトタイプが必要です。

説明する:

extern int pqr();
int main(void)
{
    int i = pqr(1, 3);
    return i;
}

最初の行がない場合、これは正しい[C89]フラグメントであり、関数pqr()を整数(戻り引数が指定されていない)を返す関数として暗黙的に宣言しています。最初の行がextern pqr();で置き換えられている場合、これは正しい(引数が指定されていない)整数を返す関数としてpqr()を宣言した正しいC89フラグメントですが、戻り値の型は「暗黙のint」。書かれているように、関数は明示的に宣言されており、明示的なint戻り値の型を持っていますが、未指定の引数があります。完全に望ましいわけではありませんが、これは有効なC99だと思います。確かに、GCC(3.4.4)はオプション '-std=c99 -pedantic "でそれを受け入れます。理想的には、関数宣言に完全なプロトタイプを含める必要があります(そして、pqr()がEllipsisで定義されている場合、そのプロトタイプは必須理論的には!)

32

最初にこのC++にタグを付けましたが、Cプログラムのようです。スコープにプロトタイプがない場合(#include <stdio.h>の省略などにより)、Cは自動的に関数の暗黙の宣言を提供します。暗黙の宣言は次のようになります。

int printf();

つまり、printfはintを返し、引数をいくつでも取ることができる関数です。このプロトタイプはたまたまあなたの電話でうまくいきました。 #include <stdio.h>

最後に、現在のC標準(ISO/IEC 9899:1999または口語的に「C99」)ではnotが暗黙の宣言を許可し、このプログラムは準拠しないことを追加する必要があります。暗黙の宣言が削除されました。コンパイラはC99をサポートしていないと思います。 C++も正しいプロトタイプを必要とし、暗黙の宣言を行いません。

37
Chris Young

printf()は標準Cライブラリにあり、リンカーは常に標準ライブラリを実行可能ファイルにリンクするため、標準関数が検出され、リンクの問題は発生しません。

Cコンパイラはプロトタイプのない関数がintを返し、可変数の引数を取ると想定しているため、適切なヘッダーを含めないと、プロトタイプではない関数が使用され、問題が発生する可能性があります。したがって、常にヘッダーを含めてください-それはあなたの安全柵です。

9
qrdl