Модератор: Модераторы разделов
unixlike
Сообщения: 14
Сообщение
unixlike » 14.08.2012 19:40
Начал изучать Си и для тренировки написал программу копирования файлов cp.c
Код:
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFFER_SIZE 4096
int main (int argc, char * argv[])
{
int finput1, foutput2, closef1, closef2;
int read_bytes;
char buffer[BUFFER_SIZE+1];
if (argc < 3) {
fprintf (stderr, "Lack of arguments\n");
exit (1);
}
finput1 = open (argv[1], O_RDONLY);
if (finput1 < 0)
{
fprintf (stderr, "Cannot open file-Read\n");
exit (1);
}
foutput2 = open (argv[2], O_WRONLY|O_CREAT|O_EXCL, 0600);
if (foutput2 < 0)
{
fprintf (stderr, "Cannot open file-Write\n");
exit (1);
}
while ((read_bytes = read (finput1, buffer, BUFFER_SIZE)) > 0)
{
write (foutput2, buffer, read_bytes);
}
if (read_bytes < 0)
{ fprintf (stderr, "cp: Cannot read file\n");
exit (1);
}
closef1=close (finput1);
if (closef1 < 0)
{
fprintf (stderr, "Cannot close file-Read\n");
exit (1);
}
closef2=close (foutput2);
if (closef2 < 0)
{
fprintf (stderr, "Cannot close file-Write\n");
exit (1);
}
exit (0);
}
компилировал
gcc -o cp cp.c -std=c99 -Wall в консоли тишина
проверьте все ли там правильно.
Janik
Сообщения: 855
Статус: Оператор вычислительных машин
ОС: Debian
Сообщение
Janik » 14.08.2012 23:27
Если gcc ничего не вернул, то компиляция прошла успешно. А вот в самой программе ошибки скорее всего будут. Вы её хоть пробовали запустить?
Кто ищет, тот всегда найдет!
Опыт - это когда все получается с первого раза.
Фантом
Сообщения: 457
ОС: openSUSE
Сообщение
Фантом » 15.08.2012 00:05
Вполне нормально. Только зачем нужны два последних #include (один из которых повторяет уже имеющийся) и зачем указывать при компиляции C99 (и совершенно не использовать его в самой программе)?
unixlike
Сообщения: 14
Сообщение
unixlike » 15.08.2012 10:03
Вы её хоть пробовали запустить?
да, работает как бы нормально, сравнение оригинала с копией
cmp говорит ОК.
Только зачем нужны два последних #include (один из которых повторяет уже имеющийся) и зачем указывать при компиляции C99
повторение #include <stdlib.h> ошибка - перестарался
а #include <unistd.h> чтоб не было варниннгов при компиляции с флагом -std=c99 без unistd.h gcc ругался.
ну и c99 указал для более строгой проверки формальной корректности кода или это не поможет?
Janik
Сообщения: 855
Статус: Оператор вычислительных машин
ОС: Debian
Сообщение
Janik » 15.08.2012 10:50
По-умолчанию используется старый стандарт, вроде как.
Поправте, если заблуждаюсь
Кто ищет, тот всегда найдет!
Опыт - это когда все получается с первого раза.
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Сообщение
drBatty » 15.08.2012 10:51
unixlike писал(а): ↑ 14.08.2012 19:40
проверьте все ли там правильно.
форматирование сделайте нормальное. так не видно.
Janik
Сообщения: 855
Статус: Оператор вычислительных машин
ОС: Debian
Сообщение
Janik » 15.08.2012 10:59
Кстати, можно проверить программу на то, как она обрабатывает неправильные аргументы или ситуации.
Кто ищет, тот всегда найдет!
Опыт - это когда все получается с первого раза.
unixlike
Сообщения: 14
Сообщение
unixlike » 15.08.2012 13:56
форматирование сделайте нормальное. так не видно.
нормальное это как?
Я кстати похоже нашел логические ошибки. Неправильно же сразу exit(1); везде ставить, нужно открытые файлы закрыть сначала.
И еще такой момент, первое копирование 200Мб файла на тот же диск примерно 5 сек, это нормально. А вот повторное 1.2-1.6 сек явно не реально. Чтение с диска макс. 87Мб/сек. Добавлял sync() в программу время повторного копирования не изменилось. Может потому что sync() ничего не возвращает и программа не ждет результата.
Тогда как гарантированно сбросить данные на диск до закрытия программы?
unixlike
Сообщения: 14
Сообщение
unixlike » 15.08.2012 15:17
Вот прогнал через форматирование:
Код: Выделить всё
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#define BUFFER_SIZE 4096
int main(int argc, char *argv[])
{
int finput1, foutput2, closef1, closef2;
int read_bytes;
char buffer[BUFFER_SIZE + 1];
if (argc < 3)
{
fprintf(stderr, "Lack of arguments\n");
exit(1);
}
finput1 = open(argv[1], O_RDONLY);
if (finput1 < 0)
{
fprintf(stderr, "Cannot open file-Read\n");
exit(1);
}
foutput2 = open(argv[2], O_WRONLY | O_CREAT | O_EXCL, 0600);
if (foutput2 < 0)
{
fprintf(stderr, "Cannot open file-Write\n");
exit(1);
}
while ((read_bytes = read(finput1, buffer, BUFFER_SIZE)) > 0)
{
write(foutput2, buffer, read_bytes);
}
if (read_bytes < 0)
{
fprintf(stderr, "cp: Cannot read file\n");
exit(1);
}
closef1 = close(finput1);
if (closef1 < 0)
{
fprintf(stderr, "Cannot close file-Read\n");
exit(1);
}
closef2 = close(foutput2);
if (closef2 < 0)
{
fprintf(stderr, "Cannot close file-Write\n");
exit(1);
}
exit(0);
}
Janik
Сообщения: 855
Статус: Оператор вычислительных машин
ОС: Debian
Сообщение
Janik » 15.08.2012 15:50
Во-во, так надо форматировать текст.
Кто ищет, тот всегда найдет!
Опыт - это когда все получается с первого раза.
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Сообщение
drBatty » 15.08.2012 16:13
unixlike писал(а): ↑ 15.08.2012 13:56
Я кстати похоже нашел логические ошибки. Неправильно же сразу exit(1); везде ставить, нужно открытые файлы закрыть сначала.
по стандарту ЕМНИП при exit() все открытые файлы сами закрываются (в отличие от abort(3)).
unixlike писал(а): ↑ 15.08.2012 13:56
Тогда как гарантированно сбросить данные на диск до закрытия программы?
проще юзать потоки (stream), тогда закрыть все файлы можно fcloseall(3)
(для гарантии можно проверить return value)
unixlike
Сообщения: 14
Сообщение
unixlike » 15.08.2012 19:58
по стандарту ЕМНИП при exit() все открытые файлы сами закрываются (в отличие от abort(3)).
А перед нормальным выходом из программы таки нужно закрыть?
проще юзать потоки (stream), тогда закрыть все файлы можно fcloseall(3)
этой стадии просветления пока не достиг
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Сообщение
drBatty » 15.08.2012 20:35
unixlike писал(а): ↑ 15.08.2012 19:58
А перед нормальным выходом из программы таки нужно закрыть?
нет. Но для совместимости и вообще... Короче, я закрываю, и вам советую. К файлам отношение должно быть как к памяти:
Код: Выделить всё
FILE *fs = fopen(file_name, mode);
if(!fs)
{// обработка ошибки открытия файла
}
function(fs);// тут работаем с открытым файлом
if(fclose(fs) != 0)
{// ошибка закрытия. Тоже бывает
}
для выяснения КАКАЯ была ошибка, подойдёт переменная errno.
unixlike писал(а): ↑ 15.08.2012 19:58
этой стадии просветления пока не достиг
а это проще, чем ваше write/read. Файлы в данном случае сродни потокам в обычной unix-shell. Это более высокий уровень абстракции, для большинства задач этого хватает за глаза.
unixlike
Сообщения: 14
Сообщение
unixlike » 15.08.2012 21:05
применил
fprintf(stderr, "Cannot open file '%s' %s\n", argv[1], strerror(errno));
работает: Cannot open file 'testfile' -No such file or directory
а где почитать про этот (stream) понятное объяснение я не пойму как с этим работать
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current
Сообщение
drBatty » 15.08.2012 21:31
unixlike писал(а): ↑ 15.08.2012 21:05
работает: Cannot open file 'testfile' -No such file or directory
ессно.
unixlike писал(а): ↑ 15.08.2012 21:05
а где почитать про этот (stream) понятное объяснение я не пойму как с этим работать
K&R
подробности реализации
man 3 fopen
man 3 fread
man 3 fwrite
man 3 fclose
man 3 errno
man 3 strerror