मान लीजिए कि हम बाइट्स के अनुक्रम के रूप में कुछ डेटा प्राप्त करते हैं, और उस अनुक्रम को संरचना के रूप में दोबारा परिभाषित करना चाहते हैं (कुछ गारंटी है कि डेटा वास्तव में सही प्रारूप में है)। उदाहरण के लिए:यूबी पैदा किए बिना पीओडी संरचना के रूप में बाइट्स के अनुक्रम को फिर से परिभाषित करने के लिए कैसे?
#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
, वास्तव में बुरा है, क्योंकि यह सख्त अलियासिंग नियम टूट जाता है और इस तरह यूबी कारण बनता है।
यूबी का कारण नहीं बनने के लिए इसे कैसे लागू किया जाना चाहिए और memcpy
जैसे डेटा की कोई प्रतियां नहीं करनी चाहिए?
संपादित: ऊपर वास्तव में कुछ अपरिवर्तनीय समारोह माना जाता था getDataBytes()
कार्य करते हैं। वास्तविक दुनिया का उदाहरण ptrace(2)
है, जो लिनक्स पर, request==PTRACE_GETREGSET
और addr==NT_PRSTATUS
लिखते हैं, x86-64 पर) विभिन्न आकारों के दो संभावित संरचनाओं में से एक लिखते हैं, ट्रेससी सीथर के आधार पर, और आकार देता है। यहां ptrace
कॉलिंग कोड भविष्यवाणी नहीं कर सकता है कि यह वास्तव में कॉल करने तक किस प्रकार की संरचना प्राप्त करेगा। फिर यह सही पॉइंटर प्रकार के रूप में प्राप्त होने वाले परिणामों को सुरक्षित रूप से दोबारा कैसे परिभाषित कर सकता है?
अनिवार्य रूप से, संरचना के लिए डेटा के साथ बाइट सरणी कास्टिंग करने के बजाय, एक स्ट्रक्चर उदाहरण लें, इसे बाइट सरणी में डालें (एड्रेस) को डालें और इस सरणी को डेटा के साथ भरें। [जे Pileborg इसे नीचे कोड के रूप में पोस्ट किया गया] – deviantfan
* लेकिन *, जबकि आपने इसे स्वयं का जिक्र किया था, हमेशा int आकार, नकारात्मक संख्या प्रारूप, संरचना संरेखण, पैडिंग, ... – deviantfan
के बारे में सोचने के लिए एक अनुस्मारक ... विशेष रूप से, डेटा होने जा रहा है अधिकांश मशीनों पर 64 बिट्स, लेकिन वहां केवल 56 बिट जानकारी है। –