1

假设我有一个我不拥有的类: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;
}
4

3 回答 3

1

不要使用重载。为什么没有get_wordget_dword调用?界面不会更难看,但至少这个错误更难犯。

于 2011-08-31T22:50:43.047 回答
1

从网络上读取整个结构不是更好吗?让用户执行所有套接字操作对我来说似乎是个坏主意(未封装)。封装你想在网络上发送的东西以对文件描述符进行操作,而不是让用户将原始缓冲区数据放到文件描述符中。

我可以想象类似的东西

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();
于 2011-09-01T08:26:26.877 回答
-1

除非缓冲区包含有关内容的信息,否则您无法从具有类型安全性的缓冲区中读取。一种简单的方法是为每个结构添加长度,并检查至少正在读取的数据是否仍然是正常的长度。您还可以在提供类型信息的情况下使用 XML 或 ASN.1 或类似的东西。当然,我假设您也写入该缓冲区。

于 2011-08-31T22:55:25.960 回答