如何声明未知大小的结构?

时间:2016-10-17 09:56:17

标签: c++

我有这个结构:

  struct          __attribute__((packed)) BabelPacket
  {
    unsigned      senderId;
    unsigned      dataLength;
    unsigned char data[0];
  };

并宣布我这样做:

  BabelPacket *packet = reinterpret_cast<BabelPacket *>(new char[sizeof(BabelPacket) + 5]);
  packet->senderId = 1;
  packet->data = "kappa";
  packet->dataLength = 5;

但是当我编译时,我有这个错误:

error: incompatible types in assignment of ‘const char [6]’ to ‘unsigned char [0]’
   packet->data = "kappa";

            ^

您知道我该怎么做吗? 我需要通过套接字发送这个结构,以便将对象放回我的服务器中,所以我只能使用C类型。

3 个答案:

答案 0 :(得分:3)

如果这是一个C程序,你得到的错误是因为你试图分配给一个数组,这是不可能的。您只能复制到数组:

memcpy(packet->data, "kappa", 5);

另请注意,如果您希望数据为C字符串,则需要为字符串终结符'\0'分配一个额外字符。然后,您可以使用strcpy代替上面的memcpy。或者strncpy最多可以复制特定数量的字符,但是您可能需要手动终止该字符串。

但是,这根本不适用于C ++,除非您的编译器将其作为扩展名。

答案 1 :(得分:0)

您无法通过该方式指定文字字符串。您需要为字符串分配额外的内存,然后复制到数据指针。

struct A {
    size_t datasize;
    char data[0]; // flexible member must appear last.
};

A* create_A(const char* str)
{
    size_t datasize = strlen(str) + 1; // null terminated (?)
    A* p = reinterpret_cast<A*>(new char[sizeof(A) + datasize]);
    memcpy(p->data, str, datasize);
    p->datasize = datasize;
    return p;
}

A* p = create_A("data string");

此解决方案仅适用于支持零长度或灵活阵列的环境。实际上,更好的解决方案可能是在C中编写套接字代码并导出该接口以便在C ++中使用。

答案 2 :(得分:-1)

如果您愿意/允许将unsigned char更改为常规char,则可以使用strcpy

#include <iostream>
#include <stdio.h>
#include <string.h>

struct          __attribute__((packed)) BabelPacket
{
  unsigned      senderId;
  unsigned      dataLength;
  char data[0]; // I changed this to char in order to use strcpy
};

int main(){
  BabelPacket *packet = reinterpret_cast<BabelPacket *>(new char[sizeof(BabelPacket) + 5]);
  packet->senderId = 1;
  // Copy the string. Add NULL character at the end of 
  // the string to indicate its end
  strcpy(packet->data, "kappa\0"); 
  packet->dataLength = 5;

  // Verify that the string is copied properly
  for (int i=0;i<packet->dataLength;++i){
    std::cout<<packet->data[i];
  }
  std::cout<<std::endl;

  return 0;
}

请注意,仅当data位于struct的末尾时才会有效,否则没有连续的内存来分配data。如果我将元素的顺序交换为:

struct          __attribute__((packed)) BabelPacket
{
  unsigned      senderId;
  char data[0]; // I changed this to char in order to use strcpy
  unsigned      dataLength;
};

上面代码的输出(而不是&#34; kappa&#34;)将是&#34; a&#34;。

如果您决定使用C数组,更可靠的方法是假设最大数量的元素并预先分配数组,即:

#include <iostream>
#include <stdio.h>
#include <string.h>

#define MAX_NUMBER_OF_CHARACTERS 5 // Many ways to do this, I defined the macro for the purposes of this example

struct          __attribute__((packed)) BabelPacket
{
  unsigned      senderId;
  // I changed this to char in order to use strcpy. Allocate the
  // max number + 1 element for the termination string
  char data[MAX_NUMBER_OF_CHARACTERS+1]; 
  unsigned      dataLength;
};

int main(){
  BabelPacket *packet = reinterpret_cast<BabelPacket *>(new char[sizeof(BabelPacket) + 5]);
  packet->senderId = 1;
  packet->dataLength = 5;
  if (dataLength>MAX_NUMBER_OF_CHARACTERS){
    std::cout<<"String greater than the maximum number of characters"<<std::endl;
  }
  // Copy the string. Add NULL character at the end of 
  // the string to indicate its end
  strcpy(packet->data, "kappa\0");  

  // Verify that the string is copied properly
  for (int i=0;i<packet->dataLength;++i){
    std::cout<<packet->data[i];
  }
  std::cout<<std::endl;

  return 0;
}

此代码生成正确的输出,并保护您免受违规。正如您所看到的,它可能会很快变得混乱,这就是我建议使用std::vector的原因。然后可以自动检索dataLength作为向量的大小,并始终保护您免受溢出。