引数をとらない関数の仮引数にvoidを書くべきか、書かざるべきか?

本エントリ名のような質問にたいする回答をよく忘れてしまうので、ここにメモしておく。

仮引数にvoidを書く/書かないについては、C言語C++で言語仕様での扱いが異なる。C言語の場合は、関数の宣言か定義かによっても差異がある。

この違いを表にするとこんな感じ。

言語 宣言/定義 f(void) f()
C言語 関数宣言 引数なし(ANSI Cのプロトタイプ宣言) 任意の個数の引数(K&Rの頃の伝統的な宣言)
C言語 関数定義 引数なし(ANSI Cの関数定義) 引数なし(K&Rの頃の伝統的な関数定義)
C++ 関数宣言 引数なし(プロトタイプ宣言) 引数なし(プロトタイプ宣言)
C++ 関数定義 引数なし(関数定義) 引数なし(関数定義)

C言語のみを使う場合

ANSI Cでコードを書いているならば、引数をとらない関数の仮引数にvoidを書くべきだ。

関数の宣言・定義ともに、仮引数にvoidを書かなかった場合、コンパイラはそれらをANSI Cよりも前(例えばK&Rの頃)の伝統的な形式だとみなすだろう。この古い形式は、C99にて廃止予定機能となった。C11でどうなったかは不明だが、たとえ現時点で問題なく使えるとしても、今後廃止される可能性がある機能を使い続けるのは賢い選択ではないだろう。

関数の宣言においては、より深刻な問題がある。プロトタイプ宣言のつもりでvoidのない関数宣言を書いたとき、コンパイラはその宣言をプロトタイプ宣言とはみなさず、K&Rの頃の伝統的な形式の宣言であるとみなす。その関数を呼び出している部分にて、戻り値の型はチェックされるが、引数の有無についてはチェックされないことが圧倒的に多いだろう*1。つまり、誤って引数に値を設定して呼び出しているコードがあったとしても、ビルド時にチェックされることはほぼ皆無だ。

これらの問題を避けるためにも、引数をとらない関数の仮引数にはvoidを書くべきだ。

C++のみを使う場合

引数をとらない関数の仮引数にvoidを書いてもよいし、書かなくてもよい。

ただし両者のスタイルを混ぜて使うべきではない。どちらか一方に統一するべきだ。

C言語C++の双方を使用する場合

C言語のコードでは、当然ながら引数をとらない関数の仮引数にvoidを書くべきだろう。

C++のコードは、もしC++で実装した関数をC言語のコードから呼び出すことがあるのならば、少なくとも関数宣言においては引数をとらない関数の仮引数にvoidを書くべきだ。プロトタイプ宣言の仮引数にvoidが書かれていないと「C言語のみを使う場合」の項で挙げた問題が発生するからだ。この場合、スタイルの統一性の面で、C++の関数定義のコードでもvoidを書いてしまっても罰は当たらないだろう。

まとめ

面倒なら常に仮引数にvoidを書いておけば安全かつ確実。

*1:コンパイル時ではなくリンク時にチェックされる可能性はあるようだが、少なくともclang・gcc・Visual C++ではリンク時のチェックもされないようだ。