Программы
Заголовочные файлы в Си

Заголовочные файлы в Си

Начинаем писать свои "библиотеки" в Си

На данный момент мы изучили Си – в том плане, что можем писать программы на Си практически любой сложности. А действительно: основные операции есть; так как всё есть байт, можем хоть какие структуры создавать; да ещё и динамически.

Однако, не это самое сложное и интересное в программировании. Сам по себе язык мало что стоит. А вот "технологический стек", если хотите, или же умение обращаться с "батарейками" – вот где раскрывается любой язык!

Наше фееричное введение в наСИлие на этом этапе принимает ещё более ужасающие обороты! Переходим к "мясу" – к практике, где эклектика тулзовин и археология 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_ */