C言語(C89)では、C++(C++98)にはあるいくつかの型がサポートされません。また、型変換についてはかなり仕様が異なりますので、今回はそのあたりの解説を行います。
C言語にはない型
構造体と共用体以外のクラスがないのは当然として、それ以外にも、C++にはあるけれどもC言語にはない型がいくつかあります。
bool 型
C言語にはbool型が存在しません。そのため、論理値をあらわす必要があるとき、普通はint型を使います。したがって、等価演算子(== および !=)、関係演算子(<, <=, >, および>=)、論理演算子(!, &&, および||)の評価結果は、C++ではbool型でしたが、C言語ではint型になります。
wchar_t 型
C言語には、基本型としてのwchar_t型がありません。しかし、ワイド文字もワイド文字列も扱うことができます。では、どうしているかというと、wchar_t型は基本型ではありませんが、typedef名として標準ライブラリで定義されています。wchar_t型を定義しているヘッダは、<stddef.h>および<stdlib.h>です。
参照型
C++には、オブジェクトに別名を付けるための純粋な参照型がありましたが、C言語には参照型はありません。参照が必要な場合は、ポインタを使うことになります。
メンバへのポインタ型
C言語には、構造体や共用体のメンバへのポインタ型というものがありません。それにともない、.*算子や->*演算子も存在しません。メンバへのポインタと同等のことを行うには、構造体や共用体へのポインタと指定するメンバのオフセット値を併用する必要があります。メンバのオフセット値はoffsetofマクロで取得することができます。
暗黙的な型変換
C++にくらべて、C言語はかなり豪快に暗黙的な型変換が行われます。具体的には、オブジェクト型または不完全型へのポインタは、任意のオブジェクト型または不完全型へのポインタに暗黙的に型変換することができます。例えば、char*からint*とか、void*からdouble*とかに自由に型変換できてしまいます。もし間違った代入などが行われていても、コンパイラは警告を出すことはあってもエラーにすることはありません。
0 1 2 3 4 5 6 7 8 |
int main(void) { char *s = "abc"; int *p1 = s; /* OK */ double *p2 = malloc(sizeof(double)*10); /* OK */ return 0; } |
さらには、ポインタ型と汎整数型のあいだでも暗黙的な型変換が可能です。
0 1 2 3 4 5 6 7 8 |
int main(void) { char *s = "abc"; int a = s; /* OK */ int *p = 1234; /* OK */ return 0; } |
さらに、関数へのポインタは、任意の関数へのポインタ型に暗黙的な型変換を行うことができます。仮引数の型や個数が異なっていても、返却型がまったく異なっていても、何のチェックもされません。
このように、C++ではコンパイルエラーになるような暗黙の型変換ができてしまいます。多くの場合、こうした暗黙の型変換は間違いですが、コンパイラはエラーにしてくれません。プログラマは自分の責任において、こうした間違いを防がなければなりません。
明示的な型変換
C言語には、const_cast, dynamic_cast, reinterpret_cast, および static_cast演算子がありません。使えるキャスト演算子は、(型名)だけです。int(a)のような関数形式のキャストも使うことができません。