20

の使用reinterpret_castに関する以前のさまざまな質問を読みました。また、C++標準の関連する文言も読みました。基本的に、ポインタからポインタへの操作の結果は、元のポインタ型にキャストバックする以外の目的reinterpret_castには安全に使用できないということになります。

ただし、実際には、のほとんどの実際の使用法は、aがCスタイルのキャストと同じでreinterpret_castあるという(間違った)仮定に基づいているようです。reinterpret_castたとえば、文字セット変換ルーチンの目的でreinterpret_castからにキャストするために使用するchar*コードをたくさん見てきました。unsigned char*これは完全に無害ですが、厳密に言えば移植性はありません。ポインタを逆参照しようとしたときにfromtoがプログラムをクラッシュさせないreinterpret_castというchar*保証はありません。unsigned char*unsigned char*

標準によれば、ポインタから整数への変換、およびその逆の変換が実際に保証されている 他の唯一の実際の使用法のようです。reinterpret_cast

それでも、異なるポインタ型間で安全に変換したい(そしてできるはずの)多くの場合があります。例:uint16_t*新しいC ++ 0xchar16_t*へのポインタ、または実際には元の型と同じサイズ/配置である基本データ型へのポインタ。しかしreinterpret_cast、これが機能することを保証するものではありません。

質問:char*ポインタ間で、同じサイズ/配置の基本データ型( ->など)に安全に変換するにはどうすればよいunsigned char*ですか?これreinterpret_castが実際に機能することを保証していないようですが、ここではCスタイルのキャストが唯一の安全なオプションですか?

4

5 に答える 5

12

unsigned char *ポインターを逆参照しようとしたときに、char*からunsignedchar*へのreinterpret_castがプログラムをクラッシュさせないという保証はありません。

このようなキャストは他の方法では実行できないため、コンパイラがこの完全に合理的なキャストで実行することを信頼する必要があります。

reinterpret_castはこれが実際に機能することを保証していないようですが、ここではCスタイルのキャストが唯一の安全なオプションですか?

Cスタイルのキャストはマップするだけなreinterpret_castので、まったく同じになります。ある時点で、コンパイラを信頼する必要があります。この規格には、単に「いいえ。コンパイラのマニュアルを読んでください」と書かれているという制限があります。ポインタのクロスキャストに関しては、これがそのようなポイントです。左辺値charを使用してを読み取ることができます。そのようなことを行うために使用可能なものにunsigned charキャストできないコンパイラは、ほとんど使用できないものであり、そのために存在しません。char*unsigned char*

于 2011-02-21T09:09:32.020 に答える
4

基本的に、ポインタからポインタへのreinterpret_cast操作の結果は、元のポインタ型にキャストバックする以外の目的には安全に使用できないということになります。

あなたは正しいです、標準は破られました、しかしN3242はそれを修正しようとします:

の値の定義reinterpret_cast<T*>

N3242、[expr.reinterpret.cast]:

タイプ「pointertoT1」のprvaluevをタイプ「pointertocvT2」に変換すると、static_cast<cv T2*>(static_cast<cv void*>(v))T1とT2の両方が標準レイアウトタイプ(3.9)であり、T2の配置要件がそれらよりも厳密ではない場合に結果が得られます。 T1の。

これはまだ何も定義していません。楽しみのために、以下についてのあまり無関係でないテキストstatic_cast

タイプ「pointertocv1void」のprvalueは、タイプ「pointer to cv2 T」のprvalueに変換できます。ここで、Tはオブジェクトタイプであり、cv2はcv1と同じかそれ以上のcv-qualificationです。nullポインター値は、宛先タイプのnullポインター値に変換されます。「pointertocvvoid」に変換されたオブジェクトへのポインタ型の値は、おそらく異なるcv修飾で、元の値を持つ必要があります。

「適切に変換された」

N3242、[class.mem]:

を使用して適切に変換された標準レイアウト構造体オブジェクトへのポインタは、reinterpret_castその最初のメンバー(または、そのメンバーがビットフィールドの場合は、それが存在するユニット)を指し、その逆も同様です。

それはどんなスタイルですか?「適切に」?笑

明らかに、これらの人は仕様を書く方法を知りません。

Cスタイルはここで唯一の安全なオプションをキャストしますか?

それは役に立ちません。

標準は壊れている、壊れている、壊れている。

しかし、誰もがそれが本当に意味することを理解しています。標準のサブテキストには次のように書かれています。

タイプ「pointertoT1」のprvaluevがタイプ「pointertocvT2」に変換されると、結果はstatic_cast<cv T2*>(static_cast<cv void*>(v))T1とT2の両方が標準レイアウトタイプ(3.9)であり、T2のアライメント要件がT1のアライメント要件よりも厳密でない場合、メモリアドレスをvとして指します。

それは確かに完璧ではありませんが(ただし、標準の他の多くの部分よりも悪くはありません)、2分で、委員会が10年で行ったよりも優れた仕様を作成しました。

于 2011-12-11T17:26:34.807 に答える
3

標準の他の場所にいくつかの保証があります(タイプ表現に関するセクションを参照してください。IIRCでは、対応する符号なしタイプと符号付きタイプが共通の値の表現を共有することを義務付けていますが、IIRCでも、文字として何でも読み取ることができることを保証するテキストもあります。 )。ただし、読んでいるセクション(実装が定義され、指定されていないことを示す)でさえも少なくする場所があることにも注意してください。型のパンニングのいくつかの形式は未定義の動作です。

于 2011-02-20T14:57:12.827 に答える
2

標準では、すべてのプラットフォームで何が発生する必要があるかが指定されています。その必要はありません。移植性の要件を、reinterpret_castが実際に機能するプラットフォームに制限する場合は、それで問題ありません。

実際にuint16_tをサポートするプラットフォームでは、キャストが機能する可能性があります。char16_tの幅が18、24、32、または36ビットのプラットフォームでは、正しく機能しない可能性があります。問題は、そのようなプラットフォームをサポートする必要があるかどうかです。言語標準は望んでいます。

于 2011-02-20T14:42:37.630 に答える
0

ポインターからポインターへのreinterpret_cast操作の結果は、元のポインター型にキャストバックされる以外の目的には安全に使用できません。

それは正しく聞こえません。を仮定するとsizeof(void *) > sizeof(int *)void *foo; reinterpret_cast<void *>(reinterpret_cast<int *>(foo))ポインタ値が切り捨てられたままになる可能性があります。

それはreinterpret_cast、実際には、Cのデフォルトのキャストと単純に同等ではありませんか?

于 2011-02-20T14:41:31.257 に答える