3

void*をstruct*にキャストした後にポインターをチェックすることは、無効なキャストを回避するための有効な方法であると常に考えていました。何かのようなもの

MyStructOne* pStructOne = (MyStructOne*)someVoidPointer;
if(!pStructOne)
   return 0;

同じデータを2つの異なる構造体にキャストして、同じ有効なアドレスを取得できるため、これは当てはまらないようです。その後、プログラムは、構造体フィールドにランダムデータが含まれている場合はそれを入力します。

構造体ポインタをキャストする安全な方法は何ですか?

クラスではないため、dynamic_cast<>を使用できません。

助けてくれてありがとう!

4

8 に答える 8

2

構造体のレイアウトを制御できる場合は、すべての構造体の前に独自の型列挙を配置して、型を確認できます。これはCとC++の両方で機能します。

すべてのタイプが事前にわかっているわけではないために列挙型を使用できない場合は、GUIDを使用できます。または、構造体ごとに一意の静的変数またはメンバーへのポインター。

于 2012-09-23T00:15:53.607 に答える
1

ポインタのキャストは本質的に安全でない手順であるため、一般に「安全なキャスト方法」はありません。キャストは、型システムよりもよく知っていると言っているので、ポインターのキャストを開始した後は、型システムが役に立たないとは期待できません。

C ++では、(のような(T) x)Cスタイルのキャストを使用せず、代わりにC++キャストを使用してください。ここで、いくつかの簡単なルールを使用して、ポインターまたは参照をキャストしても問題がないかどうかを判断できます。

  • 悪い方向に進んでオブジェクトを変更する場合const_castは、オブジェクトが実際に変更可能であることを確認する必要があります。

  • static_castポインターまたは参照は、ポリモーフィック階層内またはfrom /tovoidポインターのみが可能です。オブジェクトの動的タイプがキャストターゲットのサブタイプであることを確認する必要があります。voidポインターの場合、そのポインターは正しいタイプのオブジェクトのアドレスです。

  • reinterpret_castchar *タイプ(おそらくsignedまたは)との間でのみ使用するかunsigned、ポインタをとの間で変換するためにのみ使用する必要があり(u)intptr_tます。

いずれの場合も、問題のポインターまたは参照が、キャストで主張するタイプのオブジェクトを参照していることを確認するのはユーザーの責任ですこれを確認するために他の誰かができるチェックはありません。

于 2012-09-23T00:07:36.233 に答える
1

使用している(Cスタイルの)キャストはコンパイル時の操作です。つまり、コンパイラーは、あるものへのポインターを別のものを指すように変更する命令を生成します。

継承関係では、これは単にポインターからの加算または減算です。

コードの場合、コンパイラはコードをまったく生成しません。キャストは、自分が何をしているかを知っていることをコンパイラに伝えるためだけのものです。

コンパイラーは、操作の有効性をチェックするコードを生成しません。someVoidPointerがnullの場合pStructOne、キャスト後になります。\

を使用してdynamic_cast<>()も、キャストされているものが実際にオブジェクトであるかどうかは検証されません。RTTIを使用するオブジェクトが、期待するタイプである(または変換できる)ことを示すだけです。そもそもオブジェクトでない場合は、クラッシュする可能性があります。

于 2012-09-23T00:09:06.697 に答える
1

dynamic_cast仮想メソッドがある限り、構造体またはクラスで使用できます。void*どこにもsがないように、より広範なシステムを再設計することをお勧めします。それは非常に悪い習慣/デザインです。

于 2012-09-22T23:59:45.653 に答える
0

ありません。そして率直に言って、あり得ない。

structこれは、コンパイラがsizeof()特定のセマンティックな方法で次のバイトを処理するための単なる命令です。

任意のポインターを任意のポインターにキャストできます。変更されるのは、コンパイラーがコンテンツを解釈する方法だけです。

使用dynamic_cast<>することが唯一の方法ですが、RTTI(実行型タイプ情報)を呼び出して、割り当ての潜在的な合法性を検討します。ええ、それはもはやreinterpret_cast<>

于 2012-09-23T00:00:42.853 に答える
0

void*関数に渡されるオブジェクトが実際に期待するタイプであることを確認したいようです。MyStructOne*最善のアプローチは、代わりに関数プロトタイプを宣言しvoid*、コンパイラに型チェックを行わせることです。

本当にもっと動的なことをしようとしている場合(さまざまなタイプのオブジェクトを関数に渡すことができるなど)、RTTIを有効にする必要があります。これにより、渡されたオブジェクトに問い合わせて、それがどのタイプであるかを尋ねることができます。

于 2012-09-23T00:04:05.013 に答える
0

構造体ポインタをキャストする安全な方法は何ですか?

まず、そもそもこれを行う必要がないようにしてください。構造体のヘッダーを含めたくない場合は、構造体の前方宣言を使用してください。一般に、関数が複数のタイプのデータを取得できる場合にのみ、署名からデータ型を非表示にする必要があります。そのようなものの例は、任意のデータを渡すことができるようにしたいメッセージパッシングシステムです。送信者と受信者は、期待するタイプを知っていますが、メッセージシステム自体は知る必要はありません。

他に選択肢がないと仮定して、を使用しboost::anyます。これは本質的にタイプセーフvoid*です; 間違ったタイプにキャストしようとすると、例外がスローされます。これが機能するにはRTTIが必要であることに注意してください(通常はRTTIが利用可能である必要があります)。

boost::variant使用できる可能性のあるタイプの固定された限定されたセットがある場合、それは可能性があることに注意してください。

于 2012-09-23T00:16:13.830 に答える
0

を使用する必要があるためvoid*、オプションは次のとおりです。

  1. 仮想デストラクタ(および/または他の仮想メソッド)を含む単一の基本クラスを作成し、それをlibevインターフェース全体で排他的に使用します。これを強制するためにlibevインターフェースをラップし、C++コードのラッパーのみを使用します。次に、 C ++コードdynamic_castで、基本クラスを作成できます。

  2. void*実際にどのタイプを指しているかについての実行時情報がないことを受け入れ、コードを構造化するだけで、常に静的に知ることができます。つまり、最初に正しいタイプにキャストするようにしてください。

  3. を使用しvoid*て単純なタグ/Cookie/ ID構造を保存し、それを使用して実際の構造体などを検索します。これは実際には#1のより手動のバージョンであり、起動するために余分な間接参照が発生します。


そして、への直接の答え

構造体ポインタをキャストする安全な方法は何ですか?

は:

正しいタイプ、またはレイアウト互換であることがわかっているタイプにキャストします。

正しいタイプが何であるかを静的に知ることに代わるものはありません。おそらく何かをとして渡したvoid*ので、それをvoid*取り戻すと、それがどのタイプであったかを知ることができるはずです。

于 2012-09-23T00:19:06.940 に答える