Есть код на Си который загружает файл (большие 1,2,3 гигабайта) в память.
.....
char * buffer;
size_t lSize, result;pFile = fopen ( file , "rb" );
fseek (pFile , 0 , SEEK_END);
lSize = ftell (pFile);
rewind (pFile);buffer = (char*) malloc (sizeof(char)*lSize);
result = fread (buffer,1,lSize,pFile);
if ( result != lSize) {fputs ("Reading error\n",stderr); }
.....После загрузки, проверяю сколько было прочитано в память (result=fread) с самим размером файла (lSize).
Что получается, если размер файла до 2гиг, то if ( result != lSize) условие ИСТИНО, если больше 2 гиг то нет, хотя result и lSize всегда равны, смотрел через printf.
И совсем как такое может быть, если в двух переменных одинаковые числа, а if говорит false?
Кто знает как с этим бороться ?
Буду очень признателен за помощь!Система: FreeBSD 7.0-RELEASE-p5
gcc version 4.2.1 20070719
>buffer = (char*) malloc (sizeof(char)*lSize);тут бы if (!buffer) perror("");
все проверки всех действий сделаны, везде?>result = fread (buffer,1,lSize,pFile);
по ману fread надо еще проверять ошибку и конец файла через feof(), ferror()
если выше в malloc() для чаров sizeof() делаем, то и тут sizeof(char) для единообразия писать надо вместо 1 :)>if ( result != lSize) {fputs ("Reading error\n",stderr); }
по мелочи: fprintf(stderr,""); // уже идиома, не цепляет глаз и читается проще чем fputs()
+ strace(), dbg, так же обратить внимание на ключи оптимизации и т.п. а то сравнение не работающее для одиноковых чисел - вроде смахивает на убитый стек.
Vic спасибо за внимание.>тут бы if (!buffer) perror("");
>все проверки всех действий сделаны, везде?Да, просто не стал засарять форум.
>по ману fread надо еще проверять ошибку и конец файла через feof(),
Говорит что конец файла не достигнут, хотя на самом деле он все считал в память.
>ferror()
ошибок нет.
>если выше в malloc() для чаров sizeof() делаем, то и тут sizeof(char)
>для единообразия писать надо вместо 1 :)Учту.
>по мелочи: fprintf(stderr,""); // уже идиома, не цепляет глаз и читается проще
>чем fputs()Тоже учту
>+ strace(), dbg, так же обратить внимание на ключи оптимизации и т.п.
>а то сравнение не работающее для одиноковых чисел - вроде смахивает
>на убитый стек.Strace работает только на i386 у меня ядро amd64. dbg запускал, но только ничего не нашел, наверно я неумют ею пользоваться.
Я забыл написать, что система у меня 64битная. (freebsd amd64)
Сегодня когда выводил через printf числа, указал формат %lu и вот что получилось
lSize = 2205089792
result = 18446744071619674112
а когда указываю формат %u ,то в обеих 2205089792Может есть какие-то идеи?
Есть мысль что вам нужно прочитать наконец про машинное представление чисел, особенно знаковых.
>Есть мысль что вам нужно прочитать наконец про машинное представление чисел, особенно
>знаковых.И включить -Wall чтобы gcc на printf() вываливал варнинг по поводу несоответствия спецификатора и типа выводимого значения. Помогает даже если в курсе, но случайно ошибся :)
>Может есть какие-то идеи?посмотреть sizeof(size_t), sizeof(off_t) и почитать про включение поддержки больших файлов для freebsd, а то если они 8 байт (так скорее всего и есть), то больше 2ГБ ну никак :)
>посмотреть sizeof(size_t), sizeof(off_t)
>а то если они 8 байт (так скорее всего и есть), то больше 2ГБ ну никак :)8589934592 GB математик хренов :)
>>посмотреть sizeof(size_t), sizeof(off_t)
>>а то если они 8 байт (так скорее всего и есть), то больше 2ГБ ну никак :)
>
>8589934592 GB математик хренов :)в хренах именно столько
>>>посмотреть sizeof(size_t), sizeof(off_t)
>>>а то если они 8 байт (так скорее всего и есть), то больше 2ГБ ну никак :)
>>
>>8589934592 GB математик хренов :)
>
>в хренах именно стольков том смысле что если они не 8, а 4 байта, я ступил =)
>
>Я забыл написать, что система у меня 64битная. (freebsd amd64)
>Сегодня когда выводил через printf числа, указал формат %lu и вот что
>получилось
>lSize = 2205089792
>result = 18446744071619674112
>а когда указываю формат %u ,то в обеих 2205089792
>
>Может есть какие-то идеи?Количество считанных из файла байт потрясает. Дайте мне два таких винта :)
Переменные типа size_t выводи с форматом %zu
>size_t lSize, result;
>...
>lSize = ftell (pFile);Попробуй еще
off_t lSize;
...
lSize = ftello (pFile);
>>size_t lSize, result;
>>...
>>lSize = ftell (pFile);
>
>Попробуй еще
>
>off_t lSize;
>...
>lSize = ftello (pFile);Пробывал, ничего не изменилось.
>Количество считанных из файла байт потрясает. Дайте мне два таких винта :)
>Переменные типа size_t выводи с форматом %zuИ при таком раскладе все тоже самое
result = 18446744071619674112>И включить -Wall чтобы gcc на printf() вываливал варнинг по поводу несоответствия >спецификатора и типа выводимого значения.
Все соответствует, Wall молчит как рыба.
----------
Повторюсь:
все работает так как надо, ошибки не выскакивают, то что я загрузил в память я потом с легкостью записываю обратно на винт, без всяких потерь данных.
Просто выскакивает такой глюк, если размер файла больше ~2гиг.
Единственный минус, так это то, что нельзя проверить сколько он считал.
Но как вариант я уже думаю просто форматировать result через sprintf c %u.Кстати где-то вычитал, что feof() в таком месте не будет работать в любом случаи.
Весь инет облазил, толком ничего и не нашел как исправить этот глюк с fread.
>[оверквотинг удален]
>>>...
>>>lSize = ftell (pFile);
>>
>>Попробуй еще
>>
>>off_t lSize;
>>...
>>lSize = ftello (pFile);
>
>Пробывал, ничего не изменилось.fseeko() & ftello() одновременно, одного не достаточно (ессно с off_t).
тип фс? для теста что будет если ручками в шелле создать файл >2GB и скопировать его?
т.к. у вас фря, а у меня линукс, проверить я на коленке ничего не могу, но могу посмотреть ман для фри выложенный на опеннет, вижу что возвращаемое/устанавливаемое значение оффсета имеет тип long (возможно ман на опеннете безнадежно устарел), а не size_t. off_t судя по замечаниям в других манах (для lseek русский ман здесь же на опеннете) может быть int (4 byte, !8 byte), а lseek используется в fseek. Т.е. необходимо с файлами более 2 ГБ очень аккуратным. где-то все же ошибка у нас с вами, даже если кажется что считывается все вроде бы правильно...
переменная errno после каждой операции проверяется?
> но могу посмотреть ман для фри выложенный на опеннетВ этом отношении с FreeBSD хорошо:
http://www.freebsd.org/cgi/man.cgi
>>Переменные типа size_t выводи с форматом %zu
>
>И при таком раскладе все тоже самое
>result = 18446744071619674112Если это действительно сразу после fread (т.е. ты совсем ничего не делаешь с result), то похоже таки на ошибку в libc. Точнее, в твоей ее версии.
Наконец-то выяснил в чем проблема!) Конечно же не без вашей помощи, всем спасибо, особенно Michelnok и vic!!!Рассказываю в чем проблема:
>Если это действительно сразу после fread (т.е. ты совсем ничего не делаешь
>с result), то похоже таки на ошибку в libc. Точнее, в
>твоей ее версии.После этого поста, я решил проверить, что же на самом деле делает fread.
Открыл /usr/src/lib/libc/stdio/fread.c и что я вижу.........
size_t
fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp)
{
int ret; //ВНИМАНИЕ СЮДАFLOCKFILE(fp);
ret = __fread(buf, size, count, fp);
FUNLOCKFILE(fp);
return (ret); //ВНИМАНИЕ СЮДА
}size_t
__fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp)
{
size_t resid;
char *p;
int r; //ВНИМАНИЕ СЮДА
size_t total;/*
* The ANSI standard requires a return value of 0 for a count
* or a size of 0. Peculiarily, it imposes no such requirements
* on fwrite; it only requires fread to be broken.
*/
if ((resid = count * size) == 0)
.........
while (resid > (r = fp->_r)) {
(void)memcpy((void *)p, (void *)fp->_p, (size_t)r);
fp->_p += r;
/* fp->_r = 0 ... done in __srefill */
p += r;
resid -= r; //ВНИМАНИЕ СЮДА
if (__srefill(fp)) {
/* no more input: return partial result */
return ((total - resid) / size);
}
}
.........
return (count);
}
-----------------------
что функция возвращает переменную типа int, ХОТЯ в функции объявленно, что возвращаем тип size_t, отсюда понятно почему файлы больше 2гиг, а это больше 2 147 483 648, возвращал что-то страшное.
После исправления int на size_t, все заработало.
Често говоря, я удивлен, что разработчики freebsd допустили такую ошибку(size_t -> int).
>[оверквотинг удален]
> int ret; //ВНИМАНИЕ СЮДА
>
>
> FLOCKFILE(fp);
> ret = __fread(buf, size,
>count, fp);
> FUNLOCKFILE(fp);
> return (ret); //ВНИМАНИЕ СЮДА
>
>}Ужас.