zerglurker的C语言教程010——运算符详解(三)

同上节课,请参考运算符总览

本节主要讲讲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的一下爆发出来。

接手的人肯定还会奇怪,代码一直好好的,怎么长度变了一下就这鸟样了?

也许你会说,如果需求不变更就没有问题。

但是作为一个工作多年的程序员,我要和你说的是:

需求当中唯一不变的就是——需求一定会被改变!

今天到此为止,下次再见!

时间: 2024-10-19 10:43:43

zerglurker的C语言教程010——运算符详解(三)的相关文章

zerglurker的C语言教程010——运算符详解(二)

首先,请参考上节课我们提到的运算符总览 今天我们主要讲解下面几个运算符: ()圆括弧运算符 {}组合运算符 ::作用域解析 throw运算符 ,逗号运算符 ()圆括弧运算符 使用示例: a*(b+c) (b>=a)&&(c<=a) (a%(b/c))*d 特点说明: 1 圆括弧拥有优先执行权限.即运算表达式时,优先运算圆括弧内的表达. 2 圆括弧可以嵌套,嵌套时内部的圆括弧拥有更高的优先级. 注意: 由于()作为圆括弧运算符的时候,里面的表达式不可以为空,也不可以有多个语句,所

zerglurker的C语言教程009——运算符详解(一)

在之前几节我们讲过数据类型.讲过函数.讲过代码执行顺序以及一些添加简单函数的方法. 这一节我们将着重讲讲运算符.包括运算符的含义以及优先级的概念 在C语言中,以下运算符是被公认的: C/C++语言运算符详解 优先级 运算符 名称以及含义 运算目 使用示例 结合方向 可否重载 附加说明 无 () 圆括弧 单目 (表达式) 无 否 括弧内的表达永远先计算 无 dynamic_cast<>() 类型动态转化 单目 dynamic_cast<目标类型>(源) 无 否 C++专有,不能转换返

Linux下Bash编程之算术运算符详解(三)

shell算术运算表示如下: 1.let 算术运算表达式 let C=$A+$B 2.$[算术运算表达式] C=$[$A+$B] 3.$((算术运算表达式)) C=$(($A+$B)) 4.expr 各操作数及运算符之间要有空格,且要使用命令引用 C=`expr $A + $B` 举例说明: 1.指定一个用户,判断用户密码剩余使用期限是否已经小于警告期限: 如果小于警告期限,则显示"Password will expire --> Warning":否则,就显示"OK&

Swift基本运算符详解

运算符是检查,改变,合并值的特殊符号或短语.例如,加号+将两个数相加(如let i = 1 + 2).复杂些的运行算例如逻辑与运算符&&(如if enteredDoorCode && passedRetinaScan),又或让 i 值加1的便捷运算符自增运算符++i等. Swift 支持大部分标准 C 语言的运算符,且改进许多特性来减少常规编码错误.如,赋值符(=)不返回值,以防止把想要判断相等运算符(==)的地方写成赋值符导致的错误.数值运算符(+,-,*,/,%等)会检

Java的位运算符详解实例

Java的位运算符详解实例——与(&).非(~).或(|).异或(^).右移(>>).左移(<<).无符号右移(>>>) 位运算符主要针对二进制, 它包括了:“与”.“非”.“或”.“异或”."右移"."左移"."无符号右移". 从表面上看似乎有点像逻辑运算符, 但逻辑运算符是针对两个关系运算符来进行逻辑运算, 而位运算符主要针对两个二进制数的位进行逻辑运算. 下面详细介绍每个位运算符. 1.与运

java移位运算符详解[转]

java移位运算符不外乎就这三种:<<(左移).>>(带符号右移)和>>>(无符号右移). 1. 左移运算符 左移运算符<<使指定值的所有位都左移规定的次数. 1)它的通用格式如下所示: value << num num 指定要移位值value 移动的位数. 左移的规则只记住一点:丢弃最高位,0补最低位 如果移动的位数超过了该类型的最大位数,那么编译器会对移动的位数取模.如对int型移动33位,实际上只移动了332=1位. 2)运算规则 按

java移位运算符详解

java移位运算符不外乎就这三种:<<(左移).>>(带符号右移)和>>>(无符号右移).1.左移运算符左移运算符<<使指定值的所有位都左移规定的次数.1)它的通用格式如下所示:value << numnum 指定要移位值value 移动的位数.左移的规则只记住一点:丢弃最高位,0补最低位如果移动的位数超过了该类型的最大位数,那么编译器会对移动的位数取模.如对int型移动33位,实际上只移动了332=1位. 2)运算规则按二进制形式把所有的

Linux下nginx编译安装教程和编译参数详解

这篇文章主要介绍了Linux下nginx编译安装教程和编译参数详解,需要的朋友可以参考下 一.必要软件准备1.安装pcre 为了支持rewrite功能,我们需要安装pcre 复制代码代码如下: # yum install pcre* //如过你已经装了,请跳过这一步 2.安装openssl 需要ssl的支持,如果不需要ssl支持,请跳过这一步 复制代码代码如下: # yum install openssl* 3.gzip 类库安装 复制代码代码如下: yum install zlib zlib-

Android基础入门教程——8.3.6 Paint API之—— Xfermode与PorterDuff详解(三)

Android基础入门教程--8.3.6 Paint API之-- Xfermode与PorterDuff详解(三) 标签(空格分隔): Android基础入门教程 本节引言: 上一节,我们学习了Xfermode中的三儿子:PorterDuffXfermode构造方法中的为一个参数: PorterDuff.Mode,我们在观看了16种图片混排模式后,又自己写代码来验证了一下文档中 18种不同的混排模式,18种是新增了ADD和OVERLAY两种模式!当然,仅仅验证知道是不够的, 本节我们来写个例子