C 语言中关于无符号整数的一些问题

身为一名程序员,或多或少都会了解一点 C 语言,我现在还清楚地记得,大一刚接触 C 语言时被它所支配的恐惧。C 语言无比强大,被称为「高级汇编语言」足以见得它的威力,也可以看出它经常与计算机底层打交道;它的指针部分更为精彩(也是最难的部分),那么我们就跳过它最难的部分,检查一下你对 C 语言掌握的程度。

 

下面是一个函数 sum_elements( ),它的作用是对给定的数组中所有元素求和并返回其值,按照代码中给定的值去执行,你认为会得到什么结果呢?

 

#include<stdio.h>

float sum_elements(float a[], unsigned length) {
    int i;
    float result;

    result = 0;
    for (i = 0; i <= length - 1; i++)
        result += a[i];

    return result;
}

void main()
{
    float a[1] = { 0.1 };
    float sum;

    sum = sum_elements(a, 0);
    printf("%f\n", sum);
}

 

 

当我们让 length = 0 时,想要得到的结果是 0.000000,但是运行时你会发现该程序会报出内存访问异常错误。你知道是什么原因出现这个错误吗?这就是检验你功底是否扎实的时候了,先仔细看看代码,好好想一想再继续往下看。

 

... ...

 

怎么样,知道是什么原因导致这段代码出现了我们预料之外的错误了吗?这里的 bug 是无符号整数(unsigned)导致的。

 

在 C 语言中,无符号整数是 4 个字节,1 个字节为 8 位,十进制数 0 用二进制表示为 0000 0000 0000 0000 0000 0000 0000 0000,计算机做减法是通过补码进行,补码为源码除符号位外各位取反再加一。-1 的补码为 1111 1111 1111 1111 1111 1111 1111 1111,计算 length - 1 (0 - 1) 就是求 length 与 -1 的补码之和,得到的结果为 1111 1111 1111 1111 1111 1111 1111 1111,因为之前定义形参的时候将 length 定义为无符号整数,所以 C 语言将计算结果按照无符号整数解释,得到的十进制数字为 4294967295(2^32 - 1)而不是我们想要的 -1,循环时 i 初值被赋为 0 ,一直小于这个数,所以循环会不断地进行,代码将试图访问数组 a 的非法元素,导致内存访问异常。

 

这个程序表面上一切正常,很符合正常人思路,数组下标不能为负数,因此形参 length 用无符号整数表示;停止条件 i <= length - 1 看上去也十分自然。但是将这两个条件组合在一起,意料之外的事情就发生了。C 语言确实很强大,但是如果我们的计算机基础知识不扎实,很可能出现各种奇奇怪怪的 bug。原来我一直觉得学那些枯燥无味的计算机基础知识没用,但是越往前走越发觉计算机基础知识很重要。书到用时方恨少,出了 bug 找不到

 

现在这个 bug 的原因已经找到了,如何修改这个 bug 使得该程序能够顺利执行呢?一种方法是修改循环条件,改成 i < length  ;另一种方法是将形参 length 定义为 int 类型。

 

 

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值