我必须解码一些字节数组(原始数据)。它可以包含基本数据类型(int,unsigned int,char,short等)。根据定义的结构,我需要解释它们。以下是例子:
struct testData
{
int a;
char c;
};
unsigned char** buf = {0x01,0x00,0x00,0x00,0x41}
example byte array(in little endian) : 0100000041
should give decoding like : a = 1, c = 'A'
样本数据可能非常大,样本结构(例如testData)可以包含200-3000个字段。 如果我使用am cast从** buf中读取相应的数据并设置如下所示的指针:
int a = *(reinterpret_cast<int*>(*buf);
*buf += 4;
char c = **buf;
*buf += 1;
如果需要解码的文件数很高,我的CPU使用率会很高。例如:
struct testData
{
int element1;
char element2;
int element3;
... ...
... ...
short element200;
char element201;
char element202;
}
有没有办法减少CPU负载并保持解码速度非常快?
我有两个限制:
答案 0 :(得分:5)
int a = *(reinterpret_cast<int*>(*buf);
请勿使用reinterpret_cast
。您在骗编译器并强制进行未对齐访问。更糟糕的是,您正在从编译器中隐藏以优化代码所需的信息 - 指针实际上是字符。相反,将您的意思编码为尽可能简单,即:
int a=static_cast<int>(*buf[0]) |
(static_cast<int>(*buf[1])<<8) |
(static_cast<int>(*buf[2])<<16) |
(static_cast<int>(*buf[3])<<24);
这很简单,清晰,你真正想要的是什么。编译器在优化它时没有问题。 (并且,无论您的平台的字节顺序如何,它都能正常工作。)
答案 1 :(得分:2)
只要结构正确打包,您应该能够简单地将结构映射到缓冲区:
#pragma pack(push, 1)
struct testData
{
int element1;
char element2;
int element3;
... ...
... ...
short element200;
char element201;
char element202;
}
#pragma pack(pop)
您还应该以对齐的方式声明结构,不要混合int
后跟char
后跟int
...然后如果您读取数据对齐缓冲区,缓冲区到testData*
的简单转换将允许您访问所有成员。这样你就可以避免所有那些无偿的副本。如果您以正向方式阅读结构(p->element1
,然后阅读p->element2
,然后阅读p->element3
,依此类推)hardware prefetch应该启动并大力提升。
进一步的改进需要对热点进行实际测量。另外,请从图书馆查看本书并阅读:The Software Optimization Cookbook。
答案 2 :(得分:1)
除了David Schwartz的回复之外,你可以通过编写一些帮助模板函数来整理它。我建议这样的事情(未经测试)。
template<typename T>
const unsigned char * read_from_buffer( T* value, const unsigned char * buffer);
template<>
const unsigned char * read_from_buffer<int>( int* value, const unsigned char * buffer)
{
*value = static_cast<int>(*buf[0]) |
(static_cast<int>(*buf[1])<<8) |
(static_cast<int>(*buf[2])<<16) |
(static_cast<int>(*buf[3])<<24);
return buffer+4'
}
template<>
const unsigned char * read_from_buffer<char>( char * value, const unsigned char * buffer )
{
*value = *buffer;
return buffer+1;
}
struct TestData
{
int a;
char c;
};
int main()
{
unsigned char buf[] = {0x01,0x00,0x00,0x00,0x41};
unsigned char * ptr = buf;
TestData data;
ptr = read_from_buffer( &data.a, ptr );
ptr = read_from_buffer( &data.c, ptr );
}
您可以进一步封装它并添加错误检查等,并且您有一个很好的二进制流,如接口。