Почему неправильно использовать C для изменения двойного двоичного файла? - PullRequest
0 голосов
/ 27 марта 2019

Я написал функцию, которая читает двойное значение в структуре в двоичном файле, вычисляет значение и затем записывает вычисленное двойное значение в двоичный файл.

структура:

struct logData{
    long logId; 
    char logDate[11]; 
    char logNote[20];  
    double charge;   
    double total;    
};

Функция для чтения и изменения данных charge это:

long size = sizeof(struct logData);

void update(FILE* fp, int n){
    fseek(fp,(n-1)*size, SEEK_SET);
    struct logData thisLogData;
    fread(&thisLogData,size,1,fp);

    long offset = sizeof(thisLogData.logId)+sizeof(thisLogData.logNote)+ sizeof(thisLogData.logDate);
    double oldCharge = thisLogData.charge;
    scanf("%lf", &thisLogData.charge);
    fseek(fp, -size+offset, SEEK_CUR);
    fwrite(&thisLogData.charge, sizeof(thisLogData.charge), 1, fp);
    fclose(fp);
}

Много структур: logDataхранится в двоичном файле.Параметр: n представляет позицию logData.

Я успешно прочитал предыдущее значение charge (oldCharge в функции update()).Начальное значение заряда - 20, я ввожу 40 в функции update.После успешного написания я прочитал значение charge и обнаружил, что это не 20 и не 40, а странное значение 32,55 (я сохранил два десятичных знака).

Я пытался изменить logDate и logNoteможет быть успешно изменено (конечно, offset отличается).Только двойные значения charge и total будут иметь странные результаты.

В чем причина?

Ответы [ 4 ]

4 голосов
/ 27 марта 2019
long offset = sizeof(thisLogData.logId)+sizeof(thisLogData.logNote)+ sizeof(thisLogData.logDate);

Это не смещение члена.Члены структуры имеют отступы.Используйте offsetof.

size_t offset = offsetof(struct logData, charge);
4 голосов
/ 27 марта 2019

Вы прочитали полные logData , вы можете изменить элемент read, а затем записать все его, возможно, у вас проблема с заполнением, поэтому вычисленное смещение неверно

bool update(FILE* fp, int n){
    struct logData thisLogData;

    if ((fseek(fp,(n-1)*size, SEEK_SET) == -1) ||
        (fread(&thisLogData,size,1,fp) == 1)) {
      ??? indicate error ???
      fclose(fp);
      return false;
    }
    if (scanf("%lf", &thisLogData.charge) != 1) {
      ??? indicate error ???
      fclose(fp);
      return false;
    }
    fseek(fp,(n-1)*size, SEEK_SET);

    return ((fwrite(&thisLogData,size,1,fp) != -1)
            & (fclose(fp) != -1); /* not && because have to close in all cases */
}

, иначе используйте offsetof только для записи нового значения заряда без чтения элемента:

bool update(FILE* fp, int n){
    double d;

    if (scanf("%lf", &d) != 1) {
      ??? indicate error ???
      fclose(fp);
      return false;
    }

    if (fseek(fp,(n-1)*size + offsetof(struct logData, charge), SEEK_SET) == -1) {
      ??? indicate wrong n / file ???
      fclose(fp);
      return false;
    }

    return ((fwrite(&d,sizeof(double),1,fp) != -1) 
            & (fclose(fp) != -1)); /* not && because have to close in all cases */
}

Примечание: странно, что функция закрывает файл, но делаетне открывайте его, более логично не делать здесь закрытие

1 голос
/ 27 марта 2019

Я написал функцию, которая считывает двойное значение в структуре в двоичном файле, вычисляет значение и затем записывает вычисленное двойное значение в двоичный файл.

Обратите внимание, что двоичные файлы по своей природе непереносимы. Если вы манипулируете файлом, созданным на том же компьютере, другой программой C, созданной с помощью той же самой реализации C, то у вас все должно быть в порядке, но в противном случае и писатель, и читатель должны уделять большое внимание проблемам совместимости двоичных файлов. .

Однако даже в этом случае ваш код делает небезопасные предположения. Смещение элемента структуры (кроме первого) не гарантируется равным сумме размеров предыдущих элементов. Структуры могут содержать, и часто содержат, заполнение между членами и после последнего члена, и это отбросит ваши вычисления.

Хотя возможно вычислить смещение элемента структуры, в том числе в старых версиях C, которые не имеют offsetof(), в этом случае я бы рекомендовал полностью обойти проблему, записав всю структуру обратно в файл, вместо этого только одного члена:

    fseek(fp, -size, SEEK_CUR);
    fwrite(&thisLogData, size, 1, fp);
1 голос
/ 27 марта 2019

Вы должны использовать offsetof, чтобы узнать смещение поля в структуре:

#include<stddef.h>

long offset = offsetof(struct logData, charge);    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...