P5.C语言学习-数据的类型与存储

1. 低位截断与整形提升

例如,unsigned char x=-1;这条语句,-1补码的16进制格式为FF FF FF FF。将其存入大小只有一个字节的无符号字符型变量x中,发生低位截断,只保留低8位数据FF,而在无符号数中,FF只表示大小,大小为255,而以%d的格式打印的时候,x的位数不够,需要进行整型提升。使其变为无符号整型的格式然后打印。y同理,但由于y是有符号字符型类型,所以整形提升时会提升为有符号整形,即高位不断补符号位。

注意:整型提升并不是按照输出格式进行的!!! 

整型提升的规则如下:

  1. 如果操作数是有符号的整数类型(signed charshortint),则它将被提升为有符号的int类型。

  2. 如果操作数是无符号的整数类型(unsigned charunsigned shortunsigned int),则它将被提升为无符号的int类型。

  3. 如果操作数是浮点类型(floatdoublelong double),则它将被提升为double类型。

  4. 如果操作数是char类型(有符号或无符号),在大多数情况下,它被提升为有符号的int类型。但是,如果char类型被定义为unsigned char,则它将被提升为无符号的int类型。

另外,当十进制整数以字符或字符串的形式存储时,其大小不是按照数字大小,而是与其它字符一样,存储的不是字符,本质上存储的是ASCII码值,例如下图:

 此时进行整形提升(或运算)是按照ASCII码值对应的数字进行的。

2. 经典案例解析:编译器下的输出结果

VS编译器x86,Debug版本下运行下面的程序会出现什么问题?运行结果是什么?为什么?

 容易知道,该程序在给数组a[ ]赋值的过程中发生了越界,访问并且修改了未分配的空间,因此会报错,但结果真的是这样简单吗?我们不妨运行看看

 我们看到,程序死循环了。

仔细分析,我们看到:数组a越界的部分:a[16]、a[17]都正常的赋值了,按道理说i++后i为18,继续为a[18]赋值,可我们发现此时i却变成了0,这说明i被异常的更改了,并且每次i循环到18的时候都会被更改为0。那么i是怎么被更改的呢?难道是有什么触发条件?但是越界的16、17为什么正常呢?

当我们调试查看内存中可能产生问题的a[18]和i的地址时,我们发现,它们的地址是一样的相同的。因此我们就找到了死循环的原因,a[18]就对应a指针向后移动18个空间(数组a的类型的空间)后地址所对应的元素,也就是i,因此更改a[18]就是更改i,i就被赋值为0了。

我们知道,数组遍历是从低地址到高地址的,我们明明先创建的i变量,为什么后创建的数组往后遍历会访问到i呢?这说明先创建的变量i的地址高于后创建的数组a[ ]的地址

 从下图截取的内存区域分布的部分来看,我们直接创建的临时变量放在栈区。可以看到,栈区与堆区空间延申的方向是相反的(这是一种共享栈结构,两侧为栈底),i从栈区的栈底侧创建(栈底地址较高),后面创建的变量不断向下创建,因此地址更低,即变量的创建是从高地址向低地址创建的。

然而,VS提供了另外一个release版本下,我们会发现代码不会发生死循环,当调试查看i变量与数组a[]的地址时,我们发现i地址更低,也就是说变量的创建是从低地址向高地址创建的。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值