質問
mingwを使用してWindows上でgtkmm用のcairommを構築しようとしています。 void *へのブールのreinterpret_castを行うパラメーターを持つ関数呼び出しでコンパイルが中断します。
cairo_font_face_set_user_data(cobj(), &USER_DATA_KEY_DEFAULT_TEXT_TO_GLYPHS, reinterpret_cast<void*>(true), NULL);
ここでコードが破損し、理由は<!> quot; boolからvoid * <!> quot;への無効なreinterpret_castです。なぜこれが発生するのですか?この行を変更してコンパイルするにはどうすればよいですか?助けが必要
解決
これはユーザーデータであり、値の処理を制御できるので、boolを最初にintにキャストします:reinterpret_cast<void *> (static_cast<int> (true))
。これを行うことは、このANSI-Cライブラリーのテンプレート関数の代わりにvoid *パラメーターが使用されるため、意味があります。必要なのはtrue / false値だけです。そのため、文書化されている限り、一時的にこれをポインターとしてエンコードしても危険はありません。本当に、次のようにした方が良いでしょう:reinterpret_cast<void *> (1)
またはreinterpret_cast<void *> (+true)
。
他のヒント
標準に従って、動作するはずです。セクション3.9.1-7では、boolは整数型であり、5.2.10-5では、reinterpret_castを使用して整数型の値を明示的にポインターに変換できると述べています。コンパイラは完全に標準ではないようです。
<!> quot; true <!> quot;を変更しても大丈夫ですか? 1に?整数とポインター型の間の変換はCの古くて不名誉な伝統であり、したがってC ++であり、それを行わないコンパイラを見つけるのは驚くべきことです。
または、本当にこれを行う必要がある場合は、(void *)trueを試してください。その後、手を洗います。
reinterpret_castは、悪いアイデアです。解決しようとしている問題について詳しく教えてください。おそらく、再解釈せずに解決策を見つけることができるでしょう。なぜboolをvoid *に変換したいのですか?
これについて不平を言っている唯一のコンパイラはGCC(GCC 3.4.5のMinGW)です。そして、その理由はわかりません。標準では、これが許可されていることが明確に示されているようです:
3.9.1基本タイプ
...
bool、char、wchar_t、および 符号付きおよび符号なし整数型は 集合型と呼ばれます。
5.2.10キャストの再解釈:
...
整数型の値または 列挙型は明示的にすることができます ポインターに変換されます。
とはいえ、 monjardinの回避策 reinterpret_cast<void *> (static_cast<int> (true))
またはreinterpret_cast<void *> (1)
は妥当な回避策です。
キャストは意味をなさないため失敗します。ブール値のtrue / false値を取得し、これをポインターとして解釈するようコンパイラーに要求しています。この2つのアレントは、リモートでも関連しています。
新しいバージョンのコンパイラを試してください。テストしたばかりで、このキャストは少なくともgcc 4.1以上で動作します。ただし、gccバージョンがmingwバージョンにどのようにマッピングされるか正確にはわかりません。
場合によっては、reinterpret_cast<void*>(true)
などのコードに対してコンパイラが警告またはエラーを表示することが非常に望ましい場合がありますが、このコードは明らかに合法的なC ++です。たとえば、64ビットプラットフォームへの移植を支援します。
64ビットポインターをポインターより小さい整数型(int
やbool
など)にキャストすることは、多くの場合バグです。ポインターの値を切り捨てています。さらに、C ++仕様は、ポインターをより小さな整数型に直接キャストできることを保証するようには見えません(強調を追加):
5.2.10.4。ポインターは、保持するのに十分な大きさの任意の整数型に明示的に変換できます。マッピング関数は実装定義です。
同様に、小さな整数型を(reinterpret_cast<void*>(static_cast<int>(true))
と同様に)64ビットポインターにキャストすることもしばしばバグです。コンパイラーはポインターの上位ビットを何かで埋める必要があります。それはゼロフィルまたは符号拡張ですか?メモリマップドI / OアクセスまたはDMA用の低レベルのプラットフォーム固有のコードを記述している場合を除き、ハッキングを行う(ブール値をポインターに詰めるなど)場合を除き、通常はこれをまったく行いたくないでしょう。 )。しかし、C ++仕様では、実装定義である(脚注は省略されている)こと以外、このケースについてはあまり言及していないようです:
5.2.10.5。整数型または列挙型の値は、明示的にポインターに変換できます。*
十分なサイズの整数に変換されたポインター(実装上に存在する場合)は、元の値を持ち、同じポインター型に戻ります。それ以外の場合、ポインターと整数間のマッピングは実装定義です。
@monjardinはvoid*
を提案しました。エラーの原因が整数型のサイズとポインターサイズの不一致である場合、これはほとんどの32ビットプラットフォーム(uintptr_t
とDWORD_PTR
は32ビット)で動作しますが、ほとんどの64ビットで失敗しますプラットフォーム(<=>は32ビット、<=>は64ビット)。その場合、この式の<=>を<=>や<=>(Windowsの場合)などのポインターサイズの整数型に置き換えると、<=>とポインターサイズの整数間の変換が許可されるため、動作するはずです。ポインターサイズの整数とポインターの間の変換です。
GCCの最新バージョンには、次の警告抑制があります。オプション、ただし C ++ではない:
-Wno-int-to-pointer-cast(CおよびObjective-Cのみ)
異なるサイズの整数のポインター型へのキャストからの警告を抑制します。-Wno-pointer-to-int-cast(CおよびObjective-Cのみ)
異なるサイズの整数型へのポインターからのキャストによる警告を抑制します。