C Базовый синтаксис

Язык C — универсальный язык программирования, широко используемый в таких областях, как системное программирование, разработка встраиваемых систем и высокопроизводительные вычисления.

Язык C обладает такими характеристиками, как высокая эффективность, гибкость и хорошая переносимость. Он является основой многих других языков программирования (таких как C, Java, Go) и остаётся основным выбором для операционных систем, драйверов и низкоуровневых библиотечных функций.

В языке C токены — это базовые строительные блоки программы. Компилятор выполняет лексический анализ исходного кода, разбивая код на отдельные токены. Токены — это наименьшие значимые единицы, которые может распознать компилятор, и вся программа на C состоит из этих токенов.

Токены в языке C в основном включают следующие типы:

  • Ключевые слова: слова, зарезервированные языком и имеющие специальное значение, такие какint、if、return。
  • Идентификаторы: имена, определяемые программистами, используемые для переменных, функций, массивов и т. д.
  • Константы: значения в программе, которые фиксированы и не изменяются, например целые числа42, числа с плавающей запятой3.14。
  • Строковые литералы: последовательности символов, заключённые в двойные кавычки, например"Hello"。
  • Операторы: символы, используемые для выполнения операций, например+、==、&&。
  • Разделители: символы, используемые для разделения инструкций и блоков кода, например;、{}。

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

Это простая программа на языке C, которая может вывести "Hello, World!"

Пример

#include <stdio.h>

int main() {
    printf("Hello, World!\n");
    return 0;
}

Приведённый выше код состоит из следующей структуры:

  • Директивы препроцессора: например#includeи#define, обрабатываемые препроцессором перед компиляцией.
  • функция main: каждая программа на C имеет одну и только однуmain()Функция является точкой входа в программу.
  • Объявление переменных: объявляет переменные, используемые в программе. C89 требует, чтобы объявления находились в самом начале блока кода.
  • Определение функции: определяет функции, используемые в программе, описывая конкретную логику реализации функций.

Более сложное объяснение структуры программы на C (каждое понятие будет подробно рассмотрено в последующих главах):

Пример

#include <stdio.h> // Подключение заголовочного файла

#define PI 3.14159 // Определение макроса

// Объявление функции
int add(int a, int b);

int main() {         // Главная функция
    // объявление переменных
    int num1, num2, sum;

    // Ввод данных пользователем
    printf("Введите два целых числа: ");
    scanf("%d %d", &num1, &num2);

    // вызов функции
    sum = add(num1, num2);

    // Вывод результатов
    printf("Сумма: %d\n", sum);

    return 0;        // Возврат 0 указывает на успешное выполнение программы
}

// Определение функции
int add(int a, int b) {
    return a + b;
}

Включение заголовочного файла

  • Заголовочные файлы обычно используются в начале программы#includeДиректива include. Заголовочные файлы предоставляют объявления функций и библиотек, таких как стандартная библиотека ввода/вывода<stdio.h>, стандартная библиотека<stdlib.h>и т. д. Они определяют функции, макросы, константы и т. д., позволяя программе использовать предопределённые библиотечные функции.
  • Системные заголовочные файлы используют угловые скобки<>, пользовательские заголовочные файлы используют двойные кавычки"", у этих двух разные пути поиска.
  • Пример:#include <stdio.h>(системные заголовочные файлы),#include "myheader.h"(пользовательские заголовочные файлы)

Определение макроса

  • Макрос реализуется с помощью#defineСимвольные константы или фрагменты кода, определяемые директивами. Макросы текстуально заменяются препроцессором перед компиляцией, не занимают память во время выполнения и часто используются для определения констант или простой встроенной логики кода.
  • Макросы не имеют проверки типов, и их следует использовать с осторожностью; для констант с требованиями к типу рекомендуется использоватьconstподстановку переменных.
  • Пример:#define PI 3.14159、#define MAX(a, b) ((a) > (b) ? (a) : (b))

