M' Blog

人生天地间,忽如远行客

C++ 变量声明中 const 的用法

一直以来对 C++ 中的 const 说明符理解不够清晰,尤其是在变量声明时处于何种位置起到何种作用,分辨不清。

现在花费一些时间专门理清其中的关系,明白其中的道理之后,就再也不会混淆了。文中内容主要参考了这篇译文

1. 几个概念

static unsigned long int *x[N]; 为例,说明几个概念

  • 声明符:一个声明符就是被声明的名称,可能伴有操作符和标识符,这里为 *x[N]
  • 操作符:如 *, [], (), 和(C++中的) &. 正如你所知的,声明中的符号 * 表示“指针”,[] 表示 “序列”;
  • 标识符:一个声明符可能包含不止一个标识符。声明符 *x[N] 包含两个标识符,xN。只有其中一个标识符是被声明的,而且被称为是声明符ID,其余的必须在这之前就被声明过。举例,*x[N] 中的声明符ID是 x
  • 说明符:可以包括类型说明符,如 int, unsigned ,他们也可以是存储类说明符,如 externstatic。在C++中,他们也可以是函数说明符,如 inlinevirtualconstvolat 关键词都是类型说明符。

现在可以说,变量声明语句 static unsigned long int *x[N]; 是由声明符和说明符来组成的。其中声明符由操作符和标识符组成,说明符可以同时含有类型说明符、存储类说明符等。

2. 解析顺序

所谓的解析顺序,我理解分为两个部分,声明符说明了是一个什么东西,说明符给出了这个东西的一些性质。对声明符来说,解析顺序决定了这个东西属于什么大类,什么小类,说明符不区分顺序,给出了这个东西在不同方面的属性。

2.1 操作符解析顺序

可以按照这个规则来决定解析顺序:离标识符ID越近,越决定了目标先是什么,距离相等情况下操作符优先级越高越先解析。

举例来说,*x[N]*[] 离标识符ID x 的距离相等,按照 C++ 符号优先级图表进行解析, [] 的优先级比 * 更高,因此声明符 *x[N] 表明 x 是一个优先于指针的序列,也就是说,它首先是一个序列,其次序列中的每个元素是一个指针。如果想要变换解析顺序,可以应用 () 来提高解析级别,例如 (*x)[N] 表示为一个指向序列为 N 的指针。

2.2 说明符解析顺序

声明说明符在一个声明中出现的顺序并不重要。比如 const unsigned static intstatic unsigned int constint const unsigned staticconst int static unsigned,只不过通常大家有一套默认的书写顺序。

2.3 constvolatile

能出现在声明符中的声明说明符只有 constvolatile。当出现在声明符中时,可以认为其修饰的对象变成了操作符,并且不能交换 constvolatile 在声明中的顺序(不能交换constvolatile与操作符*的顺序)。例如 int const *aa 声明为指向 const int 的指针,而 int *const aa 声明为指向 int 的 const 指针。

2.4 最终的解析顺序

参考文章中总结到:

C++基本上是按从头到尾、从左到右的顺序来读,但是指针的声明,从某种意义来讲却是倒着的。指针的声明是从右到左来看。把 const 放在其他类型说明符的右边,可以严格的从右到左来看指针声明,还可以把 const 从“右边的”位置提出来,如:
T const *p;
p 声明为“指向 const T 的指针”,非常准确,同样:
T *const p;
p 声明为“指向 T 的 const 指针”,也能正确的理解。

按照我自己的理解,可以按照先确定是什么东西(声明符),再看这个东西的性质(说明符)顺序来确定。

以上面例子来说,T const *p 先确定是一个指针,再看这个指针是关于 const T 类型的,也就是“指向 const T 的指针”;T *const p 先确定时一个 const 指针,再看这个 const 指针是关于 T 类型的,也就是“指向 T 的 const 指针”。

3. 声明风格

  • 当把变量声明语句分成说明符和声明符两大部分之后,可能比较好理解文中给出的陈述:

const int* p;
而不是
const int *p;

  • 依照参考文章中对声明顺序的理解,给出的另一个建议:

const void *vectorTable[] (3)
void const *vectorTable[] (4)
大多数C和C++程序员更喜欢把const和volatile写在其他类型的说明符的左边,同(3)。而我更喜欢把const和volatile写在右边,如(4),而且强烈推荐这样写。

参考链接

[1] const T vs. T const ——Dan Saks 【翻译】