문제

Structs는 이진의 데이터를 구문 분석하는 유용한 방법처럼 보입니다 (즉, 파일 또는 네트워크 패킷). 블로브에 가변적 인 크기 배열이있을 때까지 이것은 괜찮고 멋지다. 예를 들어:

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

이를 통해 마지막 데이터 문자를 찾을 수 있습니다.

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

문제는 여러 가변 길이 배열을 원합니다.

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

이 구조를 수동으로 할당하지 않습니다. 그런 파일이 있습니다.

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

이진 파일을 구문 분석하려고 할 때 (특히 클래스 파일). 나는 Java (내 클래스 과제 인)에서 구현을 작성했는데, C ++에서 개인 버전을 수행하고 있으며 100 줄의 코드를 쓰지 않고 도망 치기를 바랐습니다. 어떤 아이디어?

감사합니다, 스테판

도움이 되었습니까?

해결책

여러 가변 크기의 배열을 가질 수 없습니다. 컴파일 타임의 컴파일러는 친구 []가 어디에 있는지 알아야합니까? 친구의 위치는 데이터 크기 []의 크기에 따라 다르며 컴파일 시간에 데이터의 크기는 알려져 있지 않습니다.

다른 팁

이것은 매우 위험한 구조이며, 나는 그것에 대해 조언합니다. 마지막 요소 일 때 구조물에 가변 길이 배열 만 포함 할 수 있으며, 그렇게하면 충분한 메모리를 할당해야합니다.

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

당신이하고 싶은 것은 정기적으로 동적으로 할당 된 배열을 사용하는 것입니다.

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

당신은 - 적어도 당신이 시도하는 단순한 방법은 아닙니다. 구조의 끝에있는 미확인 배열은 기본적으로 구조의 끝 부분에 오프셋이며, 끝을 찾을 수있는 빌드 방법이 없습니다.

모든 필드는 컴파일 타임에 숫자 오프셋으로 변환되므로 그 당시에 계산할 수 있어야합니다.

지금까지의 답변은 간단한 문제를 심각하게 복제하고 있습니다. Mecki는 왜 그렇게하려고하는 방식으로 할 수없는 이유에 대해 옳지 만, 당신은 그것을 매우 유사하게 할 수 있습니다.

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

당신이하고있는 일을 위해 당신은 형식에 인코더/디코더가 필요합니다. 디코더는 원시 데이터를 가져 와서 구조를 작성하고 (귀하의 경우 데이터의 각 섹션의 사본에 대한 공간을 할당하는 경우) 디코더는 원시 바이너리를 씁니다.

( 'std :: vector')

편집하다:

피드백을 읽을 때 대답을 확장해야한다고 생각합니다. 다음과 같이 구조의 두 가지 가변 길이 배열을 효과적으로 맞출 수 있으며 File_Data가 범위를 벗어나면 스토리지가 자동으로 해제됩니다.

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

nodeheader file_data;

이제 file_data.data.size () 등은 길이를 제공하고 & file_data.data [0]는 필요한 경우 데이터에 대한 원시 포인터를 제공합니다.

파일 단편에서 파일 데이터를 채워야합니다 - 각 버퍼의 길이를 읽고 대상 벡터의 resize ()를 호출 한 다음 데이터를 읽습니다. (이것을 약간 더 효율적으로 수행하는 방법이 있습니다. 디스크 파일 I/O의 맥락에서, 나는 그것이 중요하지 않다고 가정합니다).

우연히 OP의 기술은 그의 '미세하고 댄디'사례, 예를 들어, 마지막에는 하나의 VLA 만있는 경우에도 부정확합니다.

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

NodeHeader 유형에 대해 file_data가 올바르게 정렬되어 있음을 보장 할 수 없습니다. malloc ()에 의해 file_data를 얻는 것을 선호합니다.

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

biggestnodeheader file_data;
// etc...
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top