程序员面试系列——有符号数的溢出

请看这样一道题:

#include <string.h>
#include <stdio.h>

int main(void)
{
    signed char a[1000]={0};
    for(int i=0; i<1000; ++i)
        a[i] = -1 - i;

    printf("%lu\n",strlen(a));
    return 0;
}

请问此程序输出什么?

答案是:255

如果你不信的话,可以亲测。我在ubuntu 64位机上用gcc编译:

gcc -std=c99 test.c

结果是

255

下面我们来分析一下,为什么是这个结果。
人工计算一下,
a[0] = -1
a[1] = -2
a[2] = -3
a[3] = -4

a[127] = -128

一般来说,有符号数在机器中以补码表示。所以,signed char类型可以表示的范围是-128+127

a[128] 本应该是-129,但是-129超出范围了!

那a[128]到底是多少呢?

我认为,-129可以理解为-128减去1,进一步理解为-128(补码表示为1000 0000)加上-1(补码表示为1111 1111),我们可以用二进制计算一下。

这里写图片描述

如上图所示,因为位宽只有8位,所以进位被丢弃,结果就是0111 1111,写成十进制就是127. 于是,我们可以继续往下算,

a[0] = -1
a[1] = -2
a[2] = -3
a[3] = -4

a[127] = -128
a[128] = 127
a[129] = 126
a[130] = 125

a[253] = 2
a[254] = 1
a[255] = 0
a[256] = -1

可以观察出,a[0]的值为-1,后面的值依次在前一个值的基础上减1,当a[127]的值为-128的时候,再减去1就成了127.

也就是说,signed char类型可以表示的范围是-128+127。在最小值-128的基础上减1,就会向下溢出,回到最大值+127。反之,在+127的基础上加1,就会向上溢出,回到最小值-128

用数轴来表示就是数轴的最右端(+127)和最左端-128连在一起了,构成了一个回路。

这里写图片描述

好的,我们回到正题,按照上面的分析,a[0]~a[254]的值都不为0,而a[255]的值为0,strlen函数是计算字符串长度的,注意,不包括字符串最后的\0(其ASCII码的值为0),所以答案就是255.


【参考资料】
[1] C语言深度解剖(第二版)(北京航空航天大学出版社)P13
[2] 深入理解计算机系统 (机械工业出版社)

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值