void(ボイド)は、プログラミング言語において、「何もない」といった意味の型などに使われる名前である。プリミティブとしてキーワードまたは予約語であることも多い。
ALGOL 68のproc
(手続き、プロシージャ)[1]やC言語の関数などでは、有意な値を返さないサブルーチンの戻り値(返り値)の型について、形式上void型としている。この場合は意味的には(型理論的には)本来はUnit型である。呼び出し側にreturn文などで戻り値を返さない関数を書く場合に用いられる。そのような関数は、共有変数(グローバル変数)の状態を変更するような何らかの処理を実行する、あるいはポインタや参照によって渡された引数を経由して呼び出し元にデータを出力するといった、副作用のために呼び出されるのが通例である。Pascalのように、値を返すサブルーチンを関数、値を返さないサブルーチンを手続きと呼び、後者は戻り値の型を記述しない構文仕様となっている言語もある。なお、Visual BasicやVB.NETでは、値を返すプロシージャを「Function
プロシージャ」、値を返さないプロシージャを「Sub
プロシージャ」と呼んでいる。
似たものとしてnil(Null)やUnit型(英語: Unit type)があるが、(本来の)Void型はその型の値は存在しないという点が、NullやUnitと異なる。
また、JavaScriptなど、言語によっては、void演算子が存在する。JavaScriptのvoid演算子は、オペランドの式を評価してその値を得る計算をおこなうが、その値は捨てられ、値を返さない。C言語における、値を捨てる(無視する)ことを明示するためのvoid
型へのキャスト(たとえば、(void)printf("Hello");
のように書く)に似ている。
C言語やC++ではvoid型へのポインタがあり、void *
のように書くが、これは上で述べたvoid型と直接関連するものではなく、「不特定の」(任意の)型のデータを指すポインタとなっている。つまり、この文脈ではvoidが汎用型として扱われている。プログラムでどんな型のデータもvoid型のポインタから指すことができ、逆に元のデータを参照することもできるため、コールバック関数の引数に任意のユーザー定義データのアドレスを渡して処理するといったポリモーフィックな関数を書く際に有用である。なお、ISO C標準規格では、関数ポインタについては扱いが異なり、void *
との相互変換を保証していない[2]。POSIXのdlsym()
関数はdlopen()
で動的ロードしたモジュールから変数や関数のシンボルのアドレスをvoid *
として取得することができるが、この動作はPOSIXに準拠した実装がvoid *
から関数ポインタへの変換を正常に実行できることを前提としている[3]。
戻り値がvoid型の関数では、関数の最後まで到達するか、引数なしのreturn文によって呼び出し元に戻る(あるいは、プログラムの終了まで戻らないか、longjmpのように別の場所に飛ぶ)。また、関数プロトタイプの仮引数リストにvoidを単独で書いて、「引数がない」ことを明示する用途にも使われる。void(空虚)という名前に反して[独自研究?]、Unit型のような使われ方をしている[注釈 1]。
戻り値がvoidでない関数が処理の終わりまで達し、さらにreturn文が書かれていなかった場合の動作は未定義である。モダンなコンパイラは、このようなコードに対して警告を発するものが多い。ただしC++およびISO/IEC 9899:1999 (C99) 規格以降のmain関数に関しては、return文が書かれていなかった場合は最後にreturn 0;
が書かれているものとみなされる。
初期のC言語では、戻り値が明示されていない関数がint
型として扱われ、また引数のない関数ではただ空のカッコを書いていた。そして、指す先の型が決まらないポインタは整数、あるいはchar
へのポインタを代用していた。この仕様だったコンパイラでは、関数の戻り値を使わないことで警告が出ていたので、それをvoid型にキャストすることで警告を出さないようなコードが書かれることもあった。ビャーネ・ストロヴストルップが1979年-1980年頃にC++の開発を始めた時点では、void型やそのポインタはAT&T系のコンパイラがサポートしていた方言であった[4]。
関数の戻り値の型が明示されない場合はint
とみなすという仕様は、ANSI C (C89) およびISO/IEC 9899:1990 (C90) 規格で標準化されたが、C99では規格の文面から削除された。互換性の観点から、まだ拡張として許されている処理系もあるが、通例警告を発する。
関数プロトタイプで仮引数リストにvoid
を明示した場合は「引数なし」を意味するが、何も書かなかった場合(省略した場合)は、以下のようにC言語とC++で意味合いに違いが出てくる[5]。
コード | Cでの意味 | C++での意味 | 備考 |
---|---|---|---|
void f();
|
可変長引数 | 引数なし | C++ではこの記法が推奨されている[6] |
void f(void);
|
引数なし | 引数なし | C++ではこの記法は推奨されていない(Cリンケージを除く) |
void f(...);
|
可変長引数 | 可変長引数 | C23よりも前のC規格では、引数リストに... のみを記述することはできない[7]
|
ただしC言語でも、C99では上記のvoid f();
のような、何も書かないことで可変長の引数を意味する記法が非推奨となっている[8]。また、C23ではこの記法の意味が変更され、仮引数リストにvoid
を書いた場合と等価になる(C++と同様に「引数なし」を意味するようになる)予定である[7]。
Javaにはjava.lang.Void
クラスがある。これはインスタンスを生成できないプレースホルダーとしてのクラスであり、キーワードvoid
を表すjava.lang.Class
オブジェクトへの参照を保持するのに使用される。
.NETにはSystem.Void
構造体がある[9]。C#の場合はvoid
キーワードによってマッピングされる。
ECMAScriptでは、voidはキーワードであり(予約語を参照)、単項式の前に付けて単項式を形成する前置演算子のひとつである[10]。構文規則上はvoid 単項式
という形のためvoid(式)
という形で用いられることが多い。式を評価し、その値を取得するがその値を特にどうともせず、常に「undefined
」を返す。もっぱらHTML内で、
<a href="javascript:void(0)">foo</a>
のように記述して、リンクとしての機能を働かせないために用いられる。