<初学C++ Primer Plus>争取一次性搞清楚那些乱七八糟的符号

C++符号与标识符全解析

为什么想系统了解C++语言

学习过程中的困扰

        中文跟英文有巨大的区别,计算机语言又都是用的英文,这很容易导致同样的概念用中文翻译过来之后的就让人晕头转向。

        比如C++ Primer Plus中文版,从第2章涉及到C++程序开始,cout就没翻译清楚。首先英文版刚开始介绍cout时就用括号标注了读音(pronounced"see-out"),中文翻译视而不见,简单的东西硬是漏翻掉让人去猜;其次,cout在英文版里就对应两个词,object和facility,对C++来说是对象,对程序员来说是工具,但中文翻译却在初学者还没熟悉概念的时候,紧随其后蹦出一个cout函数概念,cout这玩意一会儿是对象,一会儿是工具,一会儿给翻成了函数,问题是后面详细介绍的时候又明确指出它是对象,这不禁让初学者困惑。如果翻译校订仔细,相信能发现这个错误:“seeing cout instead of the printf() function”被翻译成“看到cout函数(而不是printf()函数)时”,C语言中printf()确实是函数,但是C++中cout不是函数,用C++的语言来说它就是对象。其他地方这里就不举例了,建议如果看得仔细的话,可以配上英文版纸质或电子版。


        所以,其实我们有必要去梳理下C++语言的设计逻辑,这样凭着自己的深层次的基础性理解,无论看中文还是英文,都不容易被带偏,毕竟尽信书不如无书,实践出真知,书本只是基础。


剖析思考C++语言

        计算机语言其实跟人类的语言是类似的东西,毕竟都叫做语言。人类的语言也有千差万别,机器的语言也是一样,这很容易让人联想到圣经里的巴别塔,其实上帝不光让人类说不同的语言,也让万物之间不能沟通,人类向往天堂,且一直在建造通往天堂的巴别塔,可以说任重而道远。

        华为鸿蒙的野心是做物联网时代万物互联的基础操作系统,允许我断章取义,真正能做到万物互联的是神而不是人。我们对未来还是充满信心,能做的要做的事情太多了。什么时候能用中文做操作系统底层架构那咱们就真牛了,咱也不用被汉化的知识整懵逼了。
 

        回归正题:为了搞清楚C++语言,我们还是得从最底层的最基础也是最简单的逻辑去剖析理解。作为初学者我个人粗略认为,C++程序是由C++语言内置的词汇或者说预定义内容和程序员自定义的内容组成。        

        ---2025-11-21---👇

        一开始之所以联想到预定义和自定义,一方面困惑于符号与标识符的区别,还有就是看到过很多C++预定义的内容比如#define,一方面受语言这个词汇影响自然容易想到人类语言,人类语言的汉字和名字就能对应上符号和标识符,一个是预定义的一个是自定义的。

         ---2025-11-21---👆

        当我询问AI可以这么理解吗?得到了更详细的解读,经过多番查询整理如下:


        你的理解基本正确,但可以更精确地分层表述。C++程序的构成确实可以看作​​语言内置词汇​(预定义内容)与​​程序员定义(自定义内容)​​的交互,但需要进一步明确其层次关系和交互规则。以下是更系统的分析:

C++程序基本内容系统分析


​1. 构成要素分类​

​(1) 语言内置词汇(预定义内容)​

  • ​关键词(Keywords)​
    int, if, class, template 等,不可被重定义或修改。
  • ​运算符(Operators)​
    +, <<, -> 等,部分可重载(如operator+),但核心语义固定。
  • ​特殊标识符(Reserved Identifiers)​
    main, operator new, typeid 等,具有标准规定的特殊行为。
  • ​字面量(Literals)​
    42, "hello", nullptr 等,语法形式固定。
  • ​预处理器符号​
    #define, #include 等,在编译前处理。

