我正在尝试将数据流转换为结构,因为数据流由固定宽度消息组成,并且每个消息也具有完整定义的固定宽度字段。我计划创建一个结构体,然后使用reinterpret_cast 将指向数据流的指针转换为该结构体以获取字段。我编写了一些测试代码并得到了奇怪的结果。可以解释一下为什么我得到这些或如何更正代码。 (数据流将是二进制和字母数字混合的,但我只是用字符串进行测试)
#pragma pack(push,1)
struct Header
{
char msgType[1];
char filler[1];
char third[1];
char fourth[1];
};
#pragma pack(pop)
int main(void)
{
cout << sizeof(Header) << endl;
char* data = "four";
Header* header = reinterpret_cast<Header*>(data);
cout << header->msgType << endl;
cout << header ->filler << endl;
cout << header->third << endl;
cout << header->fourth << endl;
return 0;
}
出现的结果是
4
four
our
ur
r
我认为四个,我们的和你正在打印,因为它找不到空终止符。如何解决空终止符问题?
I am trying to cast a datastream into a struct since the datastream consists of fixed-width messages and each message has fulle defined fixed width fields as well. I was planning on creating a struct and then using reinterpret_cast to cast pointer to the datastream to the struct to get the fields. I made some test code and get weird results. Could any explain why I am getting these or how to correct the code. (the datastream will be binary and alpha numeric mixed but im just testing with strings)
#pragma pack(push,1)
struct Header
{
char msgType[1];
char filler[1];
char third[1];
char fourth[1];
};
#pragma pack(pop)
int main(void)
{
cout << sizeof(Header) << endl;
char* data = "four";
Header* header = reinterpret_cast<Header*>(data);
cout << header->msgType << endl;
cout << header ->filler << endl;
cout << header->third << endl;
cout << header->fourth << endl;
return 0;
}
The result that are coming up are
4
four
our
ur
r
I think the four, our and ur is printing since it cant find the null terminator. How do I get around the null terminator issue?
发布评论
评论(6)
为了能够打印字符数组,并能够将其与以 null 结尾的字符串区分开来,您需要其他
operator<<
定义:In order to be able to print an array of chars, and being able to distinguish it from a null-terminated string, you need other
operator<<
definitions:关于缺少空终止符,您是对的。它再次打印“ur”的原因是因为您重复了 header->third 而不是 header->fourth。为什么不直接将这些变量声明为“char”而不是“char[1]”呢?
You're right about the lack of null terminator. The reason it's printing "ur" again is because you repeated the header->third instead of header->fourth. Instead of "char[1]", why not just declare those variables as "char"?
问题不在于reinterpret_cast(尽管使用它是一个非常糟糕的主意),而在于结构中事物的类型。它们应该是“char”类型,而不是“char[1]”类型。
The issue is not reinterpret_cast (although using it is a very bad idea) but in the types of the things in the struct. They should be of type 'char', not of type 'char[1]'.
根据我的经验,使用
#pragma pack
会引起一些麻烦 - 部分原因是编译器无法正确弹出,但也由于开发人员忘记弹出一个标头。像这样的错误和结构最终会以不同的方式定义,具体取决于编译单元中包含的顺序标头。这是调试的噩梦。由于这个原因,我尝试不进行内存覆盖——您不能相信您的结构与您期望的数据正确对齐。相反,我创建包含来自“本机”C++ 格式的消息的数据的结构(或类)。例如,如果仅用于对齐目的,则不需要定义“填充”字段。也许字段类型为
int
比char[4]
更有意义。尽快将数据流转换为“本机”类型。In my experience, using
#pragma pack
has caused headaches -- partially due to a compiler that doesn't correctly pop, but also due to developers forgetting to pop in one header. One mistake like that and structs end up defined differently depending on which order headers get included in a compilation unit. It's a debugging nightmare.I try not to do memory overlays for that reason -- you can't trust that your struct is properly aligned with the data you are expecting. Instead, I create structs (or classes) that contain the data from a message in a "native" C++ format. For example, you don't need a "filler" field defined if it's just there for alignment purposes. And perhaps it makes more sense for the type of a field to be
int
than for it to bechar[4]
. As soon as possible, translate the datastream into the "native" type.假设您想继续使用可覆盖结构(这是明智的,因为它避免了 Alexey 代码中的复制),您可以用如下包装器替换原始 char 数组:
然后您生成的结构将如下所示:
和您现有的代码应该可以正常工作。
注意。如果需要,您可以向FixedStr 添加方法(例如,
std::stringFixedStr::toString()
),只是不要添加虚拟方法或继承,它会很好地覆盖。Assuming you want to keep using an overlayable struct (which is sensible, since it avoids the copy in Alexey's code), you can replace your raw char arrays with a wrapper like the following:
Then your generated structures will look like:
and your existing code should work fine.
NB. you can add methods to FixedStr if you want (eg,
std::string FixedStr::toString()
) just don't add virtual methods or inheritance, and it will overlay fine.