なぜC99が互換性のないポインタタイプ間の変換を許可するのか疑問に思います:
void f(int* p)
{
}
void c(char* p)
{
f(p);
}
C11もそれらを許可しますか?このような変換を診断するには、準拠する実装が必要ですか?
なぜC99が互換性のないポインタタイプ間の変換を許可するのか疑問に思います:
void f(int* p)
{
}
void c(char* p)
{
f(p);
}
C11もそれらを許可しますか?このような変換を診断するには、準拠する実装が必要ですか?
C99では、異なるタイプのポインター間の暗黙的な変換は許可されていません(to / fromを除くvoid*
)。C99の理論的根拠は次のとおりです。
明示的なキャストなしで、任意のタイプのオブジェクトへのポインターを別のタイプのオブジェクトへのポインターに変換することは無効です。
これは、割り当てのルールの結果であり、次のいずれかが保持されるという制約があります(ポインターが含まれる場合)(C99 6.5.16.1「単純な割り当て」)。
- 両方のオペランドは、互換性のある型の修飾バージョンまたは非修飾バージョンへのポインターであり、左側が指す型には、右側が指す型のすべての修飾子があります。
- 一方のオペランドはオブジェクトまたは不完全な型へのポインターであり、もう一方はvoidの修飾または非修飾バージョンへのポインターであり、左側が指す型には、右側が指す型のすべての修飾子があります。
- 左側のオペランドはポインターであり、右側はnullポインター定数です。
プロトタイプ化された関数への引数としてポインターを渡すのは、同じ規則に従います。理由は次のとおりです(C99 6.5.2.2/7「関数呼び出し」)。
呼び出された関数を示す式にプロトタイプを含む型がある場合、引数は、割り当てによるかのように、対応するパラメーターの型に暗黙的に変換されます。
C90とC11はどちらも同じような言い回しです。
多くのコンパイラ(GCCを含む)は、これに依存するレガシーコードが多すぎるため、この制約を緩和して警告のみを発行すると思います。void*
これはANSIC標準の発明であり、事前標準であり、おそらく多くの事後標準のコードであり、一般的に使用されるchar*
かint*
、「汎用」ポインタ型として使用されることを覚えておいてください。
「互換性のない」ポインタ型などはありません。
Cの利点は、プログラマーがやりたいことを実行できることです。互換性のあるものと互換性のないものを決定するのはプログラマー次第です。class
「 」または「type
」の凝集を強制すると主張する他の言語は、限られた方法でそうします。オブジェクトの参照が許可された瞬間にポインタが使用され、クラスの管理ミスが発生する可能性があります。