web-dev-qa-db-ja.com

is f(void)現代のCおよびC ++では非推奨

私は現在、C++プロジェクトで使用されているいくつかの古いCコードをリファクタリング/整理しており、次のような関数を定期的に確認しています。

int f(void)

私は次のように書く傾向があります:

int f()

一貫性を向上させるためにコードベース全体で(void)を()に置き換えない理由はありますか、または私が知らない2つの間に微妙な違いがありますか?より具体的には、C++の仮想メンバー関数が次のように記述されている場合:

virtual int f(void)

派生クラスにはメンバー関数が含まれています。

int f()

これは有効なオーバーライドですか?さらに、ほぼ同じシグネチャに基づくリンカーの問題が発生する可能性はありますか?

67
SmacL

Cでは、宣言int f(void)は、パラメーターを取らないintを返す関数を意味します。宣言int f()は、任意の数のパラメーターを取るintを返す関数を意味します。したがって、Cでパラメータを取らない関数がある場合、前者が正しいプロトタイプです。

C++では、int f(void)は非推奨であり、int f()は、パラメーターをとらない関数を具体的に意味するため、推奨されます。

97
Chris Young

Chrisの答えに追加すると、Cでのint f()の使用は、私の経験では悪い習慣です。関数の宣言をその定義と比較して、正しく呼び出されるようにするコンパイラーの機能を失うためです。

たとえば、次のコードは標準に準拠したCです。

#include <stdio.h>
void foo();
void bar(void) {
    foo();
}
void foo(int a) {
    printf("%d\n", a);
}

ただし、afooに渡されなかったため、未定義の動作になります。

C++には、fooの2つのバージョンがあります。1つは引数を取らないバージョン、もう1つはintを取るバージョンです。したがって、barは未定義のバージョンの呼び出しを終了し、リンカーエラーが発生します(fooの他の定義がない場合)。

21
Zach Hirsch

上記の答えはまったく正しいですが、この問題や他の多くの問題について 素晴らしい説明 を示しているため、David Tribbleの優れたページにリンクしています。

ハイライト:

Cは、空のパラメーターリストで宣言された関数と、voidのみで構成されるパラメーターリストで宣言された関数を区別します。前者は不特定の数の引数を取るプロトタイプ化されていない関数であり、後者は引数を取らないプロトタイプ化された関数です。

一方、C++は2つの宣言を区別せず、どちらも引数を取らない関数を意味すると見なします。

CまたはC++のいずれかとしてコンパイルすることを目的とするコードの場合、この問題の最善の解決策は、明示的なvoidプロトタイプを使用してパラメーターをとらない関数を常に宣言することです。

空の関数プロトタイプは、C99では非推奨の機能です(C89と同様)。

編集:標準を検討した後、func(void)構文はnotがC++で非推奨になっていることに注目する価値があるかもしれませんが、一般的にはCスタイルのイディオム。私が遭遇したほとんどのC++プログラマーは空のパラメーターリストを好むと思います。

編集2:C++標準からの引用の追加、セクション8.3.5、段落2:

「parameter-declaration-clauseが空の場合、関数は引数を取りません。パラメーターリスト(void)は空のパラメーターリストと同等です。この特殊な場合を除いて、voidはパラメーター型にはなりません(voidから派生した型は、たとえばvoid *、canなど)。」

どちらの形式も廃止予定であるという言及はありません。基準の正しいセクションを紹介してくれたTribble氏の優れたWebサイトに再度感謝します。

17
Dan Olson

tl; dr:voidを使用します。

C++の下位互換性、および以下で特定された曖昧さを考慮して、結論的な答えを得るには、KnRとANSI Cに戻ると断言します。

_int getline(void);
int copy(void)
_

Getlineとcopyの特殊なバージョンには引数がないため、ファイルの先頭のプロトタイプはgetline()copy()であることがロジックによって提案されます。しかし、古いCプログラムとの互換性のために、標準は古いスタイルの宣言として空のリストを取り、すべての引数リストのチェックをオフにします。 Word voidは、明示的に空のリストに使用する必要があります。 [カーニガン&リッチー、Cプログラミング言語、1988年、32〜33ページ]

そして..

空の引数リストの特別な意味は、古いCプログラムが新しいコンパイラでコンパイルできるようにすることを目的としています。しかし、新しいプログラムでそれを使用することは悪い考えです。関数が引数を取る場合は、それらを宣言します。引数を取らない場合は、void [ibid、Pg。 73]

編集:残りをここで別の議論に分けてください: 引数を取らない関数の宣言でvoidの使用を指定していますか?最も厄介な解析に対処していますか?

2
kmiklas

C11 N1570標準ドラフト

void f()は非推奨です。void f(void)を推奨:

6.11.6関数宣言子

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

はじめに

2一部の機能は廃止されています。つまり、この国際規格の将来の改訂では、撤回が検討される可能性があります。それらは広く使用されているため保持されていますが、新しい実装(実装機能用)または新しいプログラム(言語[6.11]またはライブラリ機能[7.31]用)での使用はお勧めしません。

詳細な説明: https://stackoverflow.com/a/36292431/895245

C++ 11 N3337標準ドラフト

void f(void)void f()も非推奨ではありません。

void f(void)は、Cとの互換性のために存在します。Annex C "互換性" C.1.7条項8:宣言子

8.3.5変更:C++では、空のパラメーターリストで宣言された関数は引数を取りません。 Cでは、空のパラメーターリストは、関数の引数の数と型が不明であることを意味します。

void f()はCでは非推奨であり、void f(void)が推奨されるため、C++が互換性を維持したい限り、void f(void)が存在します。

void f(void)void f()は、C++では同じです。したがって、長いvoid f(void)は、CとC++の両方でコンパイルするコードを作成する場合にのみ意味があります。

詳細な説明: https://stackoverflow.com/a/36835303/895245