使用reinterpret_cast<>时出现问题在 c++

发布于 2024-08-14 12:19:14 字数 828 浏览 8 评论 0 原文

我正在尝试将数据流转换为结构,因为数据流由固定宽度消息组成,并且每个消息也具有完整定义的固定宽度字段。我计划创建一个结构体,然后使用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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

弱骨蛰伏 2024-08-21 12:19:14

为了能够打印字符数组,并能够将其与以 null 结尾的字符串区分开来,您需要其他 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;
}

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:

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;
}
悍妇囚夫 2024-08-21 12:19:14

关于缺少空终止符,您是对的。它再次打印“ur”的原因是因为您重复了 header->third 而不是 header->fourth。为什么不直接将这些变量声明为“char”而不是“char[1]”呢?

struct Header 
{
    char msgType;
    char filler;
    char third;
    char fourth;
};

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"?

struct Header 
{
    char msgType;
    char filler;
    char third;
    char fourth;
};
梨涡 2024-08-21 12:19:14

问题不在于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]'.

入怼 2024-08-21 12:19:14
#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(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;
}
如日中天 2024-08-21 12:19:14

根据我的经验,使用 #pragma pack 会引起一些麻烦 - 部分原因是编译器无法正确弹出,但也由于开发人员忘记弹出一个标头。像这样的错误和结构最终会以不同的方式定义,具体取决于编译单元中包含的顺序标头。这是调试的噩梦。

由于这个原因,我尝试不进行内存覆盖——您不能相信您的结构与您期望的数据正确对齐。相反,我创建包含来自“本机”C++ 格式的消息的数据的结构(或类)。例如,如果仅用于对齐目的,则不需要定义“填充”字段。也许字段类型为 intchar[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 be char[4]. As soon as possible, translate the datastream into the "native" type.

南风起 2024-08-21 12:19:14

假设您想继续使用可覆盖结构(这是明智的,因为它避免了 Alexey 代码中的复制),您可以用如下包装器替换原始 char 数组:

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;
};

和您现有的代码应该可以正常工作。

注意。如果需要,您可以向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:

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;
}

Then your generated structures will look like:

struct Header 
{
    FixedStr<1> msgType;
    FixedStr<1> filler;
    FixedStr<1> third;
    FixedStr<40> forty;
};

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文