带拖车的可变尺寸结构

时间:2009-08-10 22:41:01

标签: c++ data-structures

我发布了这个主题earlier,但现在我有一个更具体的问题/问题。

这是我的代码:

#include <cstdlib>
#include <iostream>

typedef struct{
    unsigned int h;
    unsigned int b[];
    unsigned int t;
 } pkt;

 int main(){

    unsigned int* arr = (unsigned int*) malloc(sizeof(int) * 10);
    arr[0] = 0xafbb0000;
    arr[1] = 0xafbb0001;
    arr[2] = 0xafbb0011;
    arr[3] = 0xafbb0111;
    arr[4] = 0xafbb1111;
    arr[5] = 0xafbc0000;
    arr[6] = 0xafbc0001;
    arr[7] = 0xafbc0011;
    arr[8] = 0xafbc0111;
    arr[9] = 0xafbc1111;

    pkt* p = (pkt*) malloc(sizeof(int)*13);
    p->h = 0x0905006a;

    int counter;

这是我得到的         for(counter = 0; counter&lt; 10; counter ++)                 p-> b [counter] = arr [counter];

    p->t = 0x55555555;

    std::cout << "header is \n" << p->h << std::endl;
    std::cout << "body is" << std::endl;
    for(counter=0; counter < 10;++counter)
            std::cout << std::hex << *((p->b)+counter) << std::endl;
    std::cout << "trailer is \n" << p->t << std::endl;

}

这是我得到的

header is 
151322730
body is
55555555
afbb0001
afbb0011
afbb0111
afbb1111
afbc0000
afbc0001
afbc0011
afbc0111
afbc1111
trailer is 
55555555

*(p-> b)被预告片取代!如果我删除了我分配预告片的行,即p-> t = 0x55555555;那么预告片和p-> b是相同的(afbb0000)。

所以我的问题是,我怎样才能保持结构的顶部定义,并让这个数据包正常运行。

编辑:

我应该更清楚。我为网络应用程序写这个,所以我必须制作一个输出按照这个顺序排序的数据包,我通过写入文件并进行十六进制转储来测试它。所以我的问题是:

如何制作带有标题,可变大小的正文和预告片的数据包始终具有此顺序?我能想到的唯一两个解决方案是拥有许多不同的结构,或者有一个向量。

也就是说,我可以在哪里结构

typedef struct{
        unsigned int h;
        unsigned int b[12];
        unsigned int t;
     } pkt1;

typedef struct{
        unsigned int h;
        unsigned int b[102];
        unsigned int t;
     } pkt2;

etc 

或者我可以做

std::vector<unsigned int> pkt (12);
pkt[0] = header;
pkt[1] = data;
...
pkt[2]= data;
pkt[11] = trailer;

我真的不喜欢这两种解决方案。还有更好的方法吗?

此外,这是一个单独的问题,我将不得不做同样的事情来接收数据。做一些事情就像把数据块投射到矢量一样明智吗?我将以无效*的形式接收数据,我将知道最大长度。

6 个答案:

答案 0 :(得分:6)

尝试更新结构,然后添加以下内容:

typedef struct{
    unsigned int h;
    unsigned int* b;
    unsigned int t;
 } pkt;

...
...

pkt p;
p->b = arr

这是一个关于它正在做什么的视觉例子......

|----------------------|
|     header           |
|----------------------|
|     B   int*         |  -------  p->b = arr
|----------------------|        | 
|     trailer          |        |
|----------------------|        v
                              |----------------------| 
                        arr   |                      |
                              |    B items [0 ... N] |
                              |                      |
                              |----------------------|

如果你想变得棘手,你可以做这样的事情......

|----------------------|
|     header           |
|----------------------|
|     B   int*         |  -------  (= to memory address after trailer)
|----------------------|        | 
|     trailer          |        |
|----------------------|        |
|                      | <-------
|    B items [0 ... N] |
|                      |
|----------------------|

以下是后者的工作版本:

#include "stdlib.h"
#include "stdio.h"
#include "malloc.h"

typedef struct{
    unsigned int h;
    unsigned int* b;
    unsigned int t;
 } pkt;

 int main(){

    pkt* p = (pkt*) malloc( sizeof(pkt) + sizeof(int)*10);
    p->h = 0x0905006a;
    p->b = &(p->t)+1;
    p->t = 0x55555555;

    p->b[0] = 0xafbb0000;
    p->b[1] = 0xafbb0001;
    p->b[2] = 0xafbb0011;
    p->b[3] = 0xafbb0111;
    p->b[4] = 0xafbb1111;
    p->b[5] = 0xafbc0000;
    p->b[6] = 0xafbc0001;
    p->b[7] = 0xafbc0011;
    p->b[8] = 0xafbc0111;
    p->b[9] = 0xafbc1111;

    int counter;
    printf( "header is \n" );
    printf( "%0x\n", p->h);
    printf( "body is\n" );
    for(counter=0; counter < 10;++counter)
            printf( "%0x\n", (p->b)[counter]);
    printf( "trailer is\n" );
    printf( "%0x\n", p->t );
 }

