同上节课,请参考运算符总览
本节主要讲讲sizeof
也许有的资料提到过C++的typeid,但是这个根本不是运算符,而是一个类,有文件定义的
所谓运算符必须是无需头文件即可使用的符号。如果要使用一个运算符,还需要头文件,那么这个运算符就不是基本的运算符,是开发人员重载或者自己写的。
从这个角度看typeid就不是运算符,而是微软自定义的。
运算符的另一个特点是,对常量进行操作,编译阶段就会进行处理。
比如 int a = sizeof(int) ;
编译器会在编译的时候直接将4用来初始化a。所以你不能指望a的值是动态的:在16位系统它是2,32位系统它是4 。
相反的,它是固定的,具体的取值决定于编译器:16位的编译器会给2,32位的编译器会给4 。
请注意:64位的编译器不会给8,仍然是给4——因为大部分程序员认为整数就是4字节,为了遵从这个标准,后面的编译器都认为int就是4字节,不再扩展int的长度了
我们在使用sizeof的时候会跟一个括号,但是这个括号不是必须的,只是用来规范优先级!
上面的示例也可以写成这样:
int a = sizeof
int ;
结果仍然不变。但是复杂一点的情况就比较麻烦了:
int b = sizeof a * 4 ;
尽管我们知道sizeof的优先级比乘法高,但是这样写让代码无法一目了然,容易产生歧义。
int b = sizeof(a) * 4 ;
这样写就没有任何歧义了,看上去也一目了然。
当然这里会因为编译器而产生一个陷阱,其实b的值不一定是16,也可能是8 。
所以很多时候,这个运算符被用来进行内存操作:
int a[16]; memset(a,0,sizeof(int)*16); memset(a,0,sizeof(a)); memset(a,0,4*16);
第2行和第3行代码效果是一样的,就是将整数数组a的每个元素初始化为0
这样写不论是16位编译器还是32位编译器,效果都是一样,不会产生歧义,不会造成访问越界。
而第4行就是是错误示例:开发者天真的以为int就一定是4字节。
一旦代码移植到诸如window ce或者其他可能存在16位编译器的环境,那结果就不敢去想——这种没有语法错误、没有明显逻辑错误、仅在某些环境下运行才能发现的错误是最可怕的。比这个更可怕的是这样的:
<pre name="code" class="cpp">int b,c,d,e;
int a[4];b=1,c=2,d=3,e=4;
memset(a,0,4*4);
执行完第4行之后,b、c、d、e可能被设置为0,而不是你想象中的1,2,3,4 。
要命的是这种错误没有任何征兆!!!
没有语法错误!没有编译错误!运行不会产生溢出!仅仅只有逻辑错误!
如果你本身就是要将b,c,d,e初始化为0,那就更可怕了,因为逻辑错误也不会有了。
但这是一颗潜伏的很好的炸弹,等到某天需求变更,a的长度由4变成5的时候,就会duang的一下爆发出来。
接手的人肯定还会奇怪,代码一直好好的,怎么长度变了一下就这鸟样了?
也许你会说,如果需求不变更就没有问题。
但是作为一个工作多年的程序员,我要和你说的是:
需求当中唯一不变的就是——需求一定会被改变!
今天到此为止,下次再见!