【问题标题】:Loading binary file to unknown struct type将二进制文件加载到未知的结构类型
【发布时间】:2018-12-08 19:41:42
【问题描述】:

我在读取二进制文件并将其转换为未知类型的结构时遇到问题...

  • 我真的应该避免在我的电脑中使用保存/加载功能吗? 链表代码?
  • 是不是因为我使用的 GCC 编译器栈 具有更多数据的结构可以方便地存储在内存中,并且由于 加载函数时不知道这个“偏移量”?

我正在用 C 语言编写一个通用链表,它是一个头文件,所以我可以在任何地方使用它。由于它将是一个泛型类型列表,标题将不知道列表中的数据类型(我正在查看混合类型,所以是结构)。为了保存数据,我只传递从 sizeof(struct) 中提取的数据地址和长度。读取是相同的概念,使用 fread(container, sizeof(struct), 1, FILE),由调用程序传递,再次使用 sizeof(struct) 提取 se size。但在实践中,它不起作用......

#ifndef LINKEDLIST_H_INCLUDED
#define LINKEDLIST_H_INCLUDED
#include <string.h>

typedef struct tagNode{
    void            *data;
    struct tagNode  *next_Node;
} Node;

typedef struct tagLinkedList{
    Node *Head;
    int   Size;
} LinkedList;

int LinkedList_New(LinkedList *llist){
    llist->Head = NULL;
    llist->Size = 0;
    return 1;
}

int LinkedList_Insert(LinkedList *llist, int index, void *Data, size_t s_Data){
    int cur_index = 0;
    if(index > llist->Size || index < 0)
        index = 0;

    Node *newNode = malloc(sizeof(Node));
    newNode->data = malloc(s_Data);
    if(newNode       == NULL){return 0;}
    if(newNode->data == NULL){return 0;}
    newNode->data = Data;

    Node *currentNode = llist->Head;
    Node *lastNode    = llist->Head;

    if(index == 0){
        newNode->next_Node = llist->Head;
        llist->Head = newNode;
    }else{
        while(llist->Head->next_Node != NULL && cur_index != index){
            if(cur_index == index){
                newNode->next_Node  = currentNode;
                lastNode->next_Node = newNode;
            }else{
                lastNode    = currentNode;
                currentNode = currentNode->next_Node;
                cur_index++;
            }
        }
    }
    llist->Size += 1;
}

int LinkedList_Save(char *Path, LinkedList *llist, size_t sData){
    FILE *fp;
    fp = fopen(Path, "w");
    if(fp == NULL){return -1;}

    Node *currentNode;
    currentNode = llist->Head;

    while(currentNode != NULL){
        fwrite(currentNode->data, sData, 1, fp);
        currentNode = currentNode->next_Node;
    }
    fclose(fp);
    return 1;
}

int LinkedList_Load(char *Path, LinkedList *llist, size_t sData){
    FILE *fp;
    fp = fopen(Path, "r");
    if(fp == NULL){fclose(fp);return -1;}

    while(!feof(fp)){
        void *Data = malloc(sData);
        if(Data == NULL){fclose(fp);return -1;}
        fread(Data, sData, 1, fp);
        LinkedList_Insert(llist, 0, Data, sData);
    }
    fclose(fp);
    return 1;
}
#endif // LINKEDLIST_H_INCLUDED

还有我目前的测试对象:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../LinkedList.h"
typedef struct{
    int a;
    char b[5];
} tempo;

int main(){
    tempo teste = {5, "oito"};

    LinkedList lista;
    LinkedList_New(&lista);
    LinkedList_Insert(&lista, 0, &teste, sizeof(tempo));
    LinkedList_Save("data.txt", &lista, sizeof(tempo));
    printf("%s", ((tempo*)lista.Head->data)->b);
    LinkedList ls2;
    LinkedList_New(&ls2);
    LinkedList_Load("data.txt", &ls2, sizeof(tempo));

    printf("%s", ((tempo*)ls2.Head->data)->b);

    return 1;
}

第一个 printf 向我显示了结构中的 b 变量,这意味着列表按预期工作。

但是第二个 printf,如果用于显示 a 变量(int),我会得到一个随机数(类似于 8712382),如果用于显示 b 变量,我会得到“L”

【问题讨论】:

  • 正在读取的二进制数据是否在相同类型的环境中生成以避免字节顺序问题?另外,您是否正在考虑结构填充? (从读入二进制文件到读回)
  • 好吧,因为我将 de sData 作为结构的 de 大小传递,我从 fp 文件将 sData 大小的 1 块读取到 Data 变量中,还是我错了?我的意思是,如果 sData 是 12,我将 12 字节的 1 次读取到数据存储中,对吗?另外,是的,它都是动态生成的,在相同的环境中,正如在发布的第二个代码块中看到的那样
  • 没问题,我看看结构打包,但由于它都发生在同一个环境中,程序应该知道如何正确对齐数据,或者我认为......
  • 您查看过它生成的文件吗? 1 条记录的大小合适吗? char数组也应该很明显
  • 同样,如果用于通用目的,建议小心长度,从sizeof(struct)中提取。确保您了解包装、填充和对齐边界。关于那个HERE的东西。

标签: c linked-list save file-read


【解决方案1】:

您的 LinkedList_load 函数有问题。将其更新为以下

int LinkedList_Load(char *Path, LinkedList *llist, size_t sData){
        FILE *fp;
        fp = fopen(Path, "rb");
        if(fp == NULL){fclose(fp);return -1;}
        fseek(fp,0L,SEEK_SET);
        while(!feof(fp)){
                void *Data = malloc(sData);
                if(Data == NULL){fclose(fp);return -1;}
                int readed=fread(Data, sData, 1, fp);
                if(readed==0){return -1;}
                /*you were displaying the last reading that contains 
                *nothing, the previous check solves the problem.
                */
                printf("readed %d items:  \n",readed);
                LinkedList_Insert(llist, 0, Data, sData);       
        }
       fclose(fp);

}

【讨论】:

  • 您添加的if 在最后一个Data 上有内存泄漏。应该是if (readed == 0) { free(Data); return -1; }
  • 我不这么认为,这并不意味着内存泄漏; fread读取有问题返回0,与Data指针无关。
  • 我想我明白了!正确读取所有寄存器后,文件仍不处于 EOF 状态。如文件中的 12 个字节,读取 12 个字节,所以现在我在文件的第 12 个字节中。虽然仍然没有在 EOF 中,但新的运行已经完成,在第一个索引中写入了一个垃圾内存!我已经检查了编译器,列表长度也是 2.... 谢谢指出!
  • 是的,它内存泄漏。 Data 来自malloc,它在fread 之前 完成。如果您返回 而不Data 附加到链接列表,则它会挂起(即)内存泄漏。因此,您必须在返回之前释放它。
猜你喜欢
  • 2011-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多