f(void)は、現代のCおよびC ++では非推奨です[複製]
-
03-07-2019 - |
質問
この質問にはすでに回答があります:
現在、C ++プロジェクトで使用されている古いCコードをリファクタリング/整頓しており、次のような関数を定期的に確認しています。
int f(void)
次のように書く傾向があります:
int f()
一貫性を改善するために、コードベース全体で(void)を()に置き換えない理由はありますか?具体的には、C ++の仮想メンバー関数が次のように記述されている場合:
virtual int f(void)
および派生クラスにはメンバー関数が含まれます:
<*>これは有効なオーバーライドですか?さらに、ほぼ同一の署名に基づいたリンカーの問題が発生する可能性がありますか?
解決
Cでは、宣言 int f(void)
は、パラメーターを受け取らないintを返す関数を意味します。宣言 int f()
は、任意の数のパラメーターを取るintを返す関数を意味します。したがって、Cでパラメーターを受け取らない関数がある場合、前者が正しいプロトタイプです。
C ++では、 int f(void)
は推奨されておらず、 int f()
が推奨されます。これは、特にパラメーターを受け取らない関数を意味するためです。
他のヒント
Chrisの答えに追加するために、私の経験では、 int f()
を使用することはCの悪い習慣です。正しく呼び出されます。
たとえば、次のコードは標準に準拠したCです:
#include <stdio.h>
void foo();
void bar(void) {
foo();
}
void foo(int a) {
printf("%d\n", a);
}
しかし、 a
は foo
に渡されなかったため、未定義の動作になります。
C ++には、 foo
の2つのバージョンがあります。1つは引数を取らないもの、もう1つは int
を取るものです。したがって、 bar
は未定義バージョンを呼び出してしまい、リンカーエラーが発生します( foo
の定義が他にない場合)。
上記の答えは非常に正しいですが、これおよび他の多くの問題に関する優れた説明。
ハイライト:
Cは関数を区別します 空のパラメーターリストで宣言されています で宣言された関数 のみで構成されるパラメーターリスト 無効。前者はプロトタイプ化されていない 不特定の数を取る関数 後者は プロトタイプ化された関数 引数。
一方、C ++は、 2つの区別 宣言とそれらの両方を考慮 noをとる関数を意味する 引数。
意図されているコードの場合 CまたはC ++としてコンパイルされた、最高の この問題の解決策は常に パラメータを取らない関数を宣言する 明示的なvoidプロトタイプを使用します。
空の関数プロトタイプは C99の非推奨機能(それらは C89にありました)。
編集:標準を見た後、おそらくfunc(void)構文はC ++で非推奨ではない ことに注意する価値がありますが、一般的にはCスタイルのイディオムと見なされます。私が出会ったほとんどのC ++プログラマーは、空のパラメーターリストを好むと思います。
編集2:C ++標準からの引用の追加、セクション8.3.5、パラグラフ2:
&quot; parameter-declaration-clauseが空の場合、関数は引数を取りません。パラメーターリスト(void)は、空のパラメーターリストと同等です。この特別な場合を除いて、voidはパラメーター型ではありません(ただし、void *などのvoidから派生した型は可能です)。&quot;
どちらの形式も廃止されるという言及はありません。標準の正しいセクションを示してくれたTribble氏の素晴らしいWebサイトに再び感謝します。
tl; dr: void
を使用します。
C ++の下位互換性と、以下に示す曖昧さを考えると、最終的な答えを得るためにKnRとANSI Cに戻ることを断言します。
int getline(void);
int copy(void)
特殊なバージョンのgetlineおよびcopyには引数がないため、 ロジックは、ファイルの先頭にあるプロトタイプを示唆します
getline()
およびcopy()
である必要があります。しかし、との互換性のために 古いCプログラムでは、標準は古いスタイルとして空のリストを取ります 宣言、およびすべての引数リストのチェックをオフにします。言葉 明示的に空のリストには、void
を使用する必要があります。 [カーニガン&amp; Richie、Cプログラミング言語、1988年、Pgs 32-33]
and ..
空の引数リストの特別な意味は、許可することを目的としています 新しいコンパイラでコンパイルする古いCプログラム。しかし、それは悪い考えです 新しいプログラムで使用します。関数が引数を取る場合、宣言します それら;引数を取らない場合は、void [ibid、Pg。 73]
編集:残りの部分をここで別の議論に分けます: 引数をとらない関数の宣言でvoidの使用を指定すると、The Most Vexing Parseに対処しますか?
void f()
は非推奨、 void f(void)
を推奨:
6.11.6関数宣言子:
1 空の括弧を含む関数宣言子の使用(prototype-formatパラメーターではありません) 型宣言子)は廃止された機能です。
はじめに:
2特定の機能は陳腐化しています。つまり、 この国際規格の将来の改訂での撤回。保持されているのは 広く使用されているが、新しい実装での使用(実装用) 機能)または新しいプログラム(言語[6.11]またはライブラリ機能[7.31]用)は推奨されません。
詳細な議論: https://stackoverflow.com/a/36292431/895245
void f(void)
も void f()
も廃止されません。
void f(void)
はCとの互換性のために存在します。 Annex C&quot; Compatibility&quot; C.1.7条項8:宣言子:
8.3.5変更:C ++では、空のパラメーターリストで宣言された関数は引数を取りません。 Cでは、空の パラメータリストは、関数の引数の数とタイプが不明であることを意味します。
void f()
はCで非推奨になり、 void f(void)
が推奨されるため、 void f(void)
はas C ++が互換性を維持したい限り。
void f(void)
と void f()
は、C ++では同じです。したがって、長い void f(void)
は、CとC ++の両方でコンパイルするコードを書くことに関心がある場合にのみ意味があります。これはおそらく価値がありません。
C ++では、 int f(void)
は非推奨の宣言であり、 int f()
と100%同等です。これは同じ署名です 。このコンテキストの void
は、たとえば空白。また、これらはOne Definition Rule(オーバーロードしない)の対象となり、 Derived :: f(void)
は Base :: f()
をオーバーライドします。
ただし、 f(const void)
のようなものを混乱させないでください。その種の奇妙さの意味するコンセンサスはあまりありません。