Объявление функции

  • В языке C объявления функций (также называемые прототипами) должны появляться до определения или вызова функции. Объявление предоставляет тип возвращаемого значения функции, имя функции и список параметров, чтобы компилятор мог выполнять проверку типов в месте вызова.
  • Объявления функций можно размещать в заголовочных файлах для совместного использования несколькими исходными файлами.
  • Пример:int add(int a, int b);

функция main

  • main()Функция является точкой входа программы на C. Каждая программа на C должна содержатьmain()функция. Программа начинается сmain()начинает выполнение, возвращаемое значение обычно0означает успешное выполнение программы, а ненулевое значение означает, что произошла ошибка.
  • main()Функции также могут принимать аргументы командной строки:int main(int argc, char *argv[]), гдеargc— это количество параметров,argv— это массив строк аргументов.
  • Пример:int main() { ... }

Объявление переменной

  • В программах на C все переменные должны иметь объявленные типы до использования. Переменные могут бытьmain()объявлены внутри функций (локальные переменные) или глобально вне функций (глобальные переменные).
  • Переменные можно инициализировать одновременно с объявлением. Неинициализированные локальные переменные содержат неопределённые значения (мусорные значения), тогда как глобальные переменные и статические переменные автоматически инициализируются в0。
  • Пример:int count = 0;、float price = 9.99;、char grade = 'A';

операторы и выражения

  • Операторы — это базовые единицы выполнения программы на C. Обычно это вызовы функций, присваивания и управляющие операторы (такие какif、forи т. д.) или выражения. Выражение — это фрагмент кода, состоящий из переменных, операторов и констант, который может вычислять значение.
  • В языке C присваивание само по себе также является выражением и имеет значение (то есть присвоенное значение), поэтому можно писатьa = b = c = 0;цепочку присваивания, как здесь.
  • Пример:
    printf("Enter two integers: ");
    sum = add(num1, num2);

Управляющие операторы

  • Управляющие операторы используются для управления порядком выполнения программы, включая условное ветвление (if/else、switch) и циклы (for、while、do-while). Также существуют операторы переходаbreak、continue、gotoиreturn。
  • Разумное использование управляющих операторов — ключ к написанию программ с ясной логикой, и следует избегать злоупотребления ими.gotoчтобы поддерживать читаемость кода.
  • Пример:
    if (num1 > num2) {
        printf("num1 is greater than num2");
    }

Определение функции

  • Определение функции содержит полное тело функции и описывает конкретную реализацию функции. Функция состоит из типа возвращаемого значения, имени функции, списка параметров и тела функции. Хорошее проектирование функции должно следовать принципу «единственной ответственности», при этом каждая функция делает только одну вещь.
  • Функции языка C не поддерживают перегрузку. Каждое имя функции должно быть уникальным в одной и той же области видимости. Функции могут вызывать себя рекурсивно.
  • Пример:
    int add(int a, int b) {
        return a + b;
    }

Оператор return

  • returnОператор используется для завершения выполнения функции и возврата управления вместе с возвращаемым значением вызывающей стороне.voidФункции типа могут использовать return без значенияreturn;чтобы досрочно завершить работу, или можно опуститьreturnоператор.
  • main()Возвращаемое значение функции передаётся операционной системе,0обычно указывает на успех, и можно использовать стандартный макросEXIT_SUCCESSиEXIT_FAILURE(определён в<stdlib.h>)。
  • Пример:return 0;、return EXIT_SUCCESS;

Разделители

Разделители используются для разделения операторов, выражений и блоков кода, помогая компилятору понимать структуру программы. К распространённым разделителям относятся:

  • запятая,: используется для разделения нескольких элементов в объявлениях переменных, параметрах функций или списках инициализации.
  • Точка с запятой;: используется для завершения оператора и является наиболее распространённым разделителем в языке C.
  • Скобки:
    • Круглые скобки(): используются для списков параметров вызовов функций, условий в операторах управления потоком и принудительного задания порядка вычисления выражений.
    • Фигурные скобки{}: используются для определения тел функций, блоков кода управляющих конструкций и инициализации составных литералов и массивов/структур.
    • Квадратные скобки[]: используются для объявления массивов и доступа к элементам (операция индексации).

