C++ 将字符缓冲区转换为结构
我有一个C++ 将字符缓冲区转换为结构,c++,pointers,struct,type-conversion,unsigned-char,C++,Pointers,Struct,Type Conversion,Unsigned Char,我有一个char缓冲区buf包含buf[0]=10,buf[1]=3,buf[2]=3,buf[3]=0,buf[4]=58 以及一个结构: typedef struct { char type; int version; int length; }Header; 我想把buf转换成标题。现在我正在使用这个函数 int getByte( unsigned char* buf) { int number = buf[0]; return number;
char
缓冲区buf
包含buf[0]=10
,buf[1]=3
,buf[2]=3
,buf[3]=0
,buf[4]=58
以及一个结构:
typedef struct
{
char type;
int version;
int length;
}Header;
我想把buf
转换成标题
。现在我正在使用这个函数
int getByte( unsigned char* buf)
{
int number = buf[0];
return number;
}
int getInt(unsigned char* buf)
{
int number = (buf[0]<<8)+buf[1];
return number;
}
main()
{
Header *head = new Header;
int location = 0;
head->type = getByte(&buf[location]);
location++; // location = 1
head->version = getInt(&buf[location]);
location += 2; // location = 3
head->ength = getInt(&buf[location]);
location += 2; // location = 5
}
在这种情况下,
标题
,标题->类型
中的第一个值是正确的,其余值是垃圾。是否可以将无符号字符*buf
转换为头文件
?唯一可移植且安全的方法是:
void convertToHeader(unsigned char const * const buffer, Header *header)
{
header->type = buffer[0];
header->version = (buffer[1] << 8) | buffer[2];
header->length = (buffer[3] << 8) | buffer[4];
}
void convertToHeader(无符号字符常量*常量缓冲区,头*头)
{
表头->类型=缓冲区[0];
标题->版本=(缓冲区[1]长度=(缓冲区[3]类型);
缓冲区[1]=(静态_转换(头->版本)>>8)&0xFF;
缓冲区[2]=标题->版本&0xFF;
缓冲区[3]=(静态广播(头->长度>>8)&0xFF;
缓冲区[4]=标题->长度&0xFF;
}
有关说明,请参阅
编辑
上一个链接的快速总结:其他可能的解决方案(例如memcpy
或union
)根据不同系统的端性而不可移植(这样做可能是为了在至少两个异构系统之间进行某种通信)=>一些系统字节[0]是int和字节[1]的LSB是MSB,另一个是相反的
此外,由于对齐,struct Header
可以大于5个字节(在您的情况下,如果对齐为2个字节,则可能大于6个字节!)(请参见示例)
最后,根据某些平台上的对齐限制和别名规则,编译器可能会生成不正确的代码。您需要的
版本和长度与buf
数组的两个元素长度相同;也就是说,您需要使用中定义的类型uint16\u t
ode>,而不是可能更长的int
。此外,您还需要将buf
设置为uint8\u t
的数组,因为允许字符占用超过1个字节
您可能还需要将type
移到末尾;否则,编译器几乎肯定会在其后面插入一个填充字节,以便能够将version
与2字节边界对齐(一旦将其设置为uint16\u t
,从而设置为2字节);然后将buf[1]
会在那里结束,而不是你想要的。
顺便说一下,这可能就是您现在观察到的情况:通过在char
后面加上int
,这可能是4
字节,您有3
字节的填充,数组的元素1
到3
被插入其中(=永远丢失)
另一个解决方案是将buf
数组修改为更长,并具有空的填充字节,以便数据实际上与struct字段对齐
再次值得一提的是,正如评论中指出的,sizeof(head)
返回系统上指针的大小,而不是头的大小。您可以直接编写sizeof(Header)
;但是在这种微观管理级别上,如果您只编写“5
”就不会失去任何灵活性真的
此外,endianness可能会影响您。处理器没有义务按照您期望的顺序而不是相反的顺序存储数字的字节;两者毕竟都有内在意义。这意味着盲目地将字节buf[0],buf[1]
复制到数字中可能会导致(buf[0]更好的方法是创建某种序列化/反序列化例程
此外,我不仅会使用int
或char
类型,还会使用更具体的int32\u t
等。这只是一种平台独立的方式(实际上,您也可以使用pragma pack打包数据结构)
struct头文件
{
char16_t型;
int32_t版本;
int32_t长度;
};
结构工具
{
std::shared_ptr反序列化标头(常量std::vector和loadedBuffer)
{
std::共享的ptr头(新头);
memcpy(&(*头)、&loadedBuffer[0],sizeof(头));
返回头;
}
std::向量序列化头(常量头和头)
{
向量缓冲区;
resize(sizeof(Header));
memcpy(&buffer[0],&header,sizeof(header));
返回缓冲区;
}
}
工具;
Header={B',58344665};
自动v1=工具。序列化标题(标题);
auto v2=tools.deserializeHeader(v1);
Sizeof a pointer是4或8。你想要Sizeof*headsince int是2字节,char是1字节,head的大小应该是5。我会确认的。@AkhilVSuku 2-byteint
?你使用的是什么平台?不要使用memcpy,这是一种不安全且不可移植的方式。唯一一种完全可移植且安全的方式是你目前所做的(请参阅)如果你不需要移植性,你可以使用编译器特定的特性,一个Stutt的“打包”。这至少是GCC和微软C++编译器的可能。但是这要求目标CPU支持不对齐的访问。因此,你应该提供关于工具链和目标平台和CPU的信息。(Header)是12字节,这是因为Windows中的对齐规则。@veryhit当然,请参见对齐示例(linux with gcc=>12字节)。我编辑以澄清我的答案,因为我只是以用户为例,该用户位于16位平台上。为什么所有的对齐都是显式的(不幸的是C风格的)强制转换为std::uint16\u t
?首先,该类型甚至不能保证存在,我不知道为什么您不使用int
…而且无论如何,shift/&
操作符不执行任何所需的强制转换为int
?(如果存在,它可以保存与uint16\u t
相同的值)
void convertToHeader(unsigned char const * const buffer, Header *header)
{
header->type = buffer[0];
header->version = (buffer[1] << 8) | buffer[2];
header->length = (buffer[3] << 8) | buffer[4];
}
void convertFromHeader(Header const * const header, unsigned char * buffer)
{
buffer[0] = header->type;
buffer[1] = (static_cast<unsigned int>(header->version) >> 8) & 0xFF;
buffer[2] = header->version & 0xFF;
buffer[3] = (static_cast<unsigned int>(header->length) >> 8) & 0xFF;
buffer[4] = header->length & 0xFF;
}
int getTwoBytes(unsigned char* buf)
{
return (buf[0]<<8)+buf[1];
}
main()
{
Header *head = new Header;
head->type = buf[0];
head->version = getTwoBytes(buf + 1);
head->length = getTwoBytes(buf + 3);
}
struct Header
{
char16_t type;
int32_t version;
int32_t length;
};
struct Tools
{
std::shared_ptr<Header> deserializeHeader(const std::vector<unsigned char> &loadedBuffer)
{
std::shared_ptr<Header> header(new Header);
memcpy(&(*header), &loadedBuffer[0], sizeof(Header));
return header;
}
std::vector<unsigned char> serializeHeader(const Header &header)
{
std::vector<unsigned char> buffer;
buffer.resize(sizeof(Header));
memcpy(&buffer[0], &header, sizeof(Header));
return buffer;
}
}
tools;
Header header = {'B', 5834, 4665};
auto v1 = tools.serializeHeader(header);
auto v2 = tools.deserializeHeader(v1);