C言語の奇妙な点の多くは、設計時のコンピューターの動作によって説明できます。ストレージメモリの量は非常に限られていたため、ソースコードファイル自体のサイズを最小限に抑えることが非常に重要でした。70年代および80年代のプログラミングは、ソースコードに含まれる文字をできるだけ少なくし、できればソースコードのコメントが過剰に含まれないようにすることでした。
もちろん、これは今日ではとんでもないことであり、ハードドライブにほぼ無制限のストレージスペースがあります。しかし、それはCが一般にそのような奇妙な構文を持っている理由の一部です。
特に配列ポインターに関しては、2番目の例がありますint (*p)[10];
(そう、構文は非常に紛らわしいです)。多分それを「10の配列への整数ポインタ」として読むでしょう...これはいくらか理にかなっています。括弧がない場合、コンパイラーは代わりに10個のポインターの配列として解釈し、宣言にまったく異なる意味を与えます。
配列ポインターと関数ポインターはどちらもCで非常に曖昧な構文を持っているため、行うべき賢明なことは、奇妙さをtypedefすることです。おそらくこのように:
わかりにくい例:
int func (int (*arr_ptr)[10])
{
return 0;
}
int main()
{
int array[10];
int (*arr_ptr)[10] = &array;
int (*func_ptr)(int(*)[10]) = &func;
func_ptr(arr_ptr);
}
あいまいでない、同等の例:
typedef int array_t[10];
typedef int (*funcptr_t)(array_t*);
int func (array_t* arr_ptr)
{
return 0;
}
int main()
{
int array[10];
array_t* arr_ptr = &array; /* non-obscure array pointer */
funcptr_t func_ptr = &func; /* non-obscure function pointer */
func_ptr(arr_ptr);
}
関数ポインタの配列を扱う場合、事態はさらに曖昧になる可能性があります。またはそれらのすべての最もあいまいな:関数ポインタを返す関数(やや便利)。このようなことにtypedefを使用しないと、すぐに狂気に陥ります。