Pergunta

Structs parecer uma maneira útil para analisar um blob binário de dados (ou seja, um arquivo ou pacote de rede). Esta é fino e elegante até que você tenha matrizes de tamanho variável na blob. Por exemplo:

struct nodeheader{
        int flags;
        int data_size;
        char data[];
};

Isto permite-me para encontrar o último caractere de dados:

nodeheader b;
cout << b.data[b.data_size-1];

Problema ser, eu quero ter matrizes de comprimento múltiplas variáveis:

struct nodeheader{
    int friend_size;
    int data_size;
    char data[];
    char friend[];
};

Eu não estou alocando manualmente essas estruturas. Eu tenho um arquivo assim:

char file_data[1024];
nodeheader* node = &(file_data[10]);

Como eu estou tentando analisar um arquivo binário (mais especificamente um arquivo de classe). Eu escrevi uma implementação em Java (que era meu atribuição de classe), não, eu estou fazendo uma versão pessoal em C ++ e estava esperando para fugir sem ter que escrever 100 linhas de código. Alguma idéia?

Obrigado, Stefan

Foi útil?

Solução

Você não pode ter matrizes de tamanhos múltiplos variáveis. Como deve o compilador em tempo de compilação saber onde amigo [] está localizado? A localização do amigo depende do tamanho dos dados [] e o tamanho dos dados é desconhecido em tempo de compilação.

Outras dicas

Esta é uma construção muito perigoso, e eu aconselho contra ele. Você só pode incluir uma matriz de comprimento variável em uma struct quando é o último elemento, e quando você faz isso, você tem que ter certeza que você alocar memória suficiente, por exemplo:.

nodeheader *nh = (nodeheader *)malloc(sizeof(nodeheader) + max_data_size);

O que você quer fazer é usar matrizes alocadas dinamicamente regulares:

struct nodeheader
{
  char *data;
  size_t data_size;
  char *friend;
  size_t friend_size;
};

nodeheader AllocNodeHeader(size_t data_size, size_t friend_size)
{
  nodeheader nh;
  nh.data = (char *)malloc(data_size);  // check for NULL return
  nh.data_size = data_size;
  nh.friend = (char *)malloc(friend_size);  // check for NULL return
  nh.friend_size = friend_size;

  return nh;
}

void FreeNodeHeader(nodeheader *nh)
{
  free(nh->data);
  nh->data = NULL;
  free(nh->friend);
  nh->friend = NULL;
}

Você não pode - pelo menos não da maneira simples que você está tentando. A matriz não-calibrados no final de uma estrutura é basicamente um deslocamento para a extremidade da estrutura, sem acumulação de de modo a encontrar a extremidade.

Todos os campos são convertidos para deslocamentos numéricos em tempo de compilação, então eles precisam ser calculável naquele momento.

As respostas até agora estão seriamente excesso de complicar um problema simples. Mecki está certo sobre por que isso não pode ser feito da maneira que você está tentando fazê-lo, contudo, você pode fazê-lo de forma muito semelhante:

struct nodeheader
{
    int friend_size;
    int data_size;
};

struct nodefile
{
    nodeheader *header;
    char *data;
    char *friend;
};

char file_data[1024];

// .. file in file_data ..

nodefile file;
file.header = (nodeheader *)&file_data[0];
file.data = (char *)&file.header[1];
file.friend = &file.data[file->header.data_size];

Para o que você está fazendo, você precisa de um codificador / decodificador para o formato. O decodificador leva os dados brutos e preenche a sua estrutura (no seu caso alocar espaço para a cópia de cada seção dos dados), e o decodificador escreve binário simples.

(era 'usar std :: vector')

Editar:

Ao ler comentários, acho que deve expandir a minha resposta. Você pode efetivamente caber duas matrizes de comprimento variável em sua estrutura, como se segue, e o armazenamento será liberado automaticamente quando file_data sai do escopo:

struct nodeheader {
    std::vector<unsigned char> data;
    std::vector<unsigned char> friend_buf; // 'friend' is a keyword!
    // etc...
};

nodeheader file_data;

Agora file_data.data.size (), etc dá-lhe o comprimento e e & file_data.data [0] dá-lhe um ponteiro bruto para os dados se você precisar dele.

Você tem que preencher os dados do arquivo a partir do arquivo fragmentada - leia o comprimento de cada buffer, chamada de redimensionamento () no vector de destino, em seguida, ler os dados. (Existem maneiras de fazer isso um pouco mais eficiente. No contexto do arquivo de disco I / O, eu estou supondo que isso não importa).

A técnica de Aliás OP está incorreta mesmo para o seu 'fino e elegante' casos, por exemplo, com apenas um VLA no final.

char file_data[1024];
nodeheader* node = &(file_data[10]);

Não há nenhuma garantia de que file_data está alinhada corretamente para o tipo nodeheader. Prefere obter file_data por malloc () - o que garante a devolver um apontador alinhadas para qualquer tipo - ou então (melhor) declarar o tampão a ser do tipo correcto em primeiro lugar:

struct biggestnodeheader {
    int flags;
    int data_size;
    char data[ENOUGH_SPACE_FOR_LARGEST_HEADER_I_EVER_NEED];
};

biggestnodeheader file_data;
// etc...
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top