声明语句

概述

声明语句(Declaration statement)是指执行声明操作的程序片段。我们目前遇到的大部分情况下,声明语句在执行声明操作的同时也会执行定义操作,使得声明引入的名字可以使用。

声明语句是语句(Statement)的一种。语句是函数(Function)的组成部分。

声明语句的写法实际上比较复杂。不过我们目前所需掌握的简单的声明语句可以比较容易地写出。简单的变量声明语句由以下几部分组成:

类型说明符 变量名 初始化器;

例如:

int a{42};

你可以和我们上一章学过的写法作比较。下面就 int a{42}; 这个例子来详细解释简单的变量声明语句的组成。

类型说明符

一上来开头的 int 叫做类型说明符(Type specifier),它指示声明变量的类型。我们已经知道了 int 代表变量的类型是整数类型。除此之外还有一些类型和它们的类型说明符目前你稍微了解即可:

  • double 表示一个小数类型,可以存储一个小数如 3.14 5.21
  • char 表示一个字符类型(Character type),它可以存储一个字符。(字符就是一个英文字母之类的东西,比如 'a' 'D' 'h' 等;也可以是一部分符号如 '?' '=' '&' ;甚至还可以是数字 '0' '1' …… '9' 。(数字不是数。))你会注意到表示字符的时候需要用单引号括起来。

其余的类型我们会在本章的后续内容中介绍,因此刚才所述的这两种类型只需简单了解就够了。所以说,当类型说明符为 double 时,就表示目前声明并定义的变量是一个小数类型。

“小数类型”一词是为了便于理解,它的真实名称叫“双精度浮点型”,也就是类型说明符中 double 的含义。

变量名

int a{42}; 这个例子中,a 叫做变量名,我们已经很熟悉了。在这里我们将介绍变量名的命名规则。

大部分情况下,变量名是由英文字母 a...z,A...Z 、数字 0...9 和下划线 _ 组成的文本序列;其中这个序列的第一个字符不能是数字,同时整个变量名不得与关键字相同

变量名是标识符(Identifier)的一种表现。上文所述的规则实际上是标识符的规则。

那么类似 a b c sum average total 等等,都是正确的(指可以使用的,有时也叫作合法的)变量名。包含数字或者下划线的如 x1 a123 zhang_san zhang_3 也是没有问题的。但是 3zhang 是没法用的,因为数字不能出现在第一个字符上。除了数字、英文字母和下划线之外的字符一般不能用于变量名中。比如 test#1 不能用作变量名,因为 # 这个符号不是数字、字母或下划线。同理, $123 Mc.Dowell set-minus 之类的也都包含那些不能用作变量名的字符。除此之外,我不推荐使用下划线开头的命名

不推荐的原因是可能会与标准库具体实现中的命名冲突;这些命名均为双下划线开头或者下划线+大写字母的方式开头。

最后一句“不得与关键字相同”是什么意思呢?关键字指的是在 C++ 程序中有特殊意义的单词。比如我们目前遇到的关键字有:

  • int ,它的含义是声明并定义整数类型;类似的 doublechar 也是关键字;
  • if ,它的含义是引入分支;
  • else ,它的含义是引入分支的“否则”部分;
  • while ,它的含义是引入循环。

正因为这些词有着如上所述的特殊意义,所以不能把它们用作变量名。C++ 至今包括 97 个关键词。为了方便参考,我将它们罗列在下面:

alignasconstinitlongstruct
alignofconst_castmutableswitch
andcontinuenamespacesynchronized
and_eqco_awaitnewtemplate
asmco_returnnoexceptthis
atomic_cancelco_yieldnotthread_local
atomic_commitdecltypenot_eqthrow
atomic_noexceptdefaultnullptrtrue
autodeleteoperatortry
bitanddoortypedef
bitordoubleor_eqtypeid
booldynamic_castprivatetypename
breakelseprotectedunion
caseenumpublicunsigned
catchexplicitreflexprusing
charexportregistervirtual
char8_texternreinterpret_castvoid
char16_tfalserequiresvolatile
char32_tfloatreturnwchar_t
classforshortwhile
complfriendsignedxor
conceptgotosizeofxor_eq
constifstatic
constevalinlinestatic_assert
constexprintstatic_cast

