系列文章目录
前言
蓝色问号代表个人理解 绿色代表来源 红色问号代表尚有疑问
为什么要读标准?因为全面、权威,所有答案都在标准里面!
哪些人适合浏览本系列文章?不清楚C语言程序的组成,以及每个组成部分的详细内容
持续更新,码字不易,求点赞收藏
前言
为什么要读标准?因为全面、权威,所有答案都在标准里面!哪些人适合浏览本系列文章?不清楚C语言程序的组成,以及每个组成部分的详细内容
持续更新,码字不易,求点赞收藏
1、概述
- token,国标翻译为单词,但是感觉不准确?
- 翻译3~6阶段所有词法元素为预处理token,7、8阶段已转换成了token
- 转换为token的每个预处理token应具有token的词汇形式
- 若 ’ 或 “ 字符与最后一个类别的预处理单元(不属于上述范围内的任一非白空类符)匹配,行为未定义
- 预处理单元可以被白空类单元分隔(注释或白空类符或两者都有)
- 若直至某个给定字符为止的输入流字符序列已被分析为预处理单词,则下一个预处理单词是可构成预处理单词的最长的字符序列 ,比如, x ++ + ++y 是不符合定义的,x++已被分析为预处理单词,后面的字符构成不了预处理单词
#include<bits/stdc++.h>
using namespace std;
int main(int argc,char *argv[]){
int x = 0, y = 0, c;
c = x ++ + ++ y;
cout << x << endl << y << endl << c; //输出 1 1 1
return 0;
}
token
pp-token
2、关键字
关键字 | 说明 |
---|---|
auto | 声明自动变量 |
break | 跳出当前循环 |
case | 开关语句分支 |
char | 声明字符型变量或函数返回值类型 |
const | 定义常量,如果一个变量被 const 修饰,那么它的值就不能再被改变 |
continue | 结束当前循环,开始下一轮循环 |
default | 开关语句中的"其它"分支 |
do | 循环语句的循环体 |
double | 声明双精度浮点型变量或函数返回值类型 |
else | 条件语句否定分支(与 if 连用) |
enum | 声明枚举类型 |
extern | 声明变量或函数是在其它文件或本文件的其他位置定义 |
float | 声明浮点型变量或函数返回值类型 |
for | 一种循环语句 |
goto | 无条件跳转语句 |
if | 条件语句 |
int | 声明整型变量或函数 |
long | 声明长整型变量或函数返回值类型 |
register | 声明寄存器变量 |
return | 子程序返回语句(可以带参数,也可不带参数) |
short | 声明短整型变量或函数 |
signed | 声明有符号类型变量或函数 |
sizeof | 计算数据类型或变量长度(即所占字节数) |
static | 声明静态变量 |
struct | 声明结构体类型 |
switch | 用于开关语句 |
typedef | 用以给数据类型取别名 |
unsigned | 声明无符号类型变量或函数 |
union | 声明共用体类型 |
void | 声明函数无返回值或无参数,声明无类型指针 |
volatile | 说明变量在程序执行中可被隐含地改变 |
while | 循环语句的循环条件 |
3、标识符
描述
标识符是由非数字字符(包括下划线和大小写字母)及数字构成的序列,其第一个字符应是非数字字符,不同的标识符取决于有效字符的不同
分类
- 结构成员或标记
- 联合成员或标记
- 枚举成员或标记,枚举成员称枚举常量
- 自定义类型名
- 标签名
- 宏名或宏形参
约束
- 组成标识符的字符序列不应与组成关键字的字符序列相同
- 标识符最大长度没有具体限制。标准规定宏名或无外部链接的标识符前31个字符定为有效字符(不忽略大小写),外部链接的标识符前6个字符定为有效字符(可忽略大小写),具体由实现定义,存在有效字符相同、非有效字符不同的两个标识符的行为未定义
3.1、标识符作用域
3.1.1、作用域范围
- 函数(function)作用域:仅标签具有函数作用域,通过冒号隐式声明(go to语句)
- 文件(file)作用域:声明标识符的声明符或类型说明符出现在所有块或参数列表之外,在翻译单元的末尾终止,比如,全局变量
- 块(block)作用域:声明标识符的声明符或类型说明符出现在块内或函数定义中的参数声明列表内,终止于},比如,函数形参
- 函数原型(function prototype)作用域:如果声明标识符的声明符或类型区分符出现在函数原型(不是函数定义的一部分)的参数声明列表中,在函数声明的末尾终止
#include<bits/stdc++.h>
using namespace std;
int test1(int a, int b); //a、b函数原型作用域
//buf1、buf2块作用域
int test1(int buf1, int buf2){
return buf1 + buf2;
}
int N = 100, M; //M, N文件作用域
int main()
{
label: M = test1(N, M); //label函数作用域
if(M < 1000){
goto label;
}
cout << M; //输出 1000
return 0;
}
- 结构、联合和枚举标记的作用域在声明标记的类型区分符时,标记出现后立即开始
- 每个枚举常量的作用域都在其在枚举符列表中定义常量的枚举符后立即开始
- 任何其他标识符的作用域都是在其声明程序完成后立即开始
#include<bits/stdc++.h>
using namespace std;
enum test{
//枚举作用域开始
a = 100, //枚举常量作用域开始
b
}num;
int main()
{
cout << 100 + num;
return 0;
}
3.1.2、链接(linkage)
通过链接可在不同作用域或同一作用域,引用同一个对象或函数
- 外部链接(external):一组翻译单元中指向同一个对象或函数,只需extern,若文件范围内有可见声明则与其具有相同的链接,若文件范围内没有可见声明则为外部链接
- 内部链接(internal):一个翻译单元中指向同一个对象或函数,文件作用域 + static,作用:别的文件不能访问
- 无链接(none):指向独一无二的实体,声明为对象或函数以外的任何标识符;声明为函数参数的标识符;没有extern的块内声明的对象标识符
- 如果在翻译单元中,同一标识符同时出现在内部和外部链接中,则该行为未定义
- 函数标识符和文件作用范围的对象默认外部链接
//test2.cpp
int b = 100;
//test1.cpp
#include<bits/stdc++.h>
using namespace std;
static int b = 1000;
void test_fuc(){
extern int b;
cout << b;
}
int main()
{
test_fuc();
return 0;
}
//多文件编译$g++ -o test test1.cpp test2.cpp,输出1000,有extern但是文件作用范围内有可见声明,所以extern b的链接是内部链接
//将test1的static int b = 1000;语句删除,再次运行输出100,有extern且文件作用范围内没有可见声明,所以extern b的链接是外部链接
//将test2的int b = 100;语句前加上static,再次编译,编译失败
3.1.3、命名空间
不同类别的标识符具有不同的命名空间
类别 | 消除歧义方法 |
---|---|
标签名称 | 通过标签声明和使用的语法消除歧义 |
结构、联合和枚举的标记 | 通过跟随关键字struct、union或enum来消除歧义 |
结构或联合的成员 | 通过. 或 ->运算符访问成员时使用的表达式类型消除歧义 |
所有其他标识符称为普通标识符 | 在普通声明器中声明或作为枚举常量声明 |
//正常编译
#include<bits/stdc++.h>
using namespace std;
struct test1
{
int a = 1;
}test1