声明符:
这是第一个观点:
C和C++的每一个声明都有两个主要的部分:一串0个或多个声明修饰符+一串0个或多个声明符(多个申明符用逗号分开)例如:
Static unsigned long int *x[N];
(Declarationg specifier )(declarator)
声明符就是要声明的名字,经常与像*,[],()和&((在C++中)组合在一起。在声明符中这个符号*意味着“指向”,[]意思是“数组”。因此,*x[N]是一个声明符说明x是一个有N个指针元素组成的数组,类型是在类型修饰符中指定的类型。例如,
Static unsigned long int *x[N];
将x声明为这种类型的对象:“有N个指向无符号长整型元素组成的数组。“
我怎么知道*x[N]是一个指针数组而不是指向数组的指针呢?
它遵循这个原则:在声明符组中操作符的优先级与他们在表达式中的一致。
例如:[]比*的优先级高。因此,在这个声明符中*x[N]意味着x 首先是一个数组,然后才是它的元素是一个指针。
圆括号:();在声明符中有两个作用:
一是作为函数调用操作符;
二是分组。
作为函数调用操作符时,()与[]的优先级相同,分组时()拥有最高的优先级。
例如,*f(int)是一个声明符,指定f是一个返回指针类型的函数。而(*f)(int)指定f是指向一个函数的函数指针。
声明符可能包含不止一个标识符。这个声明符*x[N]包含两个标识符,x和N。
只有一个标识符是被声明的,被称为声明ID。其他的,如果还有的话,必须似乎在之前声明的了。例如在这个声明符中x是声明ID。
声明限定符
一些声明限定符可以是类型限定符诸如int,unsigned或者是一个新类型的标识符。他们也可以使存储类限定符像extern或者static。在C++中他们也可以是函数限定符像inline或者virtual。
下面是另一个观点:
类型限定符作用于声明符ID的类型,其他的限定符提供非类型信息,这些信息直接作用于声明ID。
例如:static unsigned long int *x[N];
声明x为一个变量类型:“由N个指向无符号长整型的指针组成的数组。“ ;关键字static限定x为静态分配的内存。
下面是另一个重要的观点:
声明限定符在声明中的顺序是无关紧要的。例如:
Const VP vectorTable[]
等价于
VP const vetorTable[]
const void* vetorTable[]
等价于
void const* vetorTable[]
我们大多数人将诸如static这样的存储类限定符(最左边)作为第一个声明限定符,但是这只是一个惯例,不是语言本身的要求。
声明限定符const和volatile是不同的:唯一的声明限定符也能出现在声明符中的是const和volatile。
例如:在void*const vectorTable[]中的const出现在了声明符中。
在这中情况下,你就不能重新组织关键字的顺序,例如:*const void vetorTable[]是错误的。
对于编译器来说声明限定符的顺序是无关紧要的。于是这两种声明是等价的:
const void *vetorTable[];
和
void const *vectorTable[];
几乎所有的C和C++编程者都倾向于将const和volatile写在类型限定符的左边。我更喜欢将他们写在右边,并且我强烈推荐写在后边的这种写法。
尽管一般C和C++是从左到右, 从上到下读的,读指针声明的时候,在某种意义上说,是相反的。也就是说,指针声明是从右到左读的。
通过将const置于其他类型限定符的右边,你可以严格的从右到左读指针声明,并且将const出现在右边的位置。
例如:
T const *p;
<------------
将p声明为指向cons T 的指针;
并且:
T *const p;
<------------
将p声明为指向T的const指针。
将const写在其他声明限定符之后实际上使得更加容易看到const和typedef结合的效果。
Typedef void* VP;
Const VP vectorTable[];
一种转化是象下面这样置换VP:
Const (VP )vectorTable[]
Const(void*)vetorTable[]
使得它看起来vectorTable具有这种类型“指向const void 的指针数组“,这是错误的,
正确的转换是将VP置换为:
const (VP) vectorTable[]
(void *)const vectorTable[]
也就是说,vectorTablel是指向void的const指针数组,但是它却不是显然的。
将const写在声明限定符的最右边使得更容易看到正确的翻译,
(VP) const vectorTable[];
(void *)const vectorTable[];
现在我意识到我正在推荐一种其他人很少用的风格,其他人都会将const放在左边;
但是,鉴于很少有C和C++的程序员知道在声明中使用const时自己在做什么,每个人都不这样做是支持现在流行风格。为什么不抵制这种趋势。尝试着使用一种更加清晰的风格呢?
只要我还从事着这个职业,我就会一如既往的支持这种风格。尽管这对大多数程序员还没有任何影响,但是很多人还是养成了书写的坏习惯。
Const int *p;(更加规范化)
而不是
Constint* p;
也就是说,他们将空格和*作为声明限定符而不是声明符,我真的相信程序员这样书写给他们自己和其他人造成麻烦。
当然,空格对编译器毫无影响,但是将空格置于*之后会给人关于声明的内在结构造成一种错误的印象。
---------------------------------------------------------------------------------------------------------
const的作用
const是C语言的一种关键字,起受保护,防止以外的变动的作用!可以修饰变量,参数,返回值, 函数体。
const可以提高程序的健壮性,你只管用到你想用的任何地方。
1、如果输入参数是指针型的,用const修饰可以防止指针被意外修改。
2、如果参数采用值传递的方式,无需const,因为函数自动产生临时变量复制该参数。
3、非内部数据类型的参数,需要临时对象复制参数,而临时对象的构造,析构,复制较为费时,因此建议采用前加const的引用方式传递非内部数据类型。而内部数据类型无需引用传递。
1、函数返回const指针,表示该指针不能被改动,只能把该指针赋给const修饰的同类型指针变量。
2、函数返回值为值传递,函数会把返回值赋给外部临时变量,用const无意义!不管是内部还是非内部数据类型。
3、函数采用引用方式返回的场合不多,只出现在类的赋值函数中,目的是为了实现链式表达。
class stack
{
public:
int GetCount(void) const ;
private:
int m_num;
};
int stack::GetCount(void) const
{
m_num++;
}
编译器输出错误信息:error C2166: l-value specifies const object。
1、const char *p 表示 指向的内容不能改变
2、char * const p,就是将P声明为常指针,它的地址不能改变,是固定的,但是它的内容可以改变。
3、这种const指针是前两种的结合,使得指向的内容和地址都不能发生变化.
const double pi = 3.14159;
const double *const pi_ptr = π