В программах на C точка с запятой;является терминатором оператора. Каждый оператор должен заканчиваться точкой с запятой, которая обозначает конец логической сущности. Пропущенная точка с запятой — одна из самых распространённых синтаксических ошибок у начинающих.

Например, следующие две записи являются разными операторами:

printf("Hello, World! \n");
return 0;

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

while (condition);  // 空循环体,等待条件变化

Комментарии

В языке C есть два способа комментирования:

// Single-line comment

с//Однострочными комментариями, начинающимися с (введены в C99). Этот тип комментария распространяется от//до конца строки. Он может занимать строку целиком или размещаться в конце строки кода.

/* Single-line comment */
/* 
 Multi-line comment
 Multi-line comment
 Multi-line comment
 */

/* */Комментарии в этом формате могут быть однострочными или многострочными, подходят для более длинных сценариев комментирования, таких как описания функций и заголовки модулей.

Пример

// Это однострочный комментарий

/*
Это многострочный комментарий
Он может занимать несколько строк
*/


int main() {
    // Вывести сообщение
    printf("Hello, World!\n");
    return 0;
}

При использовании комментариев обратите внимание на следующие моменты:

  • Комментарии не могут быть вложены в комментарии (/* /* */ */это недопустимо).
  • Комментарии не могут находиться внутри строковых литералов или символьных констант.
  • Комментарии пишутся для чтения людьми. Они должны быть краткими и ясными, сосредоточенными на объяснении «почему», а не «что было сделано»; сам код должен выражать «что он делает».
  • Хорошие привычки комментирования — важная часть профессионального программирования, помогающая сопровождению кода и командной работе.

Идентификаторы

Идентификаторы — это имена переменных, функций, массивов, типов и т. д. в программе, определяемые программистом. Идентификаторы состоят из букв (верхнего или нижнего регистра), цифр и символов подчёркивания, но первый символ должен быть буквой или символом подчёркивания, а не цифрой.

Идентификатор начинается с буквы A-Z или a-z либо с символа подчёркивания _, за которым следует ноль или более букв, символов подчёркивания и цифр (0-9).

Такие знаки пунктуации, как @, $ и %, не допускаются в идентификаторах C. C — эточувствительный к региструязык программирования. Поэтому в C,Manpowerиmanpower— это два разных идентификатора. Ниже перечислены некоторые допустимые идентификаторы:

mohd       zara    abc   move_name  a_123
myname50   _temp   j     a23b9      retVal

Ниже приведены некоторые примеры недопустимых идентификаторов и причины:

2abc        // 错误:以数字开头
my-name     // 错误:包含连字符 -
float       // 错误:与关键字重名
my name     // 错误:包含空格

Рекомендации по именованию: идентификаторы должны быть описательными и чётко выражать своё назначение. Распространённые стили именования включают именование с подчёркиванием (my_variable) и именование в стиле lower camel case (myVariable), просто придерживайтесь единообразия в рамках одного проекта. Идентификаторы, начинающиеся с двойного подчёркивания__обычно зарезервированы компилятором или стандартной библиотекой, и их следует избегать в пользовательском коде.

Константы

Константы — это фиксированные значения, которые не изменяются во время выполнения программы. В C есть два основных способа определения констант: с помощьюconstключевого слова или использовать#defineопределение макроса.

Константы могут быть целочисленными константами, константами с плавающей точкой, символьными константами, константами перечисления и т. д.:

const int MAX = 100;          // 整型常量
const float PI = 3.14159;    // 浮点型常量
const char NEWLINE = '\n';   // 字符常量(转义字符)

К распространённым escape-последовательностям в символьных константах относятся:

  • \n: перевод строки
  • \t: горизонтальная табуляция
  • \\: обратная косая черта
  • \': одинарная кавычка
  • \0: нулевой символ (маркер конца строки)

ИспользованиеconstКонстанты, определённые с помощью const, имеют информацию о типе, поэтому компилятор может выполнять проверку типов. По сравнению с#defineМакросы безопаснее и являются рекомендуемым подходом в C99 и более поздних версиях.