​(2) 程序员定义(自定义内容​)

  • ​标识符(Identifiers)​
    变量名(count)、函数名(calculate)、类名(MyClass)等。
  • ​运算符重载​
    自定义operator+等,但必须遵循语言规定的重载规则。
  • ​类型系统扩展​
    通过class/struct定义新类型,或通过typedef/using创建类型别名。
  • ​宏(谨慎使用)​
    #define MAX 100,但可能污染命名空间。

​2. 二者的交互逻辑​

graph LR
    A[语言内置词汇] -->|提供基础规则| B[程序员自定义内容]
    B -->|遵循| C[语法约束]
    B -->|扩展| D[新功能]
    A -->|限制| B

​(1) 依赖关系​

  • ​自定义内容必须基于内置词汇的规则​
    例如:
    class MyClass {          // 使用关键词`class`
        int value;           // 使用内置类型`int`
        void print() const;  // 使用`const`修饰符
    };

​(2) 扩展机制​

  • ​有限度的自由​
    • 可重载运算符,但不能创建新运算符(如不能定义**表示幂运算)。
    • 可定义新类型,但必须通过已有类型组合(如class/enum)。

​(3) 边界控制​

​自定义行为​​语言限制​示例
定义变量名不能与关键词冲突int class;
重载运算符必须保留原始优先级和结合性a + b 永远先于 a << b
实现main函数必须符合标准签名int main(int, char*[])

​3. 设计哲学体现​

​(1) 约束与自由的平衡​

  • ​约束性规则​​(保证可预测性)

    int x = 42;    // 类型必须明确(或通过`auto`推导)
    x = "hello";   ❌ // 禁止隐式类型不匹配赋值
  • ​扩展性自由​​(支持领域特定设计)

    class Matrix {
    public:
        Matrix operator*(const Matrix& rhs);  // 自定义矩阵乘法
    };

​(2) 显式优于隐式​

  • 自定义内容需显式声明:
    explicit Data(int bytes);  // 禁止隐式转换
    override void draw();      // 显式标记覆盖

​(3) 零开销抽象​

  • 自定义类型与内置类型性能等价:
    std::array<int, 100> arr;  // 编译时确定大小,与内置数组性能相同

​4. 常见误解澄清​

