我试图铸造一个数据流成一个结构,因为数据流中包含的固定宽度的消息,并且每个消息具有定义的固定宽度领域以及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 ++格式从一个消息的数据结构(或类)。举例来说,如果它只是有为了对准你不需要定义的“填充”字段。也许它使一个字段的类型,以比它被intchar[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())只是不添加虚拟的方法或继承,它会覆盖罚款。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top