В кои то веки решил начать читать книжки по программированию. Цели следующие: перестать говнокодить, углубить свои познания программирования. Начать решил с базы: "Керниган, Ритчи - Язык программирования Си". В этом посте буду писать заметки по этой книжке.

> Инструкция return без выражения только передает управление в ту программу, которая ее вызвала, не передавая ей никакого результирующего значения.

> Внешняя переменная должна быть определена, причем только один раз, вне текста любой функции; в этом случае ей будет выделена память. Она должна быть объявлена во всех функциях, которые хотят ею пользоваться. Объявление содержит сведения о типе переменной. Объявление может быть явным, в виде инструкции extern, или неявным, когда нужная информация получается из контекста.

Применить extern на практике можно следующим образом: например у меня есть 1.c и 2.с, в файле 2.c определена глобальная переменная int a;, доступ к которой я хочу получить из файла 1.c. Для этого можно в глобальной области 1.c определить int a; либо extern int a; НО, если я не хочу захламлять глобальную область 1.c, я могу прописать extern int a; в той функции 1.c, где хочу ее применить (без ключевого слова extern сделать такое нельзя - будет ошибка компиляции).

*Тыкни чтобы посмотреть картинку*

> А f() или всё таки f(void)? Из соображений совместимости со старыми Си-программами стандарт рассматривает пустой список как сигнал к тому, чтобы выключить все проверки на соответствие аргументов. Поэтому, когда нужно сохранить контроль и явно указать отсутствие аргументов, следует пользоваться словом void.

Т.е. в старых версиях языка Си f() означало, что функция может принимать любое количество и любые типы аргументов. Это значит, что компилятор не будет проверять переданные аргументы.

Короче, если кто то пишет на древней версии Си, захочет воспользоваться вашей функцией f() и где-нибудь в коде вызовет ее с какими-нибудь аргументами, то ошибку компилятора он не получит, и неизвестно какие гадости могут произойти дальше. Так что лучше указывать (void). 🧐

> В объявлениях short int a; long int b; short и long - квалификаторы.

> В макроопределении #define A 123.4L окончание (L) говорит о том, что данная константа имеет тип long double. Без окончания была бы определена константа типа double.

> enum как способ задания констант:

*Тыкни чтобы посмотреть картинку*

> Восьмибитовый код в переменной типа char на одних машинах может быть отрицательным числом, а на других — положительным (если единичка в 7 бите). Для совместимости переменные типа char, в которых хранятся несимвольные данные, следует специфицировать явно как signed char или unsigned char (спецификаторы).

> Неявные арифметические преобразования, как правило, осуществляются естественным образом. В общем случае, когда оператор вроде + или * с двумя операндами (бинарный оператор) имеет разнотипные операнды, прежде чем операция начнет выполняться, "низший" тип повышается до "высшего". Результат будет иметь высший тип. ОДНАКО: операнды типа float не приводятся автоматически к типу double.

Правила преобразования усложняются с появлением операндов типа unsigned. Проблема в том, что сравнения знаковых и беззнаковых значений зависят от размеров целочисленных типов, которые на разных машинах могут отличаться. Предположим, что значение типа int занимает 16 битов, а значение типа long — 32 бита. Тогда -1L < 1U, поскольку 1U принадлежит типу unsigned int и повышается до типа signed long. Но -1L > 1UL, так как -1L повышается до типа unsigned long и воспринимается как большое положительное число.