строковый литерал

Строковые литералы — это последовательности символов, заключённые в двойные кавычки, используемые для представления текстовых данных.

Строковые литералы хранятся в памяти как массивы символов, и в конце автоматически добавляется нулевой символ\0(т. е. нулевой терминатор), обозначающий конец строки.

char greeting[] = "Hello, World!";  // 编译器自动计算长度(包含 \0)

Вот несколько важных замечаний о строковых литералах:

  • "Hello" на самом деле занимает 6 байт в памяти:'H'、'e'、'l'、'l'、'o'、'\0'。
  • Строковые литералы хранятся в памяти только для чтения и не могут быть изменены; если требуется изменение, их следует скопировать в массив символов.
  • Два расположенных рядом строковых литерала автоматически объединяются компилятором:"Hello, " "World!"Эквивалентно"Hello, World!"。
  • Символ'A'(символьные константы) и строки"A"(строковый литерал) различаются; последний содержит'A'и'\0'Два символа.

Операторы

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

В языке C существует множество операторов. К распространённым относятся:

  • Арифметические операторы:+, -, *, /, %(где/выполняет целочисленное деление над целыми числами,%остаток)
  • Операторы отношения:==, !=, >, <, >=, <=(возвращает 1 для истины, 0 для лжи)
  • Логические операторы:&&(И),||(ИЛИ),!(НЕ), поддерживает сокращённое вычисление
  • Побитовые операторы:&(побитовое И),|(побитовое ИЛИ),^(побитовое исключающее ИЛИ),~(побитовое НЕ),<<(сдвиг влево),>>(сдвиг вправо)
  • Операторы присваивания:=, +=, -=, *=, /=, %=(составное присваивание, напримерa += bЭквивалентноa = a + b)
  • Оператор инкремента/декремента:++(инкремент),--(декремент), который имеет две формы: префиксную (сначала уменьшение, затем вычисление) и постфиксную (сначала вычисление, затем уменьшение)
  • Другие операторы:sizeof(вычисляет размер в байтах типа или переменной),?:(тернарный оператор),&(взятие адреса),*(разыменование),->(доступ к членам через указатель),.(прямой доступ к членам)
int a = 5, b = 10;
int sum = a + b;           // 算术运算符 +,sum = 15
int isEqual = (a == b);   // 关系运算符 ==,isEqual = 0(假)
int result = a << 1;      // 位运算左移,result = 10(相当于 a * 2)
a++;                       // 后缀自增,a 变为 6
int max = (a > b) ? a : b; // 三目运算符,max = b = 10

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

Ключевые слова

В следующей таблице перечислены зарезервированные слова языка C. Эти зарезервированные слова нельзя использовать в качестве имён констант, имён переменных или других имён идентификаторов; они имеют определённое синтаксическое значение в языке C.

