C преобразует .txt в двоичный файл с помощью системных вызовов

Я пишу программу, которая заменяет каждый символ, где position % step = 0 В качестве аргументов командной строки я даю 1. file 2. character и 3. step. Я могу использовать только системные вызовы. Вот моя основная функция:

int main(int argc, char **argv){

   assert(argc ==  4);

   int fdInput = open(argv[1], O_WRONLY);
   if(fdInput == -1)
      fatalError("Error opening input file.\n");

   char c[1];
   c[0] = argv[2][0];
   unsigned step = atoi(argv[3]);

   int fileSize;
   if((fileSize = lseek(fdInput,0,SEEK_END)) < 0)
      fatalError("Lseek error: Determining file size\n");

   if(lseek(fdInput,0,SEEK_SET) == -1)
      fatalError("Lseek error: Returning to the beginning\n");

   int i;
   for(i = 0; i*step < fileSize; i++)

      if(step - 1 > 0){
         if(lseek(fdInput, i*step - 1, SEEK_SET) == -1)
            fatalError("Lseek error: Within loop\n");

         if(write(fdInput, c, 1) != 1)
            fatalError("Writing error\n");

      }
      else {

         if(write(fdInput, c, 1) != 1)
            fatalError("Writing error.\n");
      }
      close(fdInput);
      return 0;
   }

Пример:

ввод.txt: 123456789

./output input.txt x 3 вернет 12x45x78x

Проблема: по какой-то причине, когда я компилирую и запускаю в первый раз, все работает нормально! НО: когда я выполню это во второй раз, это не сработает. Когда я пытаюсь cat/less input.txt, он говорит мне, что файл двоичный.

  • echo "123456789" > input.txt -> создает .txt файл
  • ./output input.txt x 3 -> 12x45x78x
  • ./output input.txt x 3 -> не будет работать (программа закончена), но:
  • less input.txt -> input.txt" may be a binary file. See it anyway?

Как файл может быть бинарным? Это должен быть обычный текстовый файл. Что я здесь делаю неправильно? Я что-то не так делаю с open?


person Aleksandar Makragić    schedule 06.03.2016    source источник
comment
Первое, что я заметил, это то, что у меня даже первое выполнение не работает должным образом. Файл кажется заполненным множеством нулевых символов (но замененная строка выглядит нормально). Я продолжу расследование.   -  person pikkewyn    schedule 06.03.2016
comment
вау, я понял, что вы создаете с помощью этого фрагмента кода разреженный файл размером 4 ГБ.   -  person pikkewyn    schedule 06.03.2016
comment
В первом lseek в цикле вы делаете огромный скачок: lseek(3, 4294967295, SEEK_SET) = 4294967295 write(3, x, 1) = 1   -  person pikkewyn    schedule 06.03.2016


Ответы (2)


Ваше первое смещение поиска неверно:

i*step - 1

с i == 0 это дает -1, учитывая только чисто математические вычисления и исключая неявные приведения типов из игры. Затем он преобразуется в unsigned (off_t подписывается, и переданное отрицательное значение должно привести к EINVAL, поэтому это должно быть неявное преобразование), которое будет чрезвычайно большим (UINT_MAX). В результате получается чрезвычайно большой (но разреженный) файл.

О, и:

assert(argc ==  4);

assert предназначен для проверки инвариантов, а не для обработки неправильного пользовательского ввода.

person Daniel Jour    schedule 06.03.2016
comment
с i == 0 это дает -1 не так. int*unsigned - int --› unsigned. Итак, с i == 0 должно получиться UINT_MAX - person chux - Reinstate Monica; 06.03.2016
comment
Хм, мне нужно объяснить это лучше. Я имел в виду, что математический расчет дает -1. Однако я не был уверен, что signed * unsigned приведет к неподписанному результату, поэтому я не указал этого. Я хотел проверить в стандарте, когда я в сети через свой ноутбук, а не мой мобильный. - person Daniel Jour; 06.03.2016
comment
i*step - 1 не рассчитывается математически без учета типа и затем преобразуется в unsigned. На каждом шаге учитываются значение и tpye. (int)0 * (unsigned)step --› (unsigned)0. (unsigned)0 - (int)1 --› UINT_MAX. Если UINT_MAX находится в диапазоне off_t, то в lseek() передается большое положительное значение. В противном случае, если он выходит за пределы диапазона, результат не определен (UB). IAC, вы хорошо определили проблему кода OP. Это просто почему не так. Ваше редактирование улучшилось и стало ближе к причине. - person chux - Reinstate Monica; 07.03.2016
comment
Спасибо вам обоим за ответ. - person Aleksandar Makragić; 08.03.2016
comment
Еще одна вещь, почему он конвертирует .txt в двоичный файл? - person Aleksandar Makragić; 08.03.2016
comment
less замечает, что есть много непечатаемых символов, поэтому догадывается, что это может быть файл, не предназначенный для непосредственного просмотра. Нет таких вещей, как бинарные файлы (все файлы бинарные); нет никакой конверсии. (Двоичный — это открытый режим, который влияет на то, как определенные последовательности байтов интерпретируются на определенных платформах) - person Daniel Jour; 08.03.2016

Вы должны инициализировать i значением 1 вместо 0, т.е.

for(i = 1; i*step < fileSize; i++)

В противном случае, как сказал @Daniel Jour, ваше первое смещение поиска будет неправильным (i * step - 1 == -1, учитывая только чисто математический расчет и оставляя неявные приведения типов вне игры).

Кроме того, вы должны добавить открывающую и закрывающую фигурные скобки for-loop для лучшей читаемости.

person pie    schedule 06.03.2016
comment
смещение первого поиска будет неверным (i*step - 1 == -1) --> 0*step - 1 --> UINT_MAX. - person chux - Reinstate Monica; 06.03.2016
comment
@chux Обновил мой ответ, чтобы отразить ответ Даниэля Джура. Я имел в виду то же самое. Спасибо. - person pie; 07.03.2016
comment
Спасибо за ответ. - person Aleksandar Makragić; 08.03.2016