Menu

Синтаксис C: структура программы на C с разбором

У любой программы на C один и тот же скелет: подключения заголовков, функция main, инструкции с точкой с запятой и блоки в фигурных скобках. Разбираем, что делает каждая часть и какие правила компилятор действительно требует соблюдать.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Синтаксиса в C совсем немного: около 32 ключевых слов и горстка правил пунктуации. Почти каждая программа, которую вы когда-либо напишете, имеет одну и ту же внешнюю форму, поэтому эту форму стоит один раз аккуратно разобрать по частям.

Самая маленькая полноценная программа

Она компилируется, запускается и ничего не делает:

Никаких подключений, никакого вывода, никакого обязательного класса или модуля. main — это точка входа: когда операционная система запускает вашу программу, она вызывает main. Когда main возвращает управление, программа завершается, а возвращённое значение становится кодом завершения.

Добавьте вывод — и понадобится одно подключение:

Директивы препроцессора

Строки, начинающиеся с #, обрабатываются препроцессором ещё до собственно компиляции. Это не инструкции C, и точка с запятой им не нужна.

#include <stdio.h>    /* заголовок стандартной библиотеки - угловые скобки */
#include "myutils.h"  /* ваш собственный заголовок - кавычки, ищется сначала рядом */
#define MAX 100       /* макрос - ниже везде MAX заменяется на 100 */

#include — это буквальная вставка текста: всё содержимое указанного файла подставляется в это место. В stdio.h лежит объявление printf, благодаря которому компилятор знает, какие аргументы принимает printf. Забудете подключение — получите implicit declaration of function 'printf'.

Различие между угловыми скобками и кавычками касается того, где компилятор ищет файл: <...> — системные каталоги подключаемых файлов, "..." — сначала рядом с текущим файлом.

Функция main

int main(void) {
    return 0;
}

Четыре части, и каждая значима:

  • int — тип возвращаемого значения main. Оно уходит операционной системе как код завершения, где 0 означает успех.
  • main — зарезервированное имя, которое вызывает среда выполнения. В любой размещённой (hosted) программе на C оно ровно одно.
  • (void) — список параметров. void здесь значит «не принимает аргументов». Запись main() допустима, но слабее: пустые скобки в C означают «параметры не указаны», а это отключает проверку аргументов.
  • { ... } — тело функции.

Вторая стандартная форма принимает аргументы командной строки:

int main(int argc, char *argv[]) { ... }

Пишите int main(void), пока они вам не понадобятся.

Инструкции и точки с запятой

Инструкция — это одна команда, и она заканчивается точкой с запятой.

Четыре инструкции, четыре точки с запятой. Точка с запятой — это признак конца, а не разделитель: последней инструкции в блоке она тоже нужна.

Что точку с запятой не требует:

#include <stdio.h>        /* строка препроцессора - без точки с запятой */

int add(int a, int b) {   /* заголовок определения функции - без точки с запятой */
    return a + b;
}                         /* закрывающая скобка функции - без точки с запятой */

if (x > 0) {
    ...
}                         /* закрывающая скобка управляющего блока - без точки с запятой */

Случай, на котором спотыкаются все, — точка с запятой там, где должно быть тело:

if (score > 90);              /* БАГ: эта ; и есть всё тело if */
    printf("Отлично!\n");     /* выполняется всегда, каким бы ни был score */

Это абсолютно корректный C. if управляет пустой инструкцией, а printf — просто следующая строка по порядку. -Wall об этом предупреждает, но компилятор вас не остановит.

Блоки и фигурные скобки

Фигурные скобки объединяют инструкции в блок, который считается одной инструкцией везде, где ожидается инструкция.

Скобки необязательны, когда тело состоит из одной инструкции, но именно из-за их отсутствия случаются знаменитые баги: допишете позже вторую строку — и она незаметно окажется вне if. Ставьте скобки всегда.

Блоки также создают область видимости: переменная, объявленная внутри { ... }, перестаёт существовать на закрывающей скобке.

Регистр и пробелы

C чувствителен к регистру везде. total, Total и TOTAL — три разных имени. Все ключевые слова пишутся строчными буквами, поэтому Int, Return и Printf — ошибки, причём сообщение про Printf сбивает с толку, потому что компилятор решает, что вы имели в виду какую-то функцию, о которой он никогда не слышал.

С пробельными символами всё, наоборот, почти полностью свободно. Компилятор считает любую последовательность пробелов, табуляций и переводов строки одним разделителем. Вот это корректно:

int    main ( void )
{
    printf
    ( "Привет\n" ) ;
    return 0 ;
}

И вот это тоже:

int main(void){printf("Привет\n");return 0;}

Оба варианта компилируются одинаково. Раз компилятору всё равно, форматирование существует исключительно для людей — и общепринятой раскладки (одна инструкция на строку, четыре пробела или одна табуляция на уровень вложенности, открывающая скобка на той же строке) стоит придерживаться, потому что почти любая кодовая база на C, которую вы прочтёте, оформлена примерно так же.

Два места, где пробелы всё же важны: нельзя разрывать ключевое слово или идентификатор (in t — это не int) и нельзя вставлять перевод строки внутрь обычного строкового литерала.

Идентификаторы: правила именования

Идентификатор — это любое имя, которое выбираете вы: переменные, функции, типы. Правила:

  • Состоят из букв, цифр и подчёркиваний.
  • Не могут начинаться с цифры. total2 годится, 2total — нет.
  • Не могут совпадать с ключевым словом: переменной по имени int, for или return не бывает.
  • Регистр имеет значение.
  • Имена, начинающиеся с подчёркивания, и любые имена с двумя подчёркиваниями подряд зарезервированы за реализацией — не придумывайте их.
int score;        /* хорошо */
int total_items;  /* хорошо - snake_case это соглашение C */
int _hidden;      /* допустимо, но зарезервировано - избегайте */
int 2fast;        /* ошибка */
int float;        /* ошибка - ключевое слово */

Полностью прокомментированная программа

Всё перечисленное выше, собранное в одном месте:

Порядок чтения здесь важен: with_tax определена до того, как main её использует. C читает файл сверху вниз, поэтому функция должна быть объявлена до вызова. Определяйте её раньше или напишите вверху прототип функции, а определение оставьте ниже.

Часто задаваемые вопросы

Какова базовая структура программы на C?

Сначала директивы препроцессора (#include <stdio.h>), затем определения функций, одна из которых обязательно main. Внутри функции инструкции заканчиваются точкой с запятой, а блоки заключаются в фигурные скобки. Минимальная программа — это #include <stdio.h> плюс int main(void) { return 0; }.

Почему пишут int main(void), а не просто main()?

int — это тип возвращаемого значения main, то есть код завершения, который программа отдаёт операционной системе. (void) явно говорит, что main не принимает аргументов. Запись main() с пустыми скобками — устаревший стиль, который ничего не сообщает компилятору о параметрах, поэтому проверок будет меньше.

Всем ли инструкциям в C нужна точка с запятой?

Каждой инструкции — да, но не каждой строке. Директивы препроцессора (#include, #define), определения функций и закрывающая скобка блока или конструкции if/for/while её не требуют. Лишняя точка с запятой после if (x) — вполне корректный C, который молча делает тело безусловным.

Чувствителен ли C к регистру?

Да, полностью. count, Count и COUNT — три разных идентификатора, а Int — это не ключевое слово int. Все ключевые слова C записываются строчными буквами, поэтому заглавная буква в Return или Printf приводит к ошибке.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