Ключевые слова Описание
autoОбъявляет автоматические переменные (класс памяти по умолчанию для локальных переменных, редко явно используется в современном C)
breakПрерывает выполнение текущего цикла или оператора switch
caseМетка ветви в операторе switch
charОбъявляет переменную символьного типа или тип возвращаемого значения функции (обычно занимает 1 байт)
constОпределяет константу только для чтения; значение переменной, изменённое с помощью const, больше нельзя изменить
continueЗавершает текущую итерацию цикла и сразу начинает следующую итерацию цикла
defaultВетвь по умолчанию в операторе switch (выполняется, когда ни один case не совпадает)
doТело цикла do-while; тело цикла выполняется как минимум один раз
doubleОбъявляет переменную с плавающей запятой двойной точности или тип возвращаемого значения функции (обычно занимает 8 байт)
elseВетвь отрицания условного оператора (используется вместе с if)
enumОбъявляет перечисляемый тип, используемый для определения набора именованных целочисленных констант
externОбъявляет, что переменная или функция определена в другом файле или в другом месте текущего файла
floatОбъявляет переменную с плавающей запятой одинарной точности или тип возвращаемого значения функции (обычно занимает 4 байта)
forОператор цикла for, подходящий для сценариев, в которых количество итераций цикла известно заранее
gotoОператор безусловного перехода (следует использовать с осторожностью; может снизить читаемость кода)
ifУсловный оператор
intОбъявляет целочисленную переменную или тип возвращаемого значения функции (обычно занимает 4 байта)
longОбъявляет переменную длинного целого типа или тип возвращаемого значения функции
регистрРекомендует компилятору разместить переменную в регистре для ускорения доступа (современные компиляторы обычно оптимизируют автоматически)
returnОператор возврата из функции, с возвращаемым значением или без него (для функций void)
shortОбъявляет переменную короткого целого типа или тип возвращаемого значения функции (обычно занимает 2 байта)
signedОбъявляет переменную знакового типа (может представлять отрицательные числа; целые числа по умолчанию знаковые)
sizeofВычисляет количество байтов, занимаемых типом данных или переменной (оператор времени компиляции)
staticОбъявляет статические переменные (время жизни локальных статических переменных продлевается до конца программы; глобальные статические переменные ограничены областью видимости файла)
structОбъявляет тип структуры, объединяющей данные разных типов в одно целое
switchОператор множественного выбора, выполняет переход к соответствующему case в зависимости от значения выражения
typedefОпределяет новый псевдоним для существующего типа данных, чтобы улучшить читаемость кода
unsignedОбъявляет переменную беззнакового типа (может представлять только неотрицательные числа, с большим диапазоном)
объединениеОбъявляет тип объединения (union); все члены совместно используют одну и ту же область памяти
voidОбъявляет функцию без возвращаемого значения или без параметров; также используется для объявления нетипизированного указателяvoid*
volatileОбъявляет, что переменная может быть изменена внешними факторами (такими как аппаратное обеспечение или прерывания), запрещая компилятору оптимизировать чтение и запись этой переменной
whileОператор цикла while, подходит для сценариев, когда количество итераций неизвестно, но условие завершения ясно

Новые ключевые слова в C99

_Bool _Complex _Imaginary inline restrict

Ключевое слово, добавленное в C99, в основном используется для: поддержки логического типа (_Bool), поддержки комплексных чисел (_Complex、_Imaginary), оптимизация inline-функций (inline), оптимизация ограничения псевдонимов указателей (restrict)。

Новые ключевые слова в C11

_Alignas _Alignof _Atomic _Generic _Noreturn
_Static_assert _Thread_local      

Ключевое слово, добавленное в C11, в основном используется для: управления выравниванием памяти (_Alignas、_Alignof), поддержка атомарных операций и многопоточности (_Atomic、_Thread_local), обобщённый выбор (_Generic), статическое утверждение (_Static_assert) и пометка функций, не возвращающих значение (_Noreturn)。


Пробельные символы в C

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

В C к пробельным символам относят пробел (клавиша пробела), табуляцию (Tab), новую строку и комментарии. Пробельные символы разделяют части оператора, позволяя компилятору определить, где элемент оператора (например,int) заканчивается и где начинается следующий элемент. Поэтому в следующем операторе:

int age;

intиageМежду ними должен быть хотя бы один пробельный символ (обычно пробел), чтобы компилятор мог их различать. С другой стороны, в следующем операторе:

fruit = apples + oranges;   // 获取水果的总数

fruitи=, или=иapplesСимвол пробела между ними не обязателен, но для улучшения читаемости при необходимости можно добавить пробелы.

Хорошие привычки расстановки пробелов и отступов — важная часть высококачественного кода; рекомендуется следовать следующим соглашениям:

  • Используйте единообразные отступы (обычно 4 пробела или 1 табуляцию) для обозначения иерархии блоков кода.
  • Добавляйте пробелы с обеих сторон операторов (например,a + b), что делает выражения более удобочитаемыми.
  • Добавляйте пробел после запятых (например,int a, b, c;), чтобы различать несколько элементов.
  • Используйте пустые строки надлежащим образом для разделения логически связанных разделов кода, что улучшает общую читаемость.
Другие расширения