14

以下について間違っていますか?

C++ 標準では、関数へのポインターとオブジェクトへのポインター (およびその逆) の間の変換は、実装定義のセマンティクスで条件付きでサポートされていると述べていますが、すべての C 標準では、これはすべての場合に違法であると述べています。

void foo() {}

int main(void)
{
    void (*fp)() = foo;
    void* ptr = (void*)fp;
    return 0;
}

ISO/IEC 14882:2011

5.2.10 キャストの再解釈 [expr.reinterpret.cast]

8 関数ポインターからオブジェクト ポインター型への変換、またはその逆の変換は、条件付きでサポートされています。このような変換の意味は実装によって定義されますが、実装が両方向の変換をサポートしている場合を除いて、ある型の prvalue を別の型に変換し、元の型の prvalue を、おそらく異なる cvqualification で変換すると、元のポインター値が生成されます。

現在、C標準でそれについて何も見つけることができません...

4

4 に答える 4

10

  • C++03 では、そのような変換は (UB ではなく) 違法でした。コンパイラは診断を発行するはずでした。Unix システムの多くのコンパイラは、診断を発行しませんでした。これは基本的に、POSIX と C++ の標準間の衝突でした。
  • C++11 では、このような変換は「条件付きでサポート」されています。システムがそのような変換をサポートしている場合、診断は必要ありません。診断するものは何もありません。
  • C では、このような変換は正式には未定義の動作であるため、診断は必要ありません。システムがたまたま「正しい」ことを行う場合、それは UB を実装する 1 つの方法です。
  • C99 では、これは再び UB です。ただし、標準では、言語への「一般的な拡張機能」の 1 つとして、そのような変換もリストされています。

    J.5.7 関数ポインタのキャスト
    オブジェクトまたは void へのポインタを関数へのポインタにキャストして、データを関数として呼び出すことができます (6.5.4)。
    関数へのポインターは、オブジェクトへのポインターまたは void にキャストすることができ、関数を検査または変更することができます (たとえば、デバッガーによって) (6.5.4)。

于 2013-01-02T16:59:50.437 に答える
9

そうです、C(99) 標準は、関数へのポインターからオブジェクトへのポインターへの変換について何も述べていないため、未定義の動作です。*


*ただし、関数型へのポインタ間の動作を定義することに注意してください。

于 2013-01-02T16:26:05.470 に答える
5

すべての C 標準では、ポインターから関数へのポインターとポインターからオブジェクトへの変換は定義されていません。 C および下位互換性のための変換であり、動的にロードされたライブラリへのアクセスなどに役立ちます (たとえば、dlsymPOSIX 関数ではその使用が義務付けられています)。C++11 は、条件付きでサポートされる機能の概念を導入し、それを使用して標準を既存の慣行に適合させました。ここで、コンパイラは、そのような変換を行おうとするプログラムを拒否するか、指定された限定された制約を尊重する必要があります。

于 2013-01-02T16:35:24.633 に答える
5

キャストの動作は標準の「コア」によって定義されていませんが、このケースは C99 根拠ドキュメント (6.3.2.3、ポインター)で無効であると明示的に説明されています。

関数へのポインターについては何も述べられていません。これは、オブジェクト ポインターおよび/または整数と一致しない可能性があります。

明示的なキャストを使用しても、関数ポインターをオブジェクト ポインターまたは void へのポインターに、またはその逆に変換することは無効です。

また、有用な場合があるため、標準の付属書 J でも「共通拡張」として言及されています (C11 標準 J.5.7、関数ポインター キャスト)。

オブジェクトへのポインターまたはへvoidのポインターは、関数へのポインターにキャストすることができ、データを関数として呼び出すことができます (6.5.4)。

関数へのポインターは、オブジェクトまたは へのポインターにキャストできますvoid。これにより、関数を (たとえば、デバッガーによって) 検査または変更できます (6.5.4)。

これを拡張として説明することは、これが標準要件の一部ではないことを意味します (ただし、明示的な動作を省略すれば十分です)。

于 2013-01-02T16:53:55.763 に答える