395

なぜコンパイルされているのか混乱している誰かのCコードに出くわしました。わからない点が2つあります。

  1. 関数プロトタイプには、実際の関数定義と比較してパラメーターがありません。

  2. 関数定義のパラメーターに型がありません。


#include <stdio.h>

int func();

int func(param)
{
    return param;
}

int main()
{
    int bla = func(10);    
    printf("%d", bla);
}

なぜこれが機能するのですか?いくつかのコンパイラでテストしましたが、正常に動作します。

4

11 に答える 11

274

他のすべての答えは正しいですが、完了のためだけです

関数は次の方法で宣言されます。

  return-type function-name(parameter-list,...) { body... }

return-typeは、関数が返す変数タイプです。これは、配列型または関数型にすることはできません。指定しない場合、intが想定されます。

function-nameは、関数の名前です。

parameter-listは、関数が使用するパラメーターのリストであり、コンマで区切られています。パラメーターが指定されていない場合、関数はパラメーターを受け取らないため、空の括弧のセットまたはキーワードvoidを使用して定義する必要があります。パラメータリストの変数の前に変数タイプがない場合、intが想定されます。配列と関数は関数に渡されませんが、自動的にポインターに変換されます。リストが省略記号(、...)で終了している場合、パラメーターの設定数はありません。注:ヘッダーstdarg.hは、省略記号を使用するときに引数にアクセスするために使用できます。

そしてまた、完全を期すために。C11仕様6:11:6から(ページ:179)

空の括弧付きの関数宣言子(プロトタイプ形式のパラメーター型宣言子ではない)の使用は、廃止された機能です

于 2012-12-19T10:56:28.537 に答える
161

Cではfunc()、任意の数の引数を渡すことができることを意味します。引数が必要ない場合は、として宣言する必要がありますfunc(void)。関数に渡すタイプは、指定されていない場合、デフォルトで。になりintます。

于 2012-12-19T10:50:19.113 に答える
59

int func();は、C標準がなかった時代、つまりK&R Cの時代(1989年以前、最初の「ANSI C」標準が公開された年)からの廃止された関数宣言です。

K&R Cにはプロトタイプがなく、キーワードvoidはまだ発明されていないことを忘れないでください。できることは、関数の戻り型についてコンパイラーに通知することだけでした。K&R Cの空のパラメータリストは、「指定されていないが固定された」引数の数を意味します。固定とは、毎回同じ数の引数を使用して関数を呼び出す必要があることを意味します(呼び出しごとに数とタイプが異なる可能性がある、のような可変個引数関数とは対照的です)。printf

多くのコンパイラはこの構成を診断します。特に、gcc -Wstrict-prototypes「関数宣言はプロトタイプではありません」と表示されます。これは、プロトタイプのように見えるため(特に、C ++に毒されている場合)、スポットですが、そうではありません。これは古いスタイルのK&RCリターン型宣言です。

経験則:空のパラメーターリスト宣言を空のままにしないでくださいint func(void)。具体的に使用してください。これにより、K&Rの戻り型宣言が適切なC89プロトタイプに変わります。コンパイラーは満足し、開発者は満足し、静的チェッカーは満足しています。ただし、C++の^W ^ Wfondによって誤解を招く可能性があるのは、外国語のスキルを行使しようとするときに余分な文字を入力する必要があるためです:-)

于 2012-12-19T10:55:49.290 に答える
53
  • 空のパラメータリストは「任意の引数」を意味するので、定義は間違っていません。
  • 欠落しているタイプは。と見なされますint

これを通過するビルドには、構成された警告/エラーレベルが不足していると思いますが、実際のコードを許可することに意味はありません。

于 2012-12-19T10:51:51.110 に答える
30

これは、 K&Rスタイルの関数の宣言と定義です。C99標準(ISO / IEC 9899:TC3)から

セクション6.7.5.3関数宣言子(プロトタイプを含む)

識別子リストは、関数のパラメータの識別子のみを宣言します。その関数の定義の一部である関数宣言子の空のリストは、関数にパラメーターがないことを指定します。その関数の定義の一部ではない関数宣言子の空のリストは、パラメーターの数またはタイプに関する情報が提供されていないことを指定します。(両方の関数型が「古いスタイル」の場合、パラメーター型は比較されません。)

セクション6.11.6関数宣言子

空の括弧付きの関数宣言子(プロトタイプ形式のパラメーター型宣言子ではない)の使用は、廃止された機能です。

セクション6.11.7関数の定義

個別のパラメーター識別子と宣言リスト(プロトタイプ形式のパラメータータイプと識別子宣言子ではない)を使用した関数定義の使用は、廃止された機能です。

古いスタイルはK&Rスタイルを意味します

例:

宣言:int old_style();

意味:

int old_style(a, b)
    int a; 
    int b;
{
     /* something to do */
}
于 2012-12-19T11:07:33.007 に答える
15

Cはint、関数の戻りタイプとパラメーターリストにタイプが指定されていない場合を想定しています。このルールの場合のみ、次の奇妙なことが可能です。

関数定義は次のようになります。

int func(int param) { /* body */}

それがあなたが書くプロトタイプなら

int func(int param);

プロトタイプでは、パラメータのタイプのみを指定できます。パラメータの名前は必須ではありません。それで

int func(int);

また、パラメータタイプを指定せずに、名前intがタイプとして想定されている場合。

int func(param);

さらに進んでいくと、以下も機能します。

func();

コンパイラはint func()、を書き込むときに想定しますfunc()。ただしfunc()、関数本体の中に入れないでください。それは関数呼び出しになります