答案 1 :(得分:4)

基本上,你不能。我很惊讶这甚至可以编译。您只允许将没有指定大小的数组作为结构的最后一个元素,因为结构在C / C ++中的基本方式。

问题是编译器必须知道b []有多大才能知道在struct中找到t的位置。通常它通过查看数组大小来实现。由于你没有传递一个大小,你的编译器显然将它视为零,这意味着b []和t实际上在内存中的相同位置!你需要在struct声明中指定b []的大小,或者你需要在b []之前移动t。

答案 2 :(得分:2)

C ++解决方案:

#include <iostream>
using namespace std;

class Packet
{
public:
  Packet (int body_size) :
    m_body_size (body_size)
  {
    m_data = new int [m_body_size + 2];
  }

  ~Packet ()
  {
    delete [] m_data;
    m_data = 0;
  }

  int &Header ()
  {
    return m_data [0];
  }

  int &Trailer ()
  {
    return m_data [m_body_size + 1];
  }

  int Size ()
  {
    return m_body_size;
  }

  int *Data ()
  {
    return m_data;
  }

  int &operator [] (int index)
  {
    return m_data [index + 1];
  }

  //  helper to write class data to an output stream
  friend ostream &operator << (ostream &out, Packet &packet)
  {
    out << "Header = " << packet.Header () << endl;
    out << "Data [" << packet.Size () << "]:" << endl;

    for (int i = 0 ; i < packet.Size () ; ++i)
    {
      out << "  [" << i << "] = 0x" << hex << packet [i] << endl;
    }

    out << "Trailer = " << packet.Trailer () << endl;

    return out;
  }

private:
  int
    m_body_size,
    *m_data;
};

//  simple test function for Packet class
int main ()
{
  Packet
    packet (10);

  packet.Header () = 0x0905006a;
  packet [0] = 0xafbb0000;
  packet [1] = 0xafbb0001;
  packet [2] = 0xafbb0011;
  packet [3] = 0xafbb0111;
  packet [4] = 0xafbb1111;
  packet [5] = 0xafbc0000;
  packet [6] = 0xafbc0001;
  packet [7] = 0xafbc0011;
  packet [8] = 0xafbc0111;
  packet [9] = 0xafbc1111;
  packet.Trailer () = 0x55555555;

  cout << packet;
}

我没有把错误检查或const访问器,你可以检查数组访问。接收数据非常简单:

Packet Read (stream in)
{
   get size of packet (exluding header/trailer)
   packet = new Packet (size)
   in.read (packet.Data, size + 2)
   return packet
}

答案 3 :(得分:1)

如果你改变了

typedef struct{
    unsigned int h;
    unsigned int b[];
    unsigned int t;
} pkt;

typedef struct{
    unsigned int h;
    unsigned int *b;
    unsigned int t;
} pkt;

我相信它会奏效。这样,bt将各自占用自己的空间,而不是相同的空间。您还需要将malloc(sizeof(int) * 13);更改为malloc(sizeof(pkt)); - malloc()的大小将保持不变,并且您需要malloc()两次 - struct一次},和b中的数组一次。当然,无论如何你已经这样做了,但这样你就不会浪费堆空间。

如果您想使用b[]代替*b(并且有正当理由),您需要将其放在最后。抱歉。这就是黑客的工作方式。

答案 4 :(得分:1)

当你在struct中声明unsigned int b []时,它没有为它分配任何空间。所以当您取消引用结构指针时,pkt.b和pkt.t是相同的位置。你可以使b []成为结构中的最后一个字段。

但是,如果您想要关注b,那么您可以尝试以下C示例:

#include <stdio.h>
#include <malloc.h>

#define PKT_STRUCT(size) struct{unsigned int h;unsigned int b[size];unsigned int t;}

int main(void)
{

    PKT_STRUCT(10) *pkt  = malloc(sizeof(PKT_STRUCT(10)));

    pkt->h = 0x0905006a;

    pkt->b[0] = 0xafbb0000;
    pkt->b[1] = 0xafbb0001;
    pkt->b[2] = 0xafbb0011;
    pkt->b[3] = 0xafbb0111;
    pkt->b[4] = 0xafbb1111;
    pkt->b[5] = 0xafbc0000;
    pkt->b[6] = 0xafbc0001;
    pkt->b[7] = 0xafbc0011;
    pkt->b[8] = 0xafbc0111;
    pkt->b[9] = 0xafbc1111;

    pkt->t = 0x55555555;

    printf("Header:  %x\n", pkt->h);

    printf("Body:\n");
    int i;
    for(i=0; i<10; ++i)
        printf("%x\n", pkt->b[i]);

    printf("Tail:  %x\n", pkt->t);


    return 0;
}

如果您正在使用已打包的数据,这可能很有用。

此外,您可以使用不同数据包大小/结构的并集。

答案 5 :(得分:1)

如果你已经标记了问题C ++,你总是可以使用vector&lt; int&gt;而不是int []。更好的是,让pkt成为一个类并隐藏客户端的内部表示。然后,您将拥有标题和预告片的访问者以及正文的索引器。