你不用特意地去记住它们。我们常用的只有其中的三十几个,将在本书中慢慢介绍。所有关键字的含义在附录中都会有简单的介绍和使用说明。我在附录介绍了关于变量命名的一些习惯用法。

除此之外还有 6 个叫做保留字的东西。保留字可以被用作变量名,但同时也具有特殊意义。我建议尽量避免变量名与保留字相同。以下是这六个保留字:

  • override
  • final
  • import
  • module
  • transaction_safe
  • transaction_safe_dynamic

初始化器

C++ 中初始化器(Initializer)非常复杂繁琐,但好在我们只需掌握一种(或者两种)就够了。这种初始化器叫做列表初始化器,长成这样:

{初始化值}

用一对大括号围起来,然后里面是初始化值。变量的初始化值的含义是,当这个变量拥有它的存储空间的那一刻,指明这个存储空间应该放什么数据。比如 int a{42};{42} 是初始化器, 42 就是初始化值:意思是当 a 拥有了存储空间之后,就放上 42 这个数。

第二种初始化器——直接初始化器 (参数列表),需要等到面向对象的时候才会接触到。此外,你可能还经常见到 int a = 42; 这种写法,也即形如 = 初始化值 的初始化器。这种写法在目前阶段可以认为和大括号初始化效果一致。

初始化器是可有可无的(正式的说法叫可选的(Optional))。也就是说,可以不写初始化器,这个时候对于变量获得的存储空间则不进行任何操作——因此当没有初始化器的时候,无法知道这个变量的值是多少。比如:

#include <iostream>
using namespace std;
int main() {
    int a;             // 移除初始化器
    cout << a << endl; // 输出是不确定的。比如在某些情况下输出“4201998”
}

因此只在确定这个变量稍后会被赋值的情况下才省去初始化器。稍后会被赋值也包含稍后会允许用户输入到这个变量的情形。

总结

作为例子,以下列举了一些声明语句,它们的含义也用注释写出:

int a{42};             // 声明并定义 a 为整数类型,它的初始化值为 42
double pi{3.14};       // 声明并定义 pi 为小数类型,它的初始化值为 3.14
double sqrt2{1.41421}; // 声明并定义 sqrt2 为小数类型,它的初始化值为 1.41421
char letter{'G'};      // 声明并定义 letter 为字符类型,它的初始化值为字符 'G'。注意单引号的使用
char symbol{'@'};      // 声明并定义 symbol 为字符类型,它的初始化值为字符 '@'

同时,还有一种简化写法:对于相同类型的变量,可以将变量名+初始化器写在同一行,用逗号 , 分隔,共用一个类型说明符。比如刚才的声明语句可以简化为:

// 声明并定义 a 为整数类型,它的初始化值为 42;声明并定义 b 也为整数类型,它的初始化值为 56
int a{42}, b{56};
// 下面两个都是 double 类型
double pi{3.14}, sqrt2{1.41421};
// 下面两个都是 char 类型
char letter{'G'}, symbol{'@'};

以后我们会经常使用这种简化。

这种简化只能用于简单类型。对于复合类型(如指针、数组、函数、引用)来说,这种简化会造成麻烦。

练习

  1. 练习使用声明语句:尝试不同类型、变量名和初始化器。尝试使用同类型声明语句的简化。编译它们来检测是否正确。
  2. 判断以下变量名是否合法: 3D64 lotus_1_2_3 a>b McDowell get3DBuffer @guyutongxue Donald Trump student_name class

练习参考答案

第二题:否(数字开头),是,否(含符号 > ),是,是,否(含符号 @ ),否(含空格),是,否(与关键字相同)。

最近更新:
代码未运行