[英]C++ defensive programming: reading from a buffer with type safety
假設我有一個不屬於自己的類:DataBuffer。 它提供了各種get成員函數:
get(uint8_t *value);
get(uint16_t *value);
...
從此緩沖區中包含的結構讀取數據時,我知道字段的順序和大小,並且我想減少將來代碼更改導致錯誤的機會:
struct Record
{
uint16_t Header;
uint16_t Content;
}
void ReadIntoRecord(Record* r)
{
DataBuffer buf( initialized from the network with bytes )
buf.get(&r->Header); // Good!
buf.get(&r->Content);
}
然后有人檢查更改以對標頭做一些事情,然后再寫它:
uint8_t customHeader;
buf.get(&customHeader); // Wrong, stopped reading after only 1 byte
r->Header = customHeader + 1;
buf.get(&r->Content); // now we're reading from the wrong part of the buffer.
以下是強化代碼以防更改的可接受方法嗎? 記住,我不能將函數名稱更改為getByte,getUShort等。我可以從DataBuffer繼承,但這似乎有些過分。
buf.get(static_cast<uint16_t*>(&r->Header)); // compiler will catch incorrect variable type
buf.get(static_cast<uint16_t*>(&r->Content))
更新為不安全的舊代碼示例:
float dummy_float;
uint32_t dummy32;
uint16_t dummy16;
uint8_t dummy8;
uint16_t headTypeTemp;
buf.get(static_cast<uint16_t*>(&headTypeTemp));
m_headType = HeadType(headTypeTemp);
buf.get(static_cast<uint8_t*>(&hid));
buf.get(m_Name);
buf.get(m_SerialNumber);
float start;
buf.get(static_cast<float*>(&start));
float stop;
buf.get(static_cast<float*>(&stop));
buf.get(static_cast<float*>(&dummy_float));
setStuffA(dummy_float);
buf.get(static_cast<uint16_t*>(&dummy16));
setStuffB(float(dummy16)/1000);
buf.get(static_cast<uint8_t*>(&dummy8)); //reserved
buf.get(static_cast<uint32_t*>(&dummy32));
Entries().setStart( dummy32 );
buf.get(static_cast<uint32_t*>(&dummy32));
Entries().setStop( dummy32 );
buf.get(static_cast<float*>(&dummy_float));
Entries().setMoreStuff( dummy_float );
uint32_t datalength;
buf.get(static_cast<uint32_t*>(&datalength));
Entries().data().setLength(datalength);
RetVal ret = ReturnCode::SUCCESS;
Entry* data_ptr = Entries().data().data();
for (unsigned int i = 0; i < datalength && ret == ReturnCode::SUCCESS; i++)
{
ret = buf.get(static_cast<float*>(&dummy_float));
data_ptr[i].FieldA = dummy_float;
}
for (unsigned int i = 0; i < datalength && ret == ReturnCode::SUCCESS; i++)
{
ret = buf.get(static_cast<float*>(&dummy_float));
data_ptr[i].FieldB = dummy_float;
}
// Read in the normalization vector
Util::SimpleVector<float> norm;
buf.get(static_cast<uint32_t*>(&datalength));
norm.setLength(datalength);
for (unsigned int i=0; i<datalength; i++)
{
norm[i] = buf.getFloat();
}
setNormalization(norm);
return ReturnCode::SUCCESS;
}
不要使用重載。 為什么沒有get_word
和get_dword
調用? 界面不會更難看,但是至少錯誤很難制造。
從網絡上讀取整個結構會更好嗎? 讓用戶執行所有套接字操作對我來說似乎是個壞主意(未封裝)。 封裝要在網絡上發送的內容以對文件描述符進行操作,而不是讓用戶將原始緩沖區數據放入文件描述符中。
我可以想像像
void readHeader(int filedes, struct Record * Header);
所以你可以做這樣的事情
struct Record
{
uint16_t Header;
uint16_t Content;
uint16_t getHeader() const { return Header; }
uint16_t getContent() const { return Content; }
};
/* socket stuff to get filedes */
struct Record x;
readHeader(fd, &x);
x.getContent();
除非緩沖區包含有關內容的信息,否則您不能從類型安全的緩沖區中讀取內容。 一種簡單的方法是增加每個結構的長度,並檢查至少要讀取的數據仍然是合理的長度。 您也可以使用XML或ASN.1或類似的提供類型信息的地方。 當然,我假設您也寫入該緩沖區。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.