**************const有关的变量声明***************** (1)const == read-only const修饰的变量被许多人错误的认为是常量,但是const所修饰的变量应该是只读变量 检验这个结论可以用下面这个方法:
这段代码会产生一个编译时的错误,switch的i必须用常量或常量表达式,这里在用two 代替的时候出现error,很明显,two并不是常量,它是一个只读变量,实质还是变量。 (有人提到这段代码在微软的vc6.0和vs2010下能编译通过并且正确运行,一开始我是这么认为的: 这个其实和编译器对代码的处理有关,因为在gcc下这段代码会提示如下问题: error:case label does not reduce to an integer constant warning:variable [two] set but not used 后来在众多牛人的解释之下,我才发现,原来这不是编译器的问题,而只是const在C和C++中意义不一样 C++中将const定义为了常量。 ) (2)const修饰指针 看这四个声明:
到底const的修饰对指针i起只读作用,还是对i所指向的int值起只读作用呢? 这里有一种直观的做法来认清它的真面目: intconst *i; constint*i;int* const i;constint* const i; 结果是不是一目了然?将数据类型直接划掉即可 最后一个声明保证了指针i和i指向的对象都为只读变量。 const最有用之处就是用它来限定函数的形参,比如strcpy函数的原型。 **************typedef与define的区别***************** (1)整个结构体的定义提倡这样定义: 这种定义方式才易于阅读,虽然多写了一点代码(2)纠结的结构标签和结构类型 我们如果用sizeof(foo)的话,编译器是不是肯定会报错的?这当时肯定是的。第一个定义中,声明了结构标签foo(第一个)和有typedef声明的结构类型foo(第二个)。 使用结构标签的foo效果:struct foo value 使用结构类型的foo效果:foo value 第二个定义中,声明了结构标签foo和变量foo 只有结构标签能够在以后的声明中使用:struct foo value 这就是利用typedef来定义类型的新名字带来的头疼之事,所以建议 不要用typedef来做这种复杂的事,下面来看看它与define的区别 (3)typedef与define typedef等价于一种彻底的“封装”:声明之后不能再次增加其他内容 区别一: 对宏类型名我们可以用其它类型说明符对其进行扩展,但对typedef所定义的类型名却不能。所以第一个定义是对的,但第二个定义会报错 区别二: 第一个利用宏定义定义a,b变量之后,经过宏扩展a的类型是int *,b的类型却还是int第二个typedef之后的a,b变量的类型都是int *,这就是两者的第二个区别 最后提醒一点,这两个东西不可以相互嵌套。。。。 (今天刚写个二叉树的程序,想用非递归实现,需要用到栈,结果把栈的宏定义内容改为 二叉树的typedef定义的结构类型就发生ERROR,弄了好久才解决) 1、数组、结构、指针已经函数的组合类型 2、可移植类型(将数据类型改一下就可以轻松适应不同的平台了) 3、也可以用在强制类型转换时提供一个简单的名字 **************各种括号组成的复杂声明***************** 先来头脑风暴一下: 大概看到的人都有一点昏迷了。。。。下面给出读懂复杂的函数声明的要诀: 最重要的是弄懂各种操作符的优先级,其次先通过最后一对操作符来判断是函数还是数组 在函数的高级声明中,主要用到()、[]和*操作符,只需记住()[]->.四个操作符的优先级最高即可 以第三个为例,来分析一下高级声明该怎么理解: 1、有三对圆括号,最后一对是方括号,说明是一个指向数组的指针吧,数组长度为6; 2、(这里有重大修改,先前写的是从最里层开始分析)先从最外层开始分析,int *(A)[6],我们 可以确定是一个A是一个指向数据为int *型数组的指针,数组长度为6,再分析A 3、A为(*(*abc)()),从里层的两个圆括号看,其中一个圆括号为空,说明肯定是一个函数,也就是 说整个的最外层int *()[6]肯定是一个函数的返回值了,在看(*abc)这是一个abc指向的函数指针,返 回值是什么?通过两个并排的原括号前面的*决定,这里(*abc)之所以没有先于*一起结合看而先于() 一起结合看作一个函数,是因为*的优先级没()高 4、*决定了里层的函数指针的返回值,它的内容当然就是外层的那些个东东,即是:指向int型数组 的一个指针 5、先在加上对里层的分析,结论就是: 返回值为“指向int型数组的指针”的函数指针 整个的顺序是简化出来是这样: int *( )[6]---->确定这是一个指向int型数组的指针 int *( (*abc) )[6]---->abc肯定是一个指针了,具体还无法判断 int *( (*abc)())[6]---->这下可以确定另一个东西了,abc是一个指针函数,函数总得有返回值吧,继续 int *(*(*abc)())[6]---->返回值出来了,通过第二个*确定的,它表明返回的是外面那个*所指向的内容 整个过程总结为: A、先取最外层的,抽出里层内容,对里层的从它的名字开始读取,按照优先级顺序依次读取 B、优先级顺序: 1、声明中被圆括号括起来的部分 2、后缀操作符:()函数、[]数组 3、前缀操作符:*指向什么的指针 C、如果还有const、volatile关键字在类型说明符前面说明它作用于类型说明符,如前面讲的const的 修饰作用,其他情况他俩一般作用于它左边紧挨的*操作符 很明显,如果用typedef来为这些个圆括号重新命名的话,再复杂的函数声明你剖析的时候都会游刃有余的 (由于昨天刚开始写这个声明的分析时头脑还没怎么理顺这个思路,造成解说的很混乱,今天重新对 此进行整理,如果有错,请大家友情指出。) |
|