2009-08-21 4 views
14

に引数を渡すとき:引数が渡された場合、式は関数呼び出しの引数のでC:型変換は、プログラミング言語C第2版からの関数呼び出し

され、型変換も行われます関数。関数プロトタイプがない場合、charとshortはintになり、floatはdoubleになります。

キャストまたは関数プロトタイプを使用して明示的に引数の型を指定しない限り、関数の引数は常にintまたはdoubleとして渡されると渡されるという印象を受けています。

私の仮説を検証するために、私は次のコードをコンパイル:

typeconversion.c:11:警告: 'の相反するタイプのコンパイル後

#include <stdio.h> 

main() 
{ 
    unsigned char c = 'Z'; 
    float number = 3.14f; 
    function_call(c, number); 
} 

void function_call(char c, float f) 
{ 
} 

を私は次の警告を取得しますfunction_call '

typeconversion.c:7:warning:以前の' function_call 'の暗黙の宣言はここにありました

私の推測はcであり、数値は両方ともintに変換され、関数呼び出しで倍精度化され、charとfloatに変換されました。これは実際に起こったことですか?

+2

これは良い質問です - そしてそれはすべてのパラメータが宣言して**常に**、スコープのプロトタイプを持つことが重要である理由も説明します。 –

答えて

17

キャストは無関係です(キャストは重要ではないかもしれません)。

void foo(short s) { 
    // do something 
} 

int main(void) { 
    signed char c = 'a'; 

    foo(c); // c is promoted to short by explicit prototype 
    bar(c); // c is promoted to int by implicit prototype 
} 

void bar(int i) { 
    // do something 
} 

本書では、「関数呼び出しの引数は式です」と書かれているときは、同じ型の昇格規則が適用されることを意味します。関数プロトタイプで指定された変数への暗黙的な代入として関数の引き数を考えると、理解しやすくなります。例えば上記のfoo()への呼び出しに暗黙のshort s = cがあります。

これは、キャストが重要でない理由です。(暗黙的に)intに続いここで、cの値は、(明示的に)shortに最初に昇格され

signed char c = 'a'; 
int i = (short) c; 

:次のコードスニペットを考えてみましょう。 iの値は、常にintになります。 intfloatになってcharshortについては

は暗黙の関数プロトタイプのデフォルトのタイプを指しdoubleになってきて。コンパイラがプロトタイプまたは関数の定義を見た前に関数の呼び出しを見ると、プロトタイプが自動的に生成されます。整数値の場合はデフォルトでint、浮動小数点値の場合はdoubleになります。

最終的な関数宣言が暗黙のプロトタイプと一致しない場合、警告が表示されます。

+0

あなたの記事はこの質問を投稿する前に私が持っていた多くの質問に答えます。 –

+0

喜んで、ミッドナイトブルー。 –

+1

この回答は「プロトタイプ」と「宣言」をミックスしています。プロトタイプは、関数のパラメータの型を宣言するものです。宣言は、プロトタイプを含むものであり、全体を何と呼びますか(「void f();」)。だから、代わりに "暗黙の宣言"と "明示的な宣言"と言いたい。 –

15

あなたは何が間違っているかという一般的な考え方を持っていますが、正確ではありません。何が起こった

あなたは

function_call(c, number); 

書いたとき、コンパイラはあなたが、それはまだ見ていない関数を呼び出したことを見て、とてもその署名がどうあるべきかを決めなければならなかったということです。以前引用されたプロモーションルールに基づいて、それはint型とdoubleに浮かぶように文字を促進し、署名が

function_call(int, double) 

であることが

function_call(char c, float f) 

を見たとき、それはのための署名としてこれを解釈することを決定しました異なる名前の関数はCでは許されません。実際に定義する方法とは異なるプロトタイプを作成した場合とまったく同じエラーです。この場合、プロトタイプはコンパイラによって暗黙的に生成されます。

このルールは問題を引き起こしていますが、エラーはタイプ間で実際に値を前後に変換することとは関係ありません。

+0

宣言は、古いスタイル(K&R)宣言だけでなく、varargs関数でも発生します。 –

+0

2つは確かに関連していますが、私はその質問自体がエラーに関するものだとは思わない。 –

+0

私が見る唯一の疑問符は、彼のエラー原因の解釈が正しいかどうかを尋ねる文章に添付されています。しかし、はい、この質問にはいくつかの点があります。 –

2

コンパイラは、function_callが標準で示されている関数を返すintであると仮定していると不平を言っています。実際の関数とは異なると明示的に宣言していない限り、コンパイラは引数を気にしません。あなたは引数を渡すことはできませんし、それは不平を言うことはありません。

関数が他のモジュールにある場合、このエラーは検出されないため、必ず関数を宣言する必要があります。関数がintより大きい可能性のある型(void *やlongなど)を返さなければならない場合、呼び出し側関数のintへのキャストはおそらくそれを切り捨てて、奇妙なバグを残します。

+1

コンパイラのエラーは、渡す引数とは関係ありません。あなたはそれを持っていると思った、あなたは私を改造した。他の答えはこれを無視して、彼のコンパイラが間違った引数エラーをキャッチするとOPが思うようにします。なんでも。 – jbcreix

2

誰もが迷っています。 ISO Cでは、ISO構文プロトタイプがデフォルトの引数昇格をオーバーライドします。

そして、この場合、コンパイラはが純粋に定義のスタイルに基づいて別のコード(!)を生成することができます。これによりK & Rの互換性が得られますが、K & RはK & RコードでISOプロトタイプを参照するようにISOコードを記述していない限り、常に言語レベルを呼び出すことはできません。

CC -S -Oでそれを試してみてください

...

​​
+0

これは面白いです... – Artelius

関連する問題