​(1) "所有符号都可自定义" ❌​

  • ​不可自定义的要素​​:
    • 关键词(如不能将class改为myclass
    • 语法结构(如不能将if (x) {...}改为when (x) {...}
    • 核心运算符语义(如a + b永远表示加法,不能全局改为减法)

​(2) "宏是彻底的自定义" ❌​

  • 宏在预处理阶段展开,但:
    #define BEGIN {   // 不推荐:破坏代码可读性
    BEGIN             // 实际展开为 `{`
    • 仍受限于C++语法规则(如宏展开后必须形成合法代码)。

​5. 正确理解范式​

// 语言提供"积木块"(内置词汇)
int, +, if, class, ...

// 程序员用积木搭建"建筑"(自定义内容)
class Widget {          // 使用`class`关键词
    int priority;       // 使用`int`类型
public:
    bool operator<(Widget other) {  // 重载`<`
        return priority < other.priority;
    }
};

// 但无法修改积木本身(如不能把`int`改成`integer`)

​总结​

你的理解方向正确,但需注意:

  1. ​分层关系​​:自定义内容必须基于语言提供的底层规则
  2. ​边界明确​​:语言核心词汇不可修改,只能在允许范围内扩展
  3. ​设计意图​​:通过约束保证基础可靠性,通过扩展机制提供灵活性

这种设计使C++既能严格保证系统级编程的精确性,又能支持高层抽象表达。

C++内置词汇的完整分类


        以下是C++内置词汇的完整分类及设计逻辑分析,基于C++20标准整理:


​1. 关键词(Keywords)​

​(1) 基础类型声明​

关键词用途设计逻辑
int整型(≥16位)硬件直接映射
double双精度浮点IEEE 754标准支持
bool布尔型(true/false)逻辑运算优化
void无类型/空返回值泛型编程基础
auto自动类型推导(C++11)简化复杂类型声明

​(2) 类型修饰符​

关键词组合示例设计逻辑
constconst int编译期常量/不可修改
volatilevolatile char防止编译器优化(嵌入式)
mutablemutable int突破const限制(如缓存)
constexprconstexpr int编译期计算(C++11)

​(3) 流程控制​

if (cond) {} else {}      // 条件分支
for (init; cond; inc) {}   // 循环结构
while (cond) {}           // 前置判断循环
do {} while (cond);       // 后置判断循环
switch (val) { case 1: }  // 多路分支
break/continue/return      // 流程跳转

​设计逻辑​​:

  • 结构化编程基础(源自C语言)
  • switchcase必须为整型常量表达式(性能优化)

​(4) 面向对象​

关键词用途设计逻辑
class类声明数据封装
struct默认public的类C兼容性
union共用内存体内存敏感操作
virtual虚函数/多态运行时动态绑定
override显式覆盖(C++11)增强代码可读性
final禁止继承/覆盖(C++11)设计约束

​(5) 内存管理​

new/delete           // 堆内存分配
new[]/delete[]       // 数组版本
static               // 静态存储期
thread_local         // 线程局部存储(C++11)

​设计逻辑​​:

  • 对称性设计(new/delete配对)
  • thread_local支持并发编程

​(6) 模板与泛型​

template<typename T>  // 模板声明
typename             // 依赖类型名
concept              // 概念约束(C++20)
requires             // 约束表达式(C++20)

​2. 运算符(Operators)​

​(1) 算术运算​

运算符示例可重载设计逻辑
+ - * / %a + b数学直觉
++ --i++前置/后置区分

​(2) 位操作​

运算符示例可重载设计逻辑
`&^ ~`a & b
<< >>a << 2移位/流输出双重语义

​(3) 逻辑运算​

&& || !         // 逻辑与/或/非(短路求值)
== != < > <= >= // 比较运算符
<=>             // 三向比较(C++20)

​(4) 内存访问​

运算符示例可重载设计逻辑
**ptr解引用/乘法双重语义
&&var取地址/位与双重语义
->ptr->m指针成员访问
->*ptr->*m成员指针访问

​(5) 特殊运算符​

, (逗号运算符)      // 表达式分隔
?: (三目运算符)     // 条件表达式
sizeof            // 类型大小
typeid            // 类型信息

​3. 特殊标识符​(Reserved Identifiers)​

(1) 典型特殊标识符列表​

​标识符​

​类别​

​用途​

​是否可重载​

main

程序入口

应用程序启动点

operator new

内存管理

动态内存分配

✅(可替换)

operator delete

内存管理

内存释放

✅(可替换)

typeid

运行时类型信息

类型查询

dynamic_cast

类型转换

安全向下转型

sizeof

编译时操作符

类型/对象大小计算

this

类成员函数

当前对象指针

(2) 设计逻辑分析​

①为什么需要特殊标识符?​

  • ​保证关键功能的一致性​

    例如所有C++程序必须通过main启动,确保操作系统接口统一。

  • ​提供可扩展的底层控制​

    如允许重载operator new实现自定义内存池,但保留默认行为。

② 与关键词的区别​

​特性​

​特殊标识符​

​关键词​

​可重用性​

部分可重载/替换

完全不可重定义

​语法角色​

标识符(可包含字母数字)

固定词法单元(如if

​示例​

operator<<

while

③与普通标识符的对比​

// 特殊标识符(语言预定义行为)
int main() {}  // 必须存在且符合签名

// 普通标识符(完全自定义)
int my_function() { return 42; }  // 名称、行为均可自由定义

        它们填补了​​关键词的刚性约束​​与​​普通标识符的完全自由​​之间的空白,是C++“给你足够绳子,但不会让你轻易上吊”设计哲学的典型体现。


​4. 字面量(Literals)​

​(1) 数值字面量​

42          // 十进制
0x2A        // 十六进制
0b101010    // 二进制(C++14)
3.14f       // float
6.02e23     // 科学计数法

​(2) 字符串字面量​

"hello"           // 普通字符串
u8"UTF-8"         // UTF-8编码(C++11)
L"wide"           // 宽字符
R"(raw\nstring)"  // 原始字符串(C++11)

​(3) 自定义字面量(C++11)​

auto x = 10_km;    // 用户定义字面量
auto y = 3.14_rad; // 需定义operator""_rad

5. 预处理器符号​

符号示例用途
#define#define PI 3.14宏定义
#include#include <vector>文件包含
#ifdef#ifdef DEBUG条件编译
#pragma#pragma once编译器指令

​​​完整关键词列表(C++20)​

alignas alignof and and_eq asm auto bitand bitor bool 
break case catch char char8_t char16_t char32_t class 
compl concept const consteval constexpr constinit const_cast 
continue co_await co_return co_yield decltype default delete 
do double dynamic_cast else enum explicit export extern 
false float for friend goto if inline int long 
mutable namespace new noexcept not not_eq nullptr 
operator or or_eq private protected public register 
reinterpret_cast requires return short signed sizeof 
static static_assert static_cast struct switch synchronized 
template this thread_local throw true try typedef 
typeid typename union unsigned using virtual void 
volatile wchar_t while xor xor_eq

        以上体系展示了C++如何通过精心设计的词汇系统平衡底层控制与高级抽象,既保留C的硬件访问能力,又支持现代软件工程范式。

C++初学者常见的困惑(未完待续)


C++符号与标识符的区别是什么?

        在 C++ 中,符号(Symbols/Punctuators) 和标识符(Identifiers)是两类完全不同的语法元素,它们在语言中扮演不同的角色。以下是它们的核心区别及具体分类:

1. 标识符(Identifiers)

定义:由程序员自定义的名称,用于标识变量、函数、类、命名空间等程序实体。  
规则:
- 组成:字母(`A-Z, a-z`)、数字(`0-9`)、下划线(`_`)。
- 开头:不能是数字(如 `1var` 非法)。
- 区分大小写:`var` 和 `Var` 是不同的标识符。
- 不能是关键字(如 `int`、`class` 不能作为标识符)。

示例:
int age;          // "age" 是标识符
void calculate(); // "calculate" 是标识符
class MyClass;    // "MyClass" 是标识符

2. 符号(Symbols/Punctuators)

定义:语言预定义的标点或操作符,用于语法结构或运算。  
分类:

(1) 标点符号(Punctuators)
- 用于分隔或终止代码单元:

  ;    // 语句结束
  ,    // 参数或列表分隔
  {}   // 代码块边界
  []   // 数组下标或Lambda捕获
  ()   // 函数调用或优先级分组
  ::   // 作用域解析
  . -> // 成员访问

(2) 运算符(Operators)
- 用于数学、逻辑或内存操作:

  + - * / %   // 算术运算
  == != < >   // 比较运算
  && || !     // 逻辑运算
  = += -=     // 赋值运算
  & *         // 指针运算(取地址/解引用)

(3) 预处理符号
- 以 `#` 开头的预处理指令:

  #include <iostream>
  #define PI 3.14
  #ifdef DEBUG

(4) 字面量分隔符
- 修饰字面量的符号:

  'A'     // 字符字面量
  "Hello" // 字符串字面量
  3.14f   // float字面量(f后缀)

3. 标识符 vs 符号的关键区别

| **特征**          | **标识符**                          | **符号**                          |
|--------------------|------------------------------------|----------------------------------|
| **来源**          | 程序员自定义                     | 语言预定义                     |
| **作用**          | 命名程序实体(变量、函数等)         | 语法结构或运算                   |
| **是否可自定义**  | 是(需遵守命名规则)                 | 否(固定用途)                   |
| **示例**          | `count`, `calculate`, `MyClass`    | `;`, `+`, `::`, `#include`       |

4. 易混淆场景

(1) 下划线 `_` 的双重角色**
- 在标识符中:合法字符(如 `_value`)。
- 作为符号:单独使用时是运算符(如 `a _ b` 可能被解析为减法或用户定义运算符)。

(2) `*` 和 `&` 的多义性
- 在声明中:`int* p;` 的 `*` 是类型符号(指针)。
- 在表达式中:`*p` 的 `*` 是运算符(解引用)。

(3) 作用域解析符 `::`
- 符号 `::` 不是标识符,但连接标识符:

  std::cout;  // "std" 和 "cout" 是标识符,`::` 是符号

5. 为什么需要区分?

- 语法解析:编译器依赖符号确定代码结构(如分号结束语句)。
- 代码可读性:正确使用符号避免歧义(如 `a+++b` 应写作 `a++ + b`)。
- 错误排查:混淆二者会导致编译错误(如误将 `:` 用作变量名)。

结合前面的分析总结

- **标识符**是“名字”,由程序员定义,用于指代程序实体。

- **符号**是“语法工具”,由语言定义,用于构建代码逻辑。  

- **特殊标识符**也是符号,由语言定义,具有标准规定的特殊行为。
 

C++数据类型与变量类型的区别

        在 C++ 中,**数据类型(Data Type)** 和 **变量类型(Variable Type)** 是两个相关但不同的概念,初学者容易混淆。以下是它们的区别和联系:

1. 数据类型(Data Type)

定义:数据类型是编译器或系统定义的 **数据分类**,决定了数据的存储方式、取值范围和可执行的操作。  
特点:
- 由语言本身或标准库定义(如 `int`, `float`, `std::string`)。
- 与内存分配直接相关(如 `int` 通常占 4 字节)。
- 规定了数据的操作规则(如 `int` 支持加减乘除,`bool` 支持逻辑运算)。

分类:
1. 基本数据类型(Primitive Types)**  
   - 整数:`int`, `short`, `long`, `char`  
   - 浮点:`float`, `double`  
   - 布尔:`bool`  
   - 无类型:`void`  
2. 复合数据类型(Derived/Composite Types)**  
   - 指针:`int*`, `char*`  
   - 数组:`int[10]`  
   - 引用:`int&`  
   - 结构体/类:`struct S`, `class C`  
3. 标准库类型 
   - `std::string`, `std::vector<T>`, `std::function` 等。

2. 变量类型(Variable Type)

定义:变量类型是 **变量在声明时的具体类型**,由数据类型 + 修饰符(如 `const`、指针、引用等)组合而成。  
特点:
- 变量是数据的具名存储单元,类型决定了变量能存储的数据种类。
- 变量类型 = 数据类型 + 附加属性**(如 `const int`、`int*`)。

int a;          // 变量类型是 `int`(基本数据类型)
const float b;  // 变量类型是 `const float`(数据类型 + const修饰)
int* ptr;       // 变量类型是 `int*`(指针类型)
std::string s;  // 变量类型是 `std::string`(标准库类型)

3. 关键区别

| **维度**       | **数据类型**                  | **变量类型**                  |
|----------------|-----------------------------|-----------------------------|
| **定义范围**   | 语言或库预定义的分类           | 变量声明时使用的具体类型        |
| **组成**       | 基础类型或复合类型(如 `int`) | 数据类型 + 修饰符(如 `const int*`) |
| **内存关联**   | 决定数据存储格式和大小         | 决定变量的存储和行为规则        |
| **例子**       | `double` 是数据类型           | `volatile double*` 是变量类型 |

4. 常见混淆场景

场景1:指针和引用的类型

int x = 10;
int* p = &x;    // 变量类型是 `int*`,但 `int` 是数据类型
int& r = x;     // 变量类型是 `int&`,但 `int` 是数据类型

- `int*` 和 `int&` 是变量类型,但它们的底层数据类型是 `int`。

场景2:`const` 修饰符

const int y = 20;  // 变量类型是 `const int`,数据类型是 `int`

- `const` 是变量类型的修饰符,不属于数据类型本身。

场景3:标准库模板类型

std::vector<int> v;  // 变量类型是 `std::vector<int>`,数据类型是模板实例化的结果

- `std::vector<int>` 既是数据类型,也是变量类型(模板实例化后)。

5. 总结

- **数据类型** 是语言层面的抽象分类,**变量类型** 是具体变量声明时的类型描述。
- 变量类型可以包含数据类型以外的信息(如 `const`、`volatile`、指针/引用修饰符等)。

空白符号是否属于预定义内容

        在C++中,空白符号(包括空格、制表符、换行符等)​​不属于预定义内容​​,但它们在预处理和编译过程中具有特殊作用。以下是关键点说明:


1. ​​空白符号的分类​

  • ​空格​​ ( )
  • ​水平制表符​​ (\t)
  • ​换行符​​ (\n)
  • ​垂直制表符​​ (\v)
  • ​换页符​​ (\f)
  • ​注释​​(虽然注释在预处理后会被替换为空格,但本身不是空白符号)

2. ​​预处理阶段的行为​

  • ​宏展开前​​:空白符号用于分隔预处理指令(如 #include#define)的组成部分,但不会作为宏或标识符的一部分。
    #define X 1  // 空格分隔宏名和值
  • ​宏展开后​​:空白符号可能影响替换结果,但不会被预处理器“预定义”为特定内容。
    #define F(a,b) a##b
    F(x, y)  // 需要无空格,否则展开失败

3. ​​与预定义内容的区别​

  • ​预定义内容​​:指语言或预处理器内置的符号(如 __LINE____FILE__)或关键字(如 intif)。
  • ​空白符号​​:是语法分隔符,无预定义的语义含义,仅影响代码的解析方式。

4. ​​特殊情况​

  • ​字符串/字符常量​​:空白符号在引号内是字面量的一部分,不属于语法分隔符。
    char c = ' ';  // 空格作为字符内容
  • ​原始字符串字面量​​:换行符等会保留原样。
    const char* s = R"(Line1
    Line2)";

总结

        空白符号是C++语法中的​​分隔符​​,而非预定义的语义内容。它们在预处理和编译阶段仅用于控制代码解析,本身不具预定义的逻辑含义。

空白符号是否属于自定义内容

        在 C++ 中,​​空白符号(空格、制表符、换行符等)既不属于预定义内容,也不属于自定义内容​​,而是​​语法分隔符​​,用于控制代码的解析方式。


​1. 空白符号的定位​

  • ​不是预定义内容​​:预定义内容指语言内置的符号(如 __LINE__#define、关键字 int 等),而空白符号是语法结构的一部分,没有预定义的逻辑含义。
  • ​不是自定义内容​​:自定义内容通常是程序员定义的标识符(如变量名、宏名、函数名等),而空白符号是语言规定的分隔符,不能由程序员重新定义或改变其基本作用。

​2. 空白符号的作用​

空白符号的主要功能是​​分隔代码元素​​,例如:

  • 分隔关键字和变量名:
    int x;  // 空格分隔 `int` 和 `x`
  • 分隔宏定义:
    #define MAX 100  // 空格分隔 `#define`、`MAX` 和 `100`
  • 控制代码格式(不影响语义,但影响可读性):
    if (x > 0) {  // 换行和缩进仅用于可读性
        cout << "x is positive";
    }

​3. 特殊情况​

  • ​字符串/字符常量中的空白​​:
    如果空白符号出现在引号内(如 " "'\t'),则它们是字面量的一部分,属于程序数据而非语法分隔符。
    char space = ' ';  // 空格是字符数据
    string tab = "\t"; // 制表符是字符串数据
  • ​原始字符串(Raw String Literals)​​:
    换行符等空白会被原样保留,但仍不属于“自定义内容”。
    const char* text = R"(Line 1
    Line 2)";  // 换行符是字符串的一部分

​结论​

        空白符号在 C++ 中既不是​​预定义内容​​(如宏、关键字),也不是​​自定义内容​​(如变量名、宏名),而是​​语法分隔符​​,用于控制代码解析,但不影响程序的逻辑语义(除非在字符串/字符字面量中)。

C++语法辅助工具

在 C++ 中,类似空白符号(空格、换行符等)的​​语法辅助工具​​主要用于代码解析和格式控制,它们​​既不属于自定义内容(程序员定义的标识符)也不属于预定义内容(语言/编译器内置的符号)​​,而是​​语法结构的一部分​​。以下是这类工具的详细分类和说明:


​1. 语法辅助工具的分类​

​(1) 空白符号(Whitespace)​

  • ​作用​​:分隔代码元素(如 int x; 中的空格)。
  • ​是否可自定义/预定义​​:否,是语法强制要求的分隔符。

​(2) 注释(Comments)​

  • ​作用​​:代码说明或屏蔽,预处理阶段被替换为空格。
  • ​示例​​:
    // 单行注释
    /* 多行注释 */
  • ​是否可自定义/预定义​​:否,注释语法是语言固定的。

​(3) 分号(;)​

  • ​作用​​:终止语句(如 int x = 0;)。
  • ​是否可自定义/预定义​​:否,是语法强制要求的终结符。

​(4) 花括号({})​

  • ​作用​​:定义作用域或代码块(如函数体、类定义)。
  • ​是否可自定义/预定义​​:否,但可通过宏模拟(不推荐):
    #define BEGIN {
    #define END }

​(5) 逗号(,)​

  • ​作用​​:分隔参数或列表项(如 int a, b;)。
  • ​是否可自定义/预定义​​:否,但可通过运算符重载自定义其在特定上下文的行为(如 operator,)。

​(6) 冒号(:)​

  • ​作用​​:用于类继承、初始化列表、三目运算符等。
  • ​是否可自定义/预定义​​:否,语法固定。

​(7) 尖括号(<>)​

  • ​作用​​:模板参数列表(如 std::vector<int>)。
  • ​是否可自定义/预定义​​:否,但可通过宏模拟(极不推荐):
    #define TEMPLATE_PARAM <typename T>

​(8) 圆括号(())​

  • ​作用​​:函数调用、表达式分组。
  • ​是否可自定义/预定义​​:否,但可通过宏或运算符重载(如 operator())间接影响行为。

​(9) 预处理器符号(###)​

  • ​作用​​:宏展开时的字符串化或拼接。
  • ​示例​​:
    #define STR(x) #x       // 字符串化
    #define CONCAT(a,b) a##b // 拼接
  • ​是否可自定义/预定义​​:### 的行为是预定义的,但可通过宏组合间接自定义逻辑。

​2. 与空白符号的共性​

这些工具的共同特点是:

  1. ​非自定义​​:程序员无法修改其核心语法(如将分号改为其他符号)。
  2. ​非预定义​​:它们不是像 __LINE__std::cout 那样的预定义符号,而是语言的基础语法单元。
  3. ​语法强制性​​:编译器依赖它们解析代码结构,缺少或错误使用会导致编译失败。

​3. 特殊情况分析​

​工具​​是否可自定义​​例外/变通方式​
分号 ;宏替换(如 #define END ;
逗号 ,否(但可重载 operator,重载后可能改变语义(罕见使用)
圆括号 ()否(但可重载 operator()仿函数(Functor)中自定义调用行为
花括号 {}宏模拟(如 #define BEGIN {
注释

​4. 总结​

  • ​严格语法工具​​(如分号、花括号、注释):完全不可自定义,属于语言基础语法。
  • ​部分可干预工具​​(如逗号、圆括号):通过运算符重载或宏间接影响行为,但核心语法不变。
  • ​与空白符号的关系​​:它们和空白符号一样,是代码解析的“基础设施”,既非自定义也非预定义,而是​​语法规则本身​​。

这类工具的存在体现了 C++ 的​​语法与语义分离​​原则:

  • ​语法层​​(如分号、括号)由语言严格规定,不可更改。
  • ​语义层​​(如运算符重载、宏)允许程序员在规则内自定义行为。

C++中介于自定义内容和预定义内容之间的有哪些?

在 C++ 中,​​介于自定义内容(程序员定义)和预定义内容(语言内置)之间​​的元素通常是指那些​​由标准库或编译器提供,但允许程序员重新定义或部分自定义​​的符号或机制。以下是主要的几类:


​1. 宏(Macros)​

  • ​预定义宏​​(如 __LINE____FILE____cplusplus)是编译器内置的,不可修改。
  • ​可自定义的宏​​(如 #define 定义的宏)允许程序员覆盖或扩展行为,但可能和标准库宏冲突(如 maxmin)。
    #define max(a, b) ((a) > (b) ? (a) : (b))  // 可能覆盖标准库的 std::max

​2. 标准库名称(Standard Library Names)​

  • ​标准库类型/函数​​(如 std::stringstd::vectorstd::cout)是预定义的,但允许程序员通过命名空间或局部作用域覆盖:
    namespace my { int cout = 42; }  // 自定义 cout,隐藏 std::cout
  • ​注意​​:直接覆盖标准库名称(如全局定义 int endl;)是未定义行为(UB)。

​3. 运算符(Operators)​

  • ​预定义运算符​​(如 +==<<)的语义固定,但可通过​​运算符重载​​自定义行为:
    struct Point { int x, y; };
    bool operator==(Point a, Point b) { return a.x == b.x && a.y == b.y; }  // 自定义 ==

​4. 属性(Attributes)​

  • ​标准属性​​(如 [[nodiscard]][[deprecated]])是语言预定义的,但允许用户自定义属性(编译器可能忽略):
    [[my::custom_attr]] void foo();  // 自定义属性(依赖编译器支持)

​5. 字面量(Literals)​

  • ​预定义字面量​​(如 123"hello")的语法固定,但可通过​​用户定义字面量(UDL)​​扩展后缀:
    long double operator"" _km(long double x) { return x * 1000; }  // 自定义 _km
    auto dist = 5.0_km;  // 调用 operator"" _km

​6. 预处理器指令(Preprocessor Directives)​

  • ​固定指令​​(如 #include#ifdef)不可修改,但可通过宏组合实现间接自定义:
    #define MY_INCLUDE "header.h"
    #include MY_INCLUDE  // 间接自定义包含文件

​7. 关键字(Keywords)​

  • ​严格预定义​​(如 intifclass)不可更改,但可通过宏在预处理阶段替换(不推荐):
    #define INT int  // 危险!仅用于演示
    INT x = 42;      // 替换为 int x = 42;

​总结表​

​类别​​预定义内容​​可自定义/覆盖的部分​
__LINE__, __FILE__#define 定义的宏
标准库名称std::cout, std::endl通过命名空间或局部作用域覆盖
运算符+, ==, <<运算符重载
属性[[nodiscard]]自定义属性(编译器依赖)
字面量123, "hello"用户定义字面量(UDL)
预处理器指令#include, #ifdef通过宏间接自定义
关键字int, class宏替换(不推荐)

​关键区别​

  • ​完全预定义​​:语言强制规定的部分(如关键字、基本运算符语义)。
  • ​部分可自定义​​:标准库名称、运算符重载、字面量等,允许程序员扩展或覆盖,但需遵循一定规则。
  • ​完全自定义​​:用户定义的变量、函数、类等。

这些“介于之间”的内容体现了 C++ 的灵活性,但也需要谨慎使用以避免冲突或未定义行为。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wins_calculator

你的鼓励是我们共同前进的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值