2009-08-04 18 views
3

以下の関数でreinterpret_castを実行する必要があるかどうかは疑問です。 ITER_Tはchar *、unsigned char *、std :: vector <、unsigned char >イテレータ、またはそれ以外のものかもしれません。これまでのところ怪我をしていないようですが、キャストはバイトのコピー方法に影響しますか?unsigned char *とchar *との間のキャストを再解析してください。

template<class ITER_T> 
char *copy_binary(
    unsigned char length, 
    const ITER_T& begin) 
{ 
    // alloc_storage() returns a char* 
    unsigned char* stg = reinterpret_cast<unsigned char*>(alloc_storage(length)); 
    std::copy(begin, begin + length, stg); 
    return reinterpret_cast<char*>(stg); 
} 
+2

どのようなタイプのalloc_storage関数が返されますか? – zdan

答えて

6

reinterpret_castsは、低レベルの実装で定義されたキャストのために使用されます。標準によれば、reinterpret_castsは、次の変換(C++ 03 5.2.10)のために使用することができる。

  • 一体型へのポインタ
  • 一体型ポインタ
  • 関数へのポインタにすることができ異なるタイプの関数へのポインタに変換する
  • オブジェクトへのポインタを異なるタイプのオブジェクトへのポインタに変換することができます
  • データメンバへのポインタまたはデータメンバへのポインタは、関数または異なるタイプのオブジェクト。このようなポインタ変換の結果は、ポインタaが元の型に変換されていることを除いて、指定されていません。
  • タイプAの発現は、ポインタが明示的reinterpret_castを用いてB型に変換することができる入力する場合はBを入力するための基準に変換することができます。 char *からunsigned char *とバックにキャストすると、ほとんどのマシン上で動作するはずですけれども、異なるタイプにキャストすると、標準によって規定されていないので、reinterpret_castを使用して、あなたのケースでは良い解決策ではない、と述べた

私はタイプ char *として stgを定義することによって、全くキャスト static_castかを使用して考えるでしょう、あなたの場合は

template<class ITER_T> 
char *copy_binary(
    unsigned char length, 
    const ITER_T& begin) 
{ 
    // alloc_storage() returns a char* 
    char* stg = alloc_storage(length); 
    std::copy(begin, begin + length, stg); 
    return stg; 
} 
+0

+1私には良い答えのように見えます - reinterpret_castをいつ使うべきか、ここでは使用しないでください。 –

+2

これは、 'static_cast'の使用に関する部分を除いてはすべて問題ありません。私の理解は、静的キャストは、関連するポインタ型と 'void * 'の間でのみ変換するために使用できることです。 'unsigned char'と 'char'は標準的には無関係な型なので、このケースはreinterpret_castの第4弾でのみ扱われます。 –

1

コード記述されたようであるが、標準4.7(2)に従って、意図したとおりに働いていますこれは、2の補数表現を持つマシンでのみ保証されます。

alloc_storageがcha​​r *を返し、 'char'が署名されている場合、イテレータの値型が符号なしで、キャストを破棄してコピーするchar *。私は右のそれを取得する場合

0

だから、unsigned char型へのキャストは、符号なしバイトごとのコピーをgauranteeすることです。しかし、あなたはそれを戻しのために戻します。このように設定するためのコンテキスト/理由は、機能がちょっと変わったように見えますか?クイックフィックスは、memcpyを()でこのすべてを交換するかもしれない(しかし、コメントとして、イテレータオブジェクトの上にそれを使用しないでください) - そうでない場合は、単に冗長なキャストを削除します。

+1

反復子を使用してmemcpyを使用する場合は注意が必要です。この場合、彼はベクトルを使用していますが、データが常に連続しているわけではありません。 –

+0

ああ、あなたは絶対に正しいです。 – nielsj

+0

ここにコンテキストがあります:私はchar *と部分文字列の範囲を保持するStringSliceクラスを使っています。しかし、私がStringSliceに保持するデータの中には、実際にはunsignedと解釈されるものがあります。 StringSliceメンバを持つクラスでは、誰かがunsigned charまたはsigned charのいくつかの方法でデータを設定できます。データをStringSlice、unsigned char *として取得するか、unsigned charのデータを –

1

短い答えはイエスです、それが影響する可能性があります。

チャーunsigned char型は、コンバーチブル型(C++標準0X n2800において3.9.1)であるので、他の1つを割り当てることができます。 キャストはまったく必要ありません。

[3.9.1] ...char、signed char、およびunsigned charは同じ量の記憶領域を占有します。 と同じアライメント があります。つまり、彼らは 同じオブジェクトの表現を持っています。


[4.7] ...

宛先タイプが符号なし 場合、結果の値は、ソース整数( と合同以上の符号なし整数でありますモジュロ2nここで、n は、使用されるビットの数であり、 は符号なしタイプを表す)。

[注:2の補数表現で を、 この変換は、概念的なものでありかつ(まったく切り捨てがない場合) ビットパターン に変化がありません。末端音符 ]

宛先タイプが署名されている場合、 が 宛先タイプ (およびビットフィールド幅)で表すことができる場合、値は不変です。それ以外の場合、 の値は実装定義です。

したがって、最悪の場合でも、最も優れた(実装の定義が少ない)変換が得られます。とにかく、ほとんどの実装では、これはビットパターン内で何も変更されません。生成されたアセンブラを調べると、変換さえしなくなります。あなたは、コンパイラに依存reinterpret_castは

template<class ITER_T> 
char *copy_binary(unsigned char length, const ITER_T& begin) 
{ 
    char* stg = alloc_storage(length); 
    std::copy(begin, begin + length, stg); 
    return stg; 
} 

使用:

を[5.2.10.3] reinterpret_castはによって行われるマッピングは 実装定義です。 [注: は、 元の値とは異なる の表記を生成することがあります。 -end note]

注:Thisは興味深い関連記事です。

関連する問題