5

次のコードを使用します。

int main(){
    printf("%f\n",multiply(2));
    return 0;
}

float multiply(float n){
    return n * 2;
}

コンパイルしようとすると、1 つの警告が表示されます。ここ。"

質問 1 : コンパイラが最初に関数 'multiply' に遭遇したときに関数 'multiply' の知識を持っていないことを考えると、彼はプロトタイプを発明し、発明されたプロトタイプは常に 'int' が返され、次のように解釈されると想定しているからだと推測しています。パラメータ。したがって、発明されたプロトタイプは「intmultiply(int)」になり、エラーが発生します。これは正しいです?

さて、前のコードはコンパイルさえしません。ただし、次のようにコードを 2 つのファイルに分割すると、次のようになります。

#file1.c
 int main(){
    printf("%f\n",multiply(2));
    return 0;
 }

#file2.c
float multiply(float n){
    return n * 2;
}

「gcc file1.c file2.c -o file」を実行すると、警告が1つ表示されますが(printfはdoubleを期待しているが、intを取得しています)、エラーは表示されなくなり、コンパイルされます。

質問 2 : コードを 2 つのファイルに分割してコンパイルするとどうなりますか?

質問 3 : 上記のプログラム (2 つのファイルに分割されたバージョン) を実行すると、画面に 0.0000 が表示されます。どうして?コンパイラが関数に一致しないプロトタイプを再び発明したと推測していますが、なぜ 0 が出力されるのでしょうか? そして、printf("%f") を printf("%d") に変更すると、1 が出力されます。繰り返しますが、舞台裏で何が起こっているのか説明はありますか?

よろしくお願いします。

4

4 に答える 4

4

したがって、発明されたプロトタイプは「intmultiply(int)」になり、エラーが発生します。これは正しいです?

絶対。これは、関数プロトタイプがなく、型なしで宣言されたものはすべて暗黙的にint. コンパイラは をコンパイルしmain、 の暗黙的な定義を作成しますint multiply(int)が、実際の定義を見つけると、嘘を発見し、それについて知らせます。

コードをコンパイルする 2 つのファイルに分割するとどうなりますか?

コンパイラは、一度に 1 つのファイルをコンパイルするため、プロトタイプに関する嘘を発見することはありmultiplyません。ただし、このプログラムを実行すると、未定義の動作が発生します。intintmainmultiply.c

上記のプログラム (2 つのファイルに分割されたバージョン) を実行すると、画面に 0.0000 が出力されます。

これは、上記の未定義の動作の結果です。プログラムはコンパイルおよびリンクされますが、コンパイラは が を受け取るとmultiply判断するため、 にint変換2されることはなく、検出されることもありません。同様に、関数内で再解釈された を 2 倍にして計算された誤った値は、再び として扱われます。2.0Fmultiplyint floatmultiplyint

于 2013-04-18T13:56:07.950 に答える
1

質問 1:はい、あなたは正しいです。関数プロトタイプがない場合、デフォルトの型はint

質問 2:このコードを 1 つのファイルとしてコンパイルすると、コンパイラは、名前付きの関数が既に存在しmultiply、想定とは異なる型 (doubleではなくint) を持っていることを確認します。したがって、コンパイルは機能しません。

これを 2 つのファイルに分けると、コンパイラは 2 つの.oファイルを作成します。最初のものでは、multiply()関数が他のファイルにあると想定しています。次に、リンカーは両方のファイルをバイナリにリンクし、名前に従って、最初のファイルのコンパイラが想定する場所にmultiply呼び出しを挿入します。float multiply()int multiply().o

質問 3:int 2として読み取るとfloat、非常に小さい数値 (~1/2^25) が得られるため、その後で 2 を掛けても、依然として format には小さすぎます%f。それがあなたが見る理由です0.00000

于 2013-04-18T13:55:20.760 に答える
1

指定されていない関数には、戻り値の型int(警告が表示されるのはそのためです。コンパイラは、整数を返すと見なします) と、指定されていない引数の数が不明です。

プロジェクトを複数のファイルに分割する場合は、他のファイルから関数を呼び出す前に関数プロトタイプを宣言するだけで、すべて正常に動作します。

于 2013-04-18T13:55:26.730 に答える
1

質問1:

したがって、発明されたプロトタイプは「intmultiply(int)」になり、エラーが発生します。これは正しいです?

Cx(C89、C90、C99、...)に依存するため、正確にはそうではありません

関数の戻り値については、C99 より前では、関数宣言が表示されない場合はトランスレーターが提供することが明示的に指定されていました。これらの暗黙の宣言は、デフォルトで int の戻り値の型になりました

C 標準からの正当化(6.2.5 ページ 506)

C90 より前は、関数プロトタイプはありませんでした。開発者は、同じ整数型の符号付きバージョンと符号なしバージョンを持つ引数を交換できることを期待していました。関数定義のパラメータ型の符号が異なる場合に引数をキャストしなければならないことは、C の簡単な型チェック システムに反するものであり、少し煩わしいものと見なされていました。プロトタイプの導入によって、引数の互換性の問題が完全に解消されたわけではありません。省略記号表記は、1590 省略記号について何も知られていないことを指定します。省略記号は、引数の期待されるタイプの情報を提供しません。同様に、関数の戻り値の場合、C99 より前では、関数宣言が表示されない場合はトランスレーターが提供することが明示的に指定されていました。これらの暗黙の宣言は、デフォルトで int の戻り値の型になりました。実際の関数がたまたま型 unsigned int を返した場合、そのようなデフォルト宣言は予期しない結果を返した可能性があります。多くの開発者は、関数宣言に対してカジュアルな態度をとっていました。私たちの残りの部分は、委員会が書いたすべてのソースコードを壊したくないという結果を受け入れなければなりません. C99 では関数宣言が呼び出し時に可視である必要があるため、関数の戻り値の交換可能性は現在問題になっています (デフォルトの宣言は提供されなくなりました)。

質問2:

コードをコンパイルする 2 つのファイルに分割するとどうなりますか?

それはコンパイルされ、最初の質問で示されているようにまったく同じように扱われます

于 2013-04-18T13:55:42.457 に答える