The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]




Версия для распечатки Пред. тема | След. тема
Новые ответы [ Отслеживать ]
C/C++ 64bit. Глюк при сравнении чисел, !*! yerdna, 24-Ноя-08, 05:19  [смотреть все]
Есть код на Си который загружает файл (большие 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

  • C/C++ 64bit. Глюк при сравнении чисел, !*! vic, 14:13 , 24-Ноя-08 (1)
    >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, так же обратить внимание на ключи оптимизации и т.п. а то сравнение не работающее для одиноковых чисел - вроде смахивает на убитый стек.

    • C/C++ 64bit. Глюк при сравнении чисел, !*! yerdna, 00:43 , 25-Ноя-08 (2)
      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

      Может есть какие-то идеи?

  • C/C++ 64bit. Глюк при сравнении чисел, !*! Michelnok, 02:58 , 28-Ноя-08 (9)
    >size_t lSize, result;
    >...
    >lSize = ftell (pFile);

    Попробуй еще

    off_t lSize;
    ...
    lSize = ftello (pFile);

    • C/C++ 64bit. Глюк при сравнении чисел, !*! yerdna, 12:05 , 28-Ноя-08 (11)
      >>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.

      • C/C++ 64bit. Глюк при сравнении чисел, !*! vic, 14:29 , 28-Ноя-08 (12)
        >[оверквотинг удален]
        >>>...
        >>>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 после каждой операции проверяется?

      • C/C++ 64bit. Глюк при сравнении чисел, !*! Michelnok, 16:13 , 28-Ноя-08 (14)
        >>Переменные типа size_t выводи с форматом %zu
        >
        >И при таком раскладе все тоже самое
        >result = 18446744071619674112

        Если это действительно сразу после fread (т.е. ты совсем ничего не делаешь с result), то похоже таки на ошибку в libc. Точнее, в твоей ее версии.

        • C/C++ 64bit. Глюк при сравнении чисел, !*! yerdna, 21:24 , 28-Ноя-08 (15)
          Наконец-то выяснил в чем проблема!) Конечно же не без вашей помощи, всем спасибо, особенно 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).




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру