На данный момент мы изучили Си – в том плане, что можем писать программы на Си практически любой сложности. А действительно: основные операции есть; так как всё есть байт, можем хоть какие структуры создавать; да ещё и динамически.
Однако, не это самое сложное и интересное в программировании. Сам по себе язык мало что стоит. А вот "технологический стек", если хотите, или же умение обращаться с "батарейками" – вот где раскрывается любой язык!
Наше фееричное введение в наСИлие на этом этапе принимает ещё более ужасающие обороты! Переходим к "мясу" – к практике, где эклектика тулзовин и археология IT в своих соперниках имеет разве что аппаратные средства и саму физику!
Дальше идут скорее "пометки на полях" – набор пионера, чтобы выжить в джунглях программирования на Си.
Структура заголовочного файла
Уже ни раз мы подключали функции stdio
с помощью команды препроцессора
#include
. Сам заголовочный файл можно посмотреть:
→ cat /usr/include/stdio.h
И увидеть примерно следующее. Далее будут приведены части файла:
#ifndef _STDIO_H_
#define _STDIO_H_
// ...
#endif
ifndef
/ endif
– блок условного оператора макропроцессора. Код между ними
будет исполнен (не вырезан макропроцессором), если макроопределение/макрос определено.
С помощью команды define
можно определить макрос.
В данном случае конструкция, которая обрамляет весь файл – защита от повторного
определения функций и прочего при следующем include
.
Также в заголовочных файлах можно подключать другие.
#include <sys/cdefs.h>
#include <Availability.h>
Определять структуры
struct __sbuf {
unsigned char *_base;
int _size;
};
TODO: Про extern рассказывать долго, но надо
extern FILE *__stdinp;
extern FILE *__stdoutp;
extern FILE *__stderrp;
Объявлять "константы" – макросы, которые будут подставлены в код:
#define _IOFBF 0 /* setvbuf should set fully buffered */
#define _IOLBF 1 /* setvbuf should set line buffered */
#define _IONBF 2 /* setvbuf should set unbuffered */
Мы уже видели подобную "константу", когда читали входной поток и останавливались по EOF.
Но не останавливаемся: тут есть ещё прототипы функций, которые мы сможем использовать:
void clearerr(FILE *);
int fclose(FILE *);
int feof(FILE *);
int ferror(FILE *);
int fflush(FILE *);
int fgetc(FILE *);
int fgetpos(FILE * __restrict, fpos_t *);
char *fgets(char * __restrict, int, FILE *);
Этот кусок кода примечателен тем, что макрос может быть не только каким-то значением, но и "функцией" – не в СИшном виде, но по смыслу:
#define __sgetc(p) (--(p)->_r < 0 ? __srget(p) : (int)(*(p)->_p++))
#define __sputc(c, p) \
(--(p)->_w < 0 ? \
(p)->_w >= (p)->_lbfsize ? \
(*(p)->_p = (c)), *(p)->_p != '\n' ? \
(int)*(p)->_p++ : \
__swbuf('\n', p) : \
__swbuf((int)(c), p) : \
(*(p)->_p = (c), (int)*(p)->_p++))
Ну и конец – ставим комменты о том, что закрываем, ибо можно запутаться:
#endif /* _STDIO_H_ */