于 2012-12-19T20:49:45.183 に答える
11

@Krishnabhadraが述べたように、他のユーザーからの以前のすべての応答は正しい解釈を持っており、いくつかの点についてより詳細な分析を行いたいと思います。

Old-Cでは、ANSI-Cの「型指定されていない仮パラメータ」と同様に、8ビットMPUでは作業レジスタまたは命令深度機能(シャドウレジスタまたは命令累積サイクル)の次元を取り、16ビットではint16になります。 MPUなどはint16などになります。64ビットアーキテクチャが次のようなオプションをコンパイルすることを選択する場合:-m32。

高レベルでの実装はより単純に見えますが、複数のパラメーターを渡すために、制御次元のデータ型ステップでのプログラマーの作業はより要求が厳しくなります。

その他の場合、一部のマイクロプロセッサアーキテクチャでは、ANSIコンパイラがカスタマイズし、この古い機能の一部を活用してコードの使用を最適化し、これらの「型指定されていない正式なパラメータ」の場所を作業レジスタの内外で機能させます。 「volatile」と「register」の使用についてもほぼ同じです。

ただし、最新のコンパイラでは、2つのタイプのパラメータ宣言を区別していないことに注意してください。

Linuxでのgccを使用したコンパイルの例:

main.c

main2.c

main3.c  
いずれにせよ、このプロトタイプへのパラメータ参照がない呼び出しはないため、ローカルでのプロトタイプのステートメントは役に立ちません。「型指定されていない仮パラメータ」を使用してシステムを外部呼び出しに使用する場合は、宣言型プロトタイプデータ型の生成に進みます。

このような:

int myfunc(int param);
于 2012-12-19T23:46:58.277 に答える
5

パラメータタイプに関しては、ここにすでに正しい答えがありますが、コンパイラからそれを聞きたい場合は、いくつかのフラグを追加してみることができます(フラグはとにかくほとんどの場合良い考えです)。

Igetを使用してプログラムをコンパイルしますgcc foo.c -Wextra

foo.c: In function ‘func’:
foo.c:5:5: warning: type of ‘param’ defaults to ‘int’ [-Wmissing-parameter-type]

奇妙な-Wextraことに、これをキャッチしません(何らかの理由で、おそらく上記の歴史的なものをclang認識しません)が、 :-Wmissing-parameter-type-pedantic

foo.c:5:10: warning: parameter 'param' was not declared, 
defaulting to type 'int' [-pedantic]
int func(param)
         ^
1 warning generated.

また、プロトタイプの問題については、上記で再度述べたようint func()に、明示的に定義しない限り、任意のパラメーターを参照します。int func(void)これにより、期待どおりのエラーが発生します。

foo.c: In function ‘func’:
foo.c:6:1: error: number of arguments doesn’t match prototype
foo.c:3:5: error: prototype declaration
foo.c: In function ‘main’:
foo.c:12:5: error: too many arguments to function ‘func’
foo.c:5:5: note: declared here

またはclangとして:

foo.c:5:5: error: conflicting types for 'func'
int func(param)
    ^
foo.c:3:5: note: previous declaration is here
int func(void);
    ^
foo.c:12:20: error: too many arguments to function call, expected 0, have 1
    int bla = func(10);
              ~~~~ ^~
foo.c:3:1: note: 'func' declared here
int func(void);
^
2 errors generated.
于 2012-12-19T17:43:32.130 に答える
3

関数宣言にパラメーターがない場合、つまり空の場合、指定されていない数の引数を取ります。引数を取らないようにする場合は、次のように変更します。

int func(void);
于 2012-12-19T10:51:21.050 に答える
0

これが、私が通常、次のコードを使用してコードをコンパイルするようにアドバイスする理由です。

cc -Wmissing-variable-declarations -Wstrict-variable-declarations -Wold-style-definition

これらのフラグは、いくつかのことを強制します。

  • -Wmissing-variable-declarations:最初にプロトタイプを取得せずに非静的関数を宣言することは不可能です。これにより、ヘッダーファイルのプロトタイプが実際の定義と一致する可能性が高くなります。または、公開する必要のない関数にstaticキーワードを追加することを強制します。
  • -Wstrict-variable-declarations:プロトタイプは引数を適切にリストする必要があります。
  • -Wold-style-definition:関数定義自体も引数を適切にリストする必要があります。

これらのフラグは、多くのオープンソースプロジェクトでもデフォルトで使用されています。たとえば、FreeBSDでは、MakefileでWARNS=6を使用してビルドするときにこれらのフラグが有効になっています。

于 2013-02-12T21:38:48.320 に答える
0

古いスタイルの宣言者では、

関数定義(Par.A.10.1)の先頭で宣言子が使用されていない限り、識別子リストは存在しない必要があります。パラメータのタイプに関する情報は、宣言によって提供されません。たとえば、宣言

int f(), *fpi(), (*pfi)();

整数を返す関数f、整数へのポインタを返す関数fpi、および整数を返す関数へのポインタpfiを宣言します。これらのいずれにも、指定されたパラメータタイプはありません。彼らは古いスタイルです。

新しいスタイルの宣言で

int strcpy(char *dest, const char *source), rand(void);

strcpyは、intを返す関数であり、2つの引数があります。最初の引数は文字ポインターで、2番目の引数は定数文字へのポインターです。

出典:-K&Rブック

それがあなたの疑問を解決したことを願っています。

于 2021-04-22T03:57:30.890 に答える