在c中使用的reinterpret_cast <>问题++
-
18-09-2019 - |
题
我试图铸造一个数据流成一个结构,因为数据流中包含的固定宽度的消息,并且每个消息具有定义的固定宽度领域以及fulle。我打算建立一个结构,然后使用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
我觉得四,我们和UR是印刷,因为它无法找到空终止符。如何围绕空终止的问题得到什么?
解决方案
在为了能够打印字符数组,并能够从一个空终止字符串区分它,则需要其他operator<<
定义:
template< size_t N >
std::ostream& operator<<( std::ostream& out, char (&array)[N] ) {
for( size_t i = 0; i != N; ++i ) out << array[i];
return out;
}
其他提示
您说得对,缺少空终止的。它的打印“UR”再次的原因是因为你重复报头 - >第三,而不是报头 - >第四。代替“炭[1]”,为什么不宣布这些变量为“字符”?
struct Header
{
char msgType;
char filler;
char third;
char fourth;
};
在问题没有的reinterpret_cast(虽然使用它是一个非常糟糕的主意),但在该类型的结构体的事情。它们应该是类型“字符”,类型不是“字符[1]”。
的#pragma pack(push,1)
template<int N>
struct THeader
{
char msgType[1+N];
char filler[1+N];
char third[1+N];
char fourth[1+N];
};
typedef THeader<0> Header0;
typedef THeader<1> Header1;
Header1 Convert(const Header0 & h0) {
Header1 h1 = {0};
std::copy(h0.msgType, h0.msgType + sizeof(h0.msgType)/sizeof(h0.msgType[0]), h1.msgType);
std::copy(h0.filler, h0.filler+ sizeof(h0.filler)/sizeof(h0.filler[0]), h1.filler);
std::copy(h0.third , h0.third + sizeof(h0.third) /sizeof(h0.third [0]), h1.third);
std::copy(h0.fourth, h0.fourth+ sizeof(h0.fourth)/sizeof(h0.fourth[0]), h1.fourth);
return h1;
}
#pragma pack(pop)
int main(void)
{
cout << sizeof(Header) << endl;
char* data = "four";
Header0* header0 = reinterpret_cast<Header*>(data);
Header1 header = Convert(*header0);
cout << header.msgType << endl;
cout << header.filler << endl;
cout << header.third << endl;
cout << header.fourth << endl;
return 0;
}
在我的经验,使用#pragma pack
已引起头痛 - 部分原因是由于编译器不能正确弹出,而且由于开发商庄子在一个头弹出。这样一个错误和结构最终有不同的定义,这取决于顺序标头获得包括在编译单元。这是一个调试梦魇。
我尽量不要因为这个原因做内存覆盖 - 你不能信任你的结构正确地与您所期待中的数据一致。相反,我创建包含在“本机” C ++格式从一个消息的数据结构(或类)。举例来说,如果它只是有为了对准你不需要定义的“填充”字段。也许它使一个字段的类型,以比它被int
被char[4]
更有意义。只要可能,在所有的数据流转换为“本机”类型。
假设你想要使用overlayable结构,以保持(这是明智的,因为它避免了在阿列克谢代码副本),您就可以使用下面的包装更换您的原始字符数组:
template <int N> struct FixedStr {
char v[N];
};
template <int N>
std::ostream& operator<<( std::ostream& out, FixedStr const &str) {
char const *nul = (char const *)memchr(str.v, 0, N);
int n = (nul == NULL) ? N : nul-str.v;
out.write(str.v, n);
return out;
}
然后,你的生成结构将是这样的:
struct Header
{
FixedStr<1> msgType;
FixedStr<1> filler;
FixedStr<1> third;
FixedStr<40> forty;
};
和现有的代码应该可以正常工作。
NB。你可以添加方法,以FixedStr如果你想(如std::string FixedStr::toString()
)只是不添加虚拟的方法或继承,它会覆盖罚款。