C 语言语法符号
【一】语法符号的理解
每种编程语言都有自己的词汇和语法规则。编译器不会把源代码直接当作一整段文字理解,而是先进行词法分析,将代码识别成一个个具有语法意义的最小单元,这些单元通常称为 Token(记号或词法单元)。
例如:
int sum = a + 10;可以识别为:
int sum = a + 10 ;关键字 标识符 运算符 标识符 运算符 常量 标点符号按照本系列笔记便于理解的分类方式,可以将常见语法符号分为:
- 关键字:由语言标准赋予固定含义的单词;
- 标识符:由程序员命名的变量、函数、类型等名称;
- 运算符:表示计算、比较、赋值或其他操作的符号;
- 分隔符:用于分隔词法单元的空白字符和注释;
- 标点符号:用于组织声明、表达式、语句和代码块的符号。
此外,源代码中还有常量和字符串字面量。它们属于 C 语言 Token 的重要组成部分,将在“常量”章节单独讲解。
从 C 标准的词法分类来看,许多“运算符”和“标点符号”会统一归入 punctuator(标点符号/界符)。本章将它们分开说明,是为了便于初学者按用途理解。
【二】关键字
关键字是由 C 语言标准预先规定并赋予特殊语法含义的单词,不能用作变量名、函数名或其他标识符。
【1】C90 的 32 个关键字
C90 规定了 32 个经典关键字:
auto break case char constcontinue default do double elseenum extern float for gotoif int long register returnshort signed sizeof static structswitch typedef union unsigned voidvolatile while关键字区分大小写。例如,int 是关键字,而 Int 不是关键字;但不应通过改变大小写来创建含义相近的名称。
【2】后续标准新增的关键字
C 语言会随标准更新而扩展,因此“C 语言只有 32 个关键字”只适用于 C90。常见新增关键字如下:
(1)C99 新增
inline restrict _Bool _Complex _Imaginaryinline:建议以内联方式处理函数;restrict:表达指针访问对象的别名约束;_Bool:布尔类型;_Complex、_Imaginary:复数和虚数类型相关关键字,其中虚数类型属于实现可选功能。
(2)C11 新增
_Alignas _Alignof _Atomic _Generic_Noreturn _Static_assert _Thread_local这些关键字主要用于对齐控制、原子操作、泛型选择、静态断言和线程存储期等功能。
(3)C23 常用新增关键字
alignas alignof bool constexprfalse nullptr static_assert thread_localtrue typeof typeof_unqual _BitIntC23 较新,不同编译器对这些关键字的支持程度可能不同。学习或使用 C23 功能时,应确认编译器版本和所选择的语言标准模式。
【3】容易误认为关键字的名称
以下名称虽然经常出现在 C 程序中,但它们并不是 C 语言关键字:
| 名称 | 实际性质 |
|---|---|
main | 程序入口函数的约定名称 |
printf、scanf | 标准库函数名 |
NULL | 标准头文件提供的宏 |
size_t | 标准库定义的类型名 |
include、define | 预处理指令中的名称 |
它们分别受到标准库或预处理规则约束,不能简单按普通关键字理解。
【三】标识符
标识符是程序中名称的词法形式,可用于命名宏、变量、函数、形参、结构体成员、自定义类型等程序实体。
C 语言标识符的基本命名规则如下:
- 基础且可移植的标识符由英文字母
A-Z、a-z、数字0-9和下划线_组成。 - 第一个字符必须是字母或下划线,不能是数字。
- 标识符不能与 C 语言关键字相同。
- C 语言区分大小写,因此
sum、Sum和SUM是三个不同的标识符。 - 标识符中不能包含空格、连字符
-、点号.、@等字符。
新版 C 标准也支持一定范围的通用字符名称及扩展字符,但其可用性还受源文件编码和编译器支持影响。基础学习及追求可移植性时,优先使用英文字母、数字和下划线。
【1】合法与非法标识符
下面是一些合法的标识符:
x y sum a100 student_name score2以下标识符不合法:
| 名称 | 原因 |
|---|---|
1a | 以数字开头 |
3'a | 以数字开头,并且包含单引号 |
x*y | 包含运算符 * |
@ | @ 不能构成基础标识符 |
b.8 | 包含点号 . |
my-name | 包含连字符 - |
my name | 包含空格,会被识别为两个词法单元 |
while | 与关键字相同 |
【2】命名建议
- 名称应表达用途,例如用
student_count表示学生数量,而不是随意使用a1。 - 可以采用下划线命名法
student_count或小驼峰命名法studentCount,同一项目中应保持一致。 - 常量宏通常使用全大写字母和下划线,例如
MAX_SIZE。 - 不要只通过大小写区分含义相近的变量,例如同时定义
data、Data和DATA,这会降低可读性。 - 简短的局部循环变量可以使用
i、j等惯用名称,但作用范围较大的名称应更具体。
【3】保留标识符
某些形式的标识符保留给编译器、标准库或具体实现使用。编写用户代码时,应遵循以下安全规则:
- 不要定义以双下划线开头的名称,如
__value; - 不要定义以下划线加大写字母开头的名称,如
_Value; - 在文件作用域中,避免定义任何以下划线开头的名称;
- 不要重用标准库中已有的函数名、宏名和类型名来表达其他含义。
例如,_A7b_3x 从字符组成规则看是合法形式,但它以下划线和大写字母开头,属于实现保留标识符,不应在用户代码中使用。
【四】运算符
运算符用于表示计算、比较、赋值、成员访问等操作。一个运算符需要几个操作数,就称为几元运算符。例如,-a 中的 - 是一元运算符,a - b 中的 - 是二元运算符,condition ? a : b 是三元条件运算符。
按照功能,常用运算符可以概括为:
| 类别 | 常见运算符 | 作用概述 |
|---|---|---|
| 算术运算符 | +、-、*、/、% | 执行基本算术运算 |
| 关系运算符 | <、<=、>、>=、==、!= | 比较两个值 |
| 逻辑运算符 | &&、` | |
| 位运算符 | &、` | 、^、~、<<、>>` |
| 赋值运算符 | =、+=、-=、*=、/= 等 | 为对象赋值或执行复合赋值 |
| 自增、自减运算符 | ++、-- | 将操作数增加或减少 1 |
| 条件运算符 | ?: | 根据条件从两个表达式中选择一个 |
| 指针相关运算符 | &、* | 获取对象地址或间接访问所指对象 |
| 成员访问运算符 | .、-> | 访问结构体或共用体成员 |
| 其他运算符 | sizeof、类型转换、下标 []、函数调用 ()、逗号 , | 完成类型大小查询等操作 |
同一个符号在不同上下文中可能具有不同含义。例如,* 既可以表示乘法,也可以用于声明指针或解引用指针;& 既可以表示按位与,也可以表示取地址。
运算符还涉及优先级、结合性和求值规则。为了让表达式含义更清楚,不确定时应主动使用圆括号,而不是仅依赖记忆优先级。具体规则将在后续运算符章节中展开。
【五】分隔符
分隔符用于划分相邻的词法单元。常见分隔内容包括:
- 空格(space);
- 水平制表符(tab);
- 换行符(newline);
- 其他空白字符,例如垂直制表和换页;
- 注释
// ...和/* ... */。
在预处理阶段,注释会被替换为空白,因此注释也能起到分隔词法单元的作用。字符串或字符常量内部的 //、/* 并不会开始注释:
const char *url = "https://example.com"; // 字符串中的 // 是普通字符char slash = '/'; // 字符常量中的 / 是普通字符空白字符有时可以省略,有时则必不可少:
int count; // int 和 count 之间必须分隔int intcount; // intcount 是一个完整的标识符,不等同于 int count
total=a+b; // 编译器能够识别,但不利于阅读total = a + b; // 含义相同,格式更清晰还应注意:
//注释持续到当前行末尾;/* ... */块注释可以跨行,但不能嵌套;- 换行通常只是空白,但它会结束
//注释和预处理指令; - 不能用空白拆开一个完整的多字符运算符,例如
>=、==、++。
合理使用空格、缩进和换行不会改变大多数代码的含义,却能显著提升可读性并帮助排查语法错误。
【六】标点符号
C 语言中常见的标点符号包括逗号、分号、冒号、圆括号、方括号、花括号、点号和箭头等。它们用于组织声明、表达式、语句、函数、数组和代码块。
| 符号 | 常见用途 |
|---|---|
, | 分隔声明项、函数参数和初始化器;在特定上下文中也可作为逗号运算符 |
; | 结束声明或表达式语句;单独的 ; 表示空语句 |
: | 用于 case、default、标签以及条件运算符 ?: |
( ) | 函数声明与调用、条件、表达式分组和类型转换 |
[ ] | 数组声明、数组下标和属性语法等 |
{ } | 构成复合语句、函数体或初始化器 |
. | 通过对象访问结构体或共用体成员 |
-> | 通过指针访问结构体或共用体成员 |
#、## | 预处理指令及宏中的字符串化、记号拼接 |
... | 可变参数函数或其他标准规定的省略形式 |
标点符号与空白分隔符不同:它们具有严格的语法作用,不能随意省略。部分符号在特定上下文中也属于运算符,例如逗号、圆括号、方括号、点号和箭头。
下面的程序集中演示了常见标点符号的用法:
#include <stdio.h>
int add(int x, int y){ return x + y;}
int main(void){ int values[2] = {3, 4}; int result = add(values[0], values[1]);
switch (result) { case 7: printf("result = %d\n", result); break; default: printf("unexpected result\n"); break; }
return 0;}在这个示例中:
- 逗号分隔函数形参、实参和数组初始化元素;
- 分号结束声明、函数调用和
return、break语句; - 圆括号用于函数声明、函数调用和
switch条件; - 方括号用于数组声明及下标访问;
- 花括号构成初始化器、函数体和
switch语句体; - 冒号跟在
case和default标签之后。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!














