いくつかのデータを一連のバイトとして取得し、そのシーケンスを構造体として再解釈したいとします(データが実際に正しい形式であることをいくらか保証します)。例えば:それは厳しいエイリアシング規則を破るため、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_GETREGSET
とaddr==NT_PRSTATUS
とすると、トレースビット数に応じて異なるサイズの2つの可能な構造のうちの1つを書き込み、サイズを返します。ここではptrace
呼び出しコードは、実際に呼び出しを行うまでどのタイプの構造体が得られるか予測できません。どのようにして正しいポインタ型として得られた結果を安全に再解釈できますか?
基本的には、データを含むバイト配列を構造体にキャストする代わりに、structインスタンスを取得して(アドレス)をバイト配列にキャストし、この配列にデータを入力します。 [J. Pileborgは以下のコードで投稿しました] – deviantfan
*しかし、あなたはあなた自身で言及していましたが、常にintサイズ、負の数値フォーマット、構造体の整列、パディングなどを考えるリマインダーです。 – deviantfan
特に、データはほとんどのマシンでは64ビットですが、そこには56ビットの情報しかありません。 –