C语言读取TLV数据写入文本文件

问题遇到的现象和发生背景
用代码块功能插入代码,请勿粘贴截图
我的解答思路和尝试过的方法

使用文件指针,先读取tag及length,再读取value,读文件读两遍,再写入文本文件

img

我想要达到的结果

文件中有若干程序,把他们全都读取出来,按照length降序,tag降序规则读取出来将所有数据排序以文件形式保存到文本文件中
格式为
No://10进制连续
tag: //16进制 2Byte
len: //10进制
val ://16进制如果length为0则不显示
示例
no:64237
tag:08 6E
len:17
val:5C F0 5F B9 20 1E B1

你应该先读Header,然后算出val数组的大小,再读val的数据

#include <stdio.h>
#include <stdlib.h>
 
struct Header {
  unsigned int no;
  unsigned char tag[2];
  unsigned int len;
};
 
struct Program {
  struct Header header;
  unsigned char *val;
};
 
struct Node {
  struct Program *program;
  struct Node *prev;
  struct Node *next;
};
 
unsigned int program_data_size(const struct Header *header) {
  unsigned int size = 0;
  if (header->len > sizeof(struct Header))
    size = header->len - sizeof(struct Header);
  return size;
}
 
struct Program *alloc_program(const struct Header *header) {
  struct Program *program = (struct Program *)malloc(sizeof(struct Program));
  program->header = *header;
  unsigned int size = program_data_size(header);
  if (size > 0)
    program->val = (unsigned char *)malloc(size);
  else
    program->val = NULL;
  return program;
}
 
void free_program(struct Program *program) {
  free(program->val);
  free(program);
}
 
struct Program *read_program(FILE *file) {
  if (feof(file))
    return NULL;
 
  struct Header header;
  if (fread(&header, sizeof(struct Header), 1, file) != 1) {
    perror("failed to read header");
    return NULL;
  }
 
  struct Program *program = alloc_program(&header);
  unsigned int size = program_data_size(&header);
  if (fread(program->val, sizeof(unsigned char), size, file) != size) {
    perror("corrupted file");
    free_program(program);
    return NULL;
  }
 
  return program;
}
 
void add_to_list(struct Node **list, struct Program *program) {
  if (*list == NULL) {
    struct Node *p = (struct Node *)malloc(sizeof(struct Node));
    p->program = program;
    p->prev = NULL;
    p->next = NULL;
    *list = p;
    return;
  }
 
  struct Node *prev = (*list)->prev;
  struct Node *p = *list;
  while (p) {
    if (p->program->header.len < program->header.len ||
        (p->program->header.len == program->header.len &&
         p->program->header.tag < program->header.tag))
      break;
    prev = p;
    p = p->next;
  }
 
  struct Node *q = (struct Node *)malloc(sizeof(struct Node));
  q->program = program;
  q->next = p;
  q->prev = prev;
  if (prev)
    prev->next = q;
  if (p)
    p->prev = q;
}
 
void destroy_list(struct Node *list) {
  struct Node *p = list;
  while (p) {
    free_program(p->program);
    struct Node *q = p;
    p = p->next;
    free(q);
  }
}
 
void print_program_to_file(const struct Program *program, FILE *file) {
  fprintf(file, "no:%d\n", program->header.no);
  fprintf(file, "tag:%02X %02X\n", program->header.tag[0],
          program->header.tag[1]);
  fprintf(file, "len:%d\n", program->header.len);
  fprintf(file, "value:");
  unsigned int size = program_data_size(&program->header);
  for (unsigned int i = 0; i < size; i++) {
    fprintf(file, "%02X", program->val[i]);
    if (i < size - 1)
      fprintf(file, " ");
  }
  fprintf(file, "\n");
}
 
void print_list_to_file(const struct Node *list, FILE *file) {
  const struct Node *p = list;
  while (p) {
    print_program_to_file(p->program, file);
    p = p->next;
  }
}
 
int main() {
  FILE *in_file = fopen("input.bin", "rb");
  if (!in_file) {
    perror("failed to open input.bin");
    return 1;
  }
  struct Node *list = NULL;
  struct Program *program = NULL;
  while ((program = read_program(in_file)) != NULL)
    add_to_list(&list, program);
  fclose(in_file);
 
  FILE *out_file = fopen("output.txt", "w");
  if (!out_file) {
    perror("failed to open output.txt");
    return 2;
  }
  print_list_to_file(list, out_file);
  fclose(out_file);
 
  destroy_list(list);
  return 0;
}

对TLV的操作,可以参考之前写的这个demo程序
TLV 格式及编解码示例_来灵的博客-CSDN博客_tlv编码

有没有大佬能不用双向链表,用正常的指针操作读取写入文件啊,就先读tag 和length再读value,最后写入

先读Tag,根据Tag,调用不同的解释器处理Value,完成后,指针根据Length的长度移动,重复前面的步骤。