statvfs не может правильно распознать размер папки

У меня есть система Embedded Linux, которая по запросу начинает запись данных на SD-карту. Программное обеспечение, управляющее системой, имеет периодически вызываемую функцию проверки объема доступного места на SD-карте, останавливая запись, если она достигает 99% заполнения. Я использую следующий код, в котором statvfs используется как функция для чтения папки, в которой хранятся данные:

struct statvfs buff;

const int resp = statvfs("/media/mmcblk0p2/", &buff);

if (resp < 0)
{
    const QString strTemp = QString("INTERFACE: An error occurred while trying to read the file system info");

    mDebugS(strTemp);
    mLog(strTemp);

    return;
}

const float size = float(buff.f_bsize * buff.f_blocks) / float(1024 * 1024 * 1024);
const float free = float(buff.f_bsize * buff.f_bfree) / float(1024 * 1024 * 1024);
const float available = float(buff.f_bsize * buff.f_bavail) / float(1024 * 1024 * 1024);
//const float used = size - free;
const float percentUsed = (size - free)/size;   //E.g.: 0.98
const float percentAvailable = available/size;
const float totalStorageTime = size/1.2f * 24.0f;

//const float hoursUsed = percentUsed * totalStorageTime;
const float timeAvailable = percentAvailable * totalStorageTime;

const qint32 hoursLeft = (qint32)timeAvailable;
const qint32 minutesLeft = qint32((timeAvailable - (float)hoursLeft) * 60.0f);


//    mDebugS(QString("INTERFACE: mmcblk0p2 info: size: %1 | free: %2 | available: %3 | percent used: %4 | percent available: %5 | totalStorageTime: %6 | time available: %7 \n | hoursLeft: %8 "
//                    "| minutes left: %9")
//            .arg(size).arg(free).arg(available).arg(percentUsed).arg(percentAvailable).arg(totalStorageTime).arg(timeAvailable).arg((qint32)timeAvailable)
//            .arg(qint32((timeAvailable - (float)hoursLeft) * 60.0f)));


emit signalSetMassMemory(hoursLeft,minutesLeft);

if (percentUsed >= 0.99f)
//...

Примечание. Значение 1,2f здесь относится к скорости записи: 1,2 Гб в сутки. Я также использую эту функцию, чтобы узнать, сколько времени осталось для записи.

Сначала этот алгоритм был протестирован на SD-карте на 4 Гб, и он работал нормально. Этот SDC разделен на два раздела, соответствующий называется /media/mmcblk0p2/. Проблема, с которой я столкнулся, заключается в том, что при запуске точного кода в другой системе с другой SD-картой возвращаемые значения размера папки неверны: этот SDC составляет 16 ГБ, а функция возвращает мне что-то вроде 2,22 ГБ. Что может быть не так, ведь алгоритм и все остальное точно такое же?

Мое единственное подозрение на данный момент, что проблема в SD Card, Kingston 16 Gb micro sdhc Class 4, которая точно равна другой, удачной, за исключением размера. Но я бы не знал точно, какая у него может быть проблема, поскольку он отлично работает для всего остального (копирование, вставка, создание папок и т. д.). Кстати, форматирование одинаково для обеих карт памяти, и у меня не осталось других, чтобы провести дополнительные тесты.

Так кто-нибудь знает, что может произойти? Есть ли у statvfs какое-то ограничение, о котором не говорится в документах? Должен ли я изменить функцию?


person Momergil    schedule 15.06.2015    source источник
comment
Вы знаете, что большинство значений с плавающей запятой не могут быть представлены достаточно точно в двоичном компьютере, и что у вас будут ошибки округления, ошибки округления, которые усложняются по мере того, как вы выполняете больше операций. И что ошибки округления будут тем хуже, чем меньше у вас точности. В вашем случае не используйте значения с плавающей запятой, используйте целочисленную арифметику.   -  person Some programmer dude    schedule 15.06.2015
comment
@JoachimPileborg спасибо за совет, хотя я не уверен, стоит ли оно того - ведь деление целых чисел также вызывает ошибки округления! Так что это все равно, что пытаться тушить огонь огнем.   -  person Momergil    schedule 15.06.2015
comment
Во-первых, прекратите использовать float, попробуйте использовать целочисленный тип данных.   -  person ivan.ukr    schedule 16.06.2015
comment
Кроме того, float обычно имеет 32-битный тип, в то время как вы пытаетесь иметь дело с размерами, требующими 64-битного типа. 32-битный целочисленный тип может показать вам максимум 4G, в то время как для представления 16G вам нужно больше битов, поэтому должен входить 64-битный тип данных.   -  person ivan.ukr    schedule 16.06.2015
comment
Вместо этого попробуйте использовать quint64 или проверьте, какой собственный беззнаковый 64-битный тип данных поддерживает ваш компилятор. Обычно это unsigned long long.   -  person ivan.ukr    schedule 16.06.2015
comment
@ivan.ukr ты прав. Я использовал qint64, и после небольших изменений мне удалось решить проблему. Так что, если хотите, напишите свой комментарий в качестве ответа, чтобы я мог его принять. Спасибо!   -  person Momergil    schedule 16.06.2015


Ответы (1)


32-битный тип данных может содержать размеры не более 4G, в то время как для представления 16G вам нужно больше битов, поэтому необходимо использовать 64-битный тип данных. Попробуйте использовать quint64 вместо того, что вы используете сейчас, или проверьте, какой собственный беззнаковый 64-битный тип данных поддерживает ваш компилятор. Обычно это unsigned long long.

person ivan.ukr    schedule 06.07.2015