2015-12-11 3 views
7

いくつかのデータを一連のバイトとして取得し、そのシーケンスを構造体として再解釈したいとします(データが実際に正しい形式であることをいくらか保証します)。例えば:それは厳しいエイリアシング規則を破るため、UBの原因となるので、UBを発生させずに一連のバイトをPOD構造として再解釈する方法は?

#include <fstream> 
#include <vector> 
#include <cstdint> 
#include <cstdlib> 
#include <iostream> 

struct Data 
{ 
    std::int32_t someDword[629835]; 
    std::uint16_t someWord[9845]; 
    std::int8_t someSignedByte; 
}; 

Data* magic_reinterpret(void* raw) 
{ 
    return reinterpret_cast<Data*>(raw); // BAD! Breaks strict aliasing rules! 
} 

std::vector<char> getDataBytes() 
{ 
    std::ifstream file("file.bin",std::ios_base::binary); 
    if(!file) std::abort(); 
    std::vector<char> rawData(sizeof(Data)); 
    file.read(rawData.data(),sizeof(Data)); 
    if(!file) std::abort(); 
    return rawData; 
} 

int main() 
{ 
    auto rawData=getDataBytes(); 
    Data* data=magic_reinterpret(rawData.data()); 
    std::cout << "someWord[346]=" << data->someWord[346] << "\n"; 
    data->someDword[390875]=23235; 
    std::cout << "someDword=" << data->someDword << "\n"; 
} 

は今ここmagic_reinterpretは、実際に悪いです。

代わりに、UBを引き起こさず、memcpyのようなデータのコピーを作成しないように実装する必要がありますか?


EDIT:上記getDataBytes()関数は、実際にいくつかの変更不可能な機能と考えられました。現実世界の例はptrace(2)であり、Linuxではrequest==PTRACE_GETREGSETaddr==NT_PRSTATUSとすると、トレースビット数に応じて異なるサイズの2つの可能な構造のうちの1つを書き込み、サイズを返します。ここではptrace呼び出しコードは、実際に呼び出しを行うまでどのタイプの構造体が得られるか予測できません。どのようにして正しいポインタ型として得られた結果を安全に再解釈できますか?

+1

基本的には、データを含むバイト配列を構造体にキャストする代わりに、structインスタンスを取得して(アドレス)をバイト配列にキャストし、この配列にデータを入力します。 [J. Pileborgは以下のコードで投稿しました] – deviantfan

+0

*しかし、あなたはあなた自身で言及していましたが、常にintサイズ、負の数値フォーマット、構造体の整列、パディングなどを考えるリマインダーです。 – deviantfan

+0

特に、データはほとんどのマシンでは64ビットですが、そこには56ビットの情報しかありません。 –

答えて

4

ファイルをバイトストリームとして読み込むのではなく、Data構造のストリームとして読み込みます。

Data data; 
file.read(reinterpret_cast<char*>(&data), sizeof(data)); 
+0

質問の編集をご覧ください。 – Ruslan

1

私はこれらを考えるはすべてcharタイプ(符号付き、符号なし、およびプレーン)のための厳格なエイリアシング規則の特例です。

Data* magic_reinterpret(char *raw) 
は、私は怖い動作しません。だから私は、あなたがしなければならないと考え、magic_reinterpretへの署名を変更です。 deviantfanによってコメントされているように、Data[unsigned] charのシリーズとして読むことはできますが、charDataと読み書きできません。ヨアキムの答えは正しいです。

すべてのことを言っている。ネットワークやファイルから読んでいる場合は、入力を一連のオクテットとして読み込み、バッファからフィールドを計算する余分なオーバーヘッドは無視できるほど小さくなります(そして、コンパイラのバージョン間のレイアウトの変更に対処できるようになります)。マシン)。

+0

'char'は本当に特別なものですが、あなたが考えるようなものではありません。双方向ではありません。 Btw。、 'signed char'は、普通の' char'が署名された変数として動作するとしても、okではありません。 – deviantfan

+0

くそー!私は4分前に答えて、それを修正するために戻ってきて、誰かがすでにコメントしているのを見つけます。 –

+0

何が間違っているか知らずに、沈黙のダウンボウントを集めればもっと気に入るでしょうか? ... SOにはかなり多くのアクティブユーザーがいます.C++のようなタグでは、反応を得るのに時間がかかりません。 – deviantfan

関連する問題