[P&AM Lab] Пример для разбора исходного кода - cat(1) из BSD 4.2

Grigoriy A. Sitkarev sitkarev на komitex.ru
Чт Дек 9 22:44:07 MSK 2010


Сейчас по порядку.

Борис Липин пишет:
> Тут парочка вопросов возникла по поводу cat
> 1) 
> switch(argv[1][1]) {
>             case 0:
>                 break;
>             case 'u':
>                 setbuf(stdout, (char *)NULL);
>                 uflg++;
>                 continue;
>             case 'n':
>                 nflg++;
>                 continue;
> ...}
> Почему здесь мы для флагов используем ++ а не просто приравниваем флагк 1( uflg=1); Связанно ли это както с тем что операция инкремента вассемблере занимает меньше памяти чем mov?

Меньше, да и традиция такая скорее. Дело в том что пользователь может 
несколько раз указать ту же опцию -u. Здесь ведётся подсчёт, сколько раз 
он её указал, получается так. Никто не запрещает там сделать uflg = 1 и 
алгоритмически это будет верно, но традиция есть традиция.

> 2)
> Что содержится в поле st_ino структуры struct stat statb,всмысле какойу неё логический смысл, и зачем мы её вводили в программу?

Это очень важная структура, в ней хранится метаинформация о файле. 
Системный вызов stat(2) её туда помещает. В программе она используется 
для того чтобы:

1) проверить что файл не является файлом устройства (блочного или 
символьного). Проверяются биты S_IFBLK и S_IFCHR в поле .st_mode.

2) узнать размер блока т.е. дискретной единицы с которой ведутся 
операции чтения и записи. Это поле .st_blksize.

3) проверяется что файл, который выводят, и файл в который выводят 
являются разными файлами. В Unix файл уникально идентифицируется двумя 
целыми числами - номером устройства и номером индексного дескриптора. 
Эти поля также содержатся в структуре stat (.st_dev, st_ino). Вы помните 
что в Unix есть файлы-ссылки, т.е. разные имена могут ссылаться на одни 
и те же данные файла. Чтобы cat(1) не напортачил, таким образом 
проверяется что файлы "что выводить" и "куда выводить" - разные.

Рекомендую прочесть man-страницу stat(2).

> 3)
> stdout-ссылка на стандартный файл вывода.А на что именно он ссылается?

Есть соглашение в Unix программах (и те которые на Си в системах общего 
применения) при запуске открыты три файла с номерами дескрипторов файлов 
(определены в unistd.h):

STDIN_FILENO	- 0
STDOUT_FILENO	- 1
STDERR_FILENO	- 2

Можно пользоваться как макросами, так и прямо числовыми константами. 
Если мы пишем "параноидальную" программу, то неплохо бы проверить что 
эти дескрипторы действительно есть, иначе перенаправлять их в /dev/null. 
Считается что у любой Си программы эти файлы открыты и должны быть 
соединены с соответствующими файлами (для интерактивных программ это как 
правило текущее устройство терминала пользователя). В Linux например 
можно у программы посмотреть с какими файлами эти дескрипторы 
ассоциированы, пролистав длинным листингом (ls -la) каталог 
/proc/<PID>/fd. Получается что открывать самому эти файлы не нужно, как 
обычно надо делать с другими файлами, через системный вызов open(2), 
потому что они должны быть открыты уже.

Это дескрипторы "сырого" (небуферизованного) ввода/вывода, т.е. которые 
мы пользуем с вызовами read(2), write(2) и т.д. Вы прямо с shell можете 
перенаправлять у программы эти дескрипторы, если помните, мы это делали 
на занятиях, я показывал там что-то вроде:

$ cat /etc/passwd > /root/saved_passwd

Есть три потока буферизованного ввода/вывода, это то что вы можете 
использовать с fread(3), fwrite(3), fprintf(3) и т.д.:

stdin
stdout
stderr

Они объявлены где-то в заголовках как:

extern FILE *stdin, *stdout, *stderr;

И в каждой Си программе они есть в адресном пространстве. Они также 
соединены со стандартным вводом, выводом и выводом ошибок. Поэтому я 
могу печатать сообщения об ошибках так:

fprintf(stderr, "error: %s:%d:%s(): something is wrong!\n",
	__FILE__, __LINE__, __FUNCTION__);

__FILE__, __LINE__, и __FUNCTION__ - это макросы, которые препроцессор 
раскрывает в имена файла, номера строки и имя функции.

Вызов

printf("Message");

эквивалентен:

fprintf(stdout, "Message");

Успехов.

--
Г.А.





Подробная информация о списке рассылки Lab