C Базовый синтаксис
Язык C — универсальный язык программирования, широко используемый в таких областях, как системное программирование, разработка встраиваемых систем и высокопроизводительные вычисления.
Язык C обладает такими характеристиками, как высокая эффективность, гибкость и хорошая переносимость. Он является основой многих других языков программирования (таких как C, Java, Go) и остаётся основным выбором для операционных систем, драйверов и низкоуровневых библиотечных функций.
В языке C токены — это базовые строительные блоки программы. Компилятор выполняет лексический анализ исходного кода, разбивая код на отдельные токены. Токены — это наименьшие значимые единицы, которые может распознать компилятор, и вся программа на C состоит из этих токенов.
Токены в языке C в основном включают следующие типы:
- Ключевые слова: слова, зарезервированные языком и имеющие специальное значение, такие как
int、if、return。 - Идентификаторы: имена, определяемые программистами, используемые для переменных, функций, массивов и т. д.
- Константы: значения в программе, которые фиксированы и не изменяются, например целые числа
42, числа с плавающей запятой3.14。 - Строковые литералы: последовательности символов, заключённые в двойные кавычки, например
"Hello"。 - Операторы: символы, используемые для выполнения операций, например
+、==、&&。 - Разделители: символы, используемые для разделения инструкций и блоков кода, например
;、{}。
Базовая структура программы на C
Это простая программа на языке C, которая может вывести "Hello, World!"
Пример
int main() {
printf("Hello, World!\n");
return 0;
}
Приведённый выше код состоит из следующей структуры:
- Директивы препроцессора: например
#includeи#define, обрабатываемые препроцессором перед компиляцией. - функция main: каждая программа на C имеет одну и только одну
main()Функция является точкой входа в программу. - Объявление переменных: объявляет переменные, используемые в программе. C89 требует, чтобы объявления находились в самом начале блока кода.
- Определение функции: определяет функции, используемые в программе, описывая конкретную логику реализации функций.
Более сложное объяснение структуры программы на C (каждое понятие будет подробно рассмотрено в последующих главах):
Пример
#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;), чтобы различать несколько элементов. - Используйте пустые строки надлежащим образом для разделения логически связанных разделов кода, что улучшает общую читаемость.