《编写高质量代码:改善c程序代码的125个建议》——建议2-5:小心使用无符号类型带来的陷阱

简介:

本节书摘来自华章计算机《编写高质量代码:改善c程序代码的125个建议》一书中的第1章,建议2-5,作者:马 伟 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

建议2-5:小心使用无符号类型带来的陷阱

有过面试经历的同学可能曾碰到如代码清单1-6所示的问题。

代码清单1-6 一道典型的面试示例
#include <stdio.h>
int main(void)
{
    int array[] = { 1,2,3,4,5,6 };
    int i = -1;
    if ( i <= sizeof(array))
    {
            printf(" i <= sizeof(array)\n");
    }
    else
    {
            printf(" i > sizeof(array)\n");
    }
    return 0;
}

对代码清单1-6进行初步分析可以得出,sizeof(array)的返回结果为24,而i的值为-1,因此执行语句“if ( i <= sizeof(array))”所返回的结果应该为true,即输出结果为“i <= sizeof(array)”。但实际情况并非如此,其输出结果如图1-6所示。


8ed7bcd0231abedb042fd80fea763585f8af826a

那么,究竟是什么原因导致出现这样的输出结果呢?
其实,要回答这个问题并不难。我们知道sizeof()的返回结果是size_t类型,而size_t类型是一种无符号整数类型。当有符号整数类型和无符号整数类型进行运算时,有符号整数类型会先自动转化成无符号整数类型(请特别注意这一点)。
因此,在代码清单1-6中,当 i 与sizeof(array)进行比较时,即执行语句“if ( i <= sizeof(array))”,i会自动升级为无符号整数类型。又因为i的值为-1,在它转换为无符号整数类型后就变成一个非常大的正整数(如-1在32位机器上存储为0xffffffff,而它被解释为无符号整数时就是232-1,即4294967295),远远大于sizeof(array)的返回结果24。
为了加深读者的理解,我们再来看代码清单1-7所示的这个例子。
代码清单1-7 无符号类型运算示例
#include<stdio.h>
int main(void)
{
    int a = 3;
    unsigned int b = 4;
    printf("%d\n", a - b);
    printf("%u\n", a - b);
    printf("%d\n", (a - b) >> 1);
    return 0;
}

在代码清单1-7中,当执行语句“a-b”时,变量a会自动由int类型转换为unsigned int类型,再与变量b执行减法运算(即“a-b”),“a-b”的运算结果为0xffffffff。当程序使用“%d”(有符号十进制整数)格式输出时,0xffffffff被转换为-1;当程序使用“%u”(无符号十进制整数)格式输出时,0xffffffff被转换为4294967295;最后,程序执行“0xffffffff >>1”运算时,其运算结果为0x7fffffff。当程序使用“%d”(有符号十进制整数)格式输出时,0x7fffffff被转换为2147483647。代码清单1-7的输出结果如图1-7所示。


<a href=https://yqfile.alicdn.com/e372ae0615b323a6331a3f91591d052299565055.png" >

由上面两个例子可以看出,将有符号类型与无符号类型混合使用是很危险的。因此,我们一定要小心这个数据转换陷阱,尽量少在代码中使用无符号类型,以免增加不必要的复杂性。尤其是不要仅仅因为无符号数不存在负值而用它来表示某些数量(如年龄、人口等无负数的值)。建议尽量使用像int这样的类型,这样在设计升级混合类型的复杂细节时,就不必担心边界情况了(比如不用担心-1被翻译为非常大的正整数)。如果必须使用无符号类型,则应该在表达式中使用强制类型转换,使操作数均为有符号类型或者无符号类型,这样就不必由编译器来选择结果的类型,从而避免存在潜在错误的可能性。比如,我们可以通过强制转换将代码清单1-6 改写为代码清单1-8。
代码清单1-8 代码清单1-6的解决方法
#include <stdio.h>
int main(void)
{
    int array[] = { 1,2,3,4,5,6 };
    int i = -1;
    if ( i <= (int)sizeof(array))
    {
            printf(" i <= sizeof(array)\n");
    }
    else
    {
            printf(" i > sizeof(array)\n");
    }
    return 0;
}

在代码清单1-8中,我们将语句“ if ( i <= sizeof(array))”改成“if ( i <= (int)sizeof(array))”,也就是通过强制类型将其转换成int类型,因而程序的输出结果为i <= sizeof(array)。

相关文章
|
分布式计算 监控 网络协议
Hadoop集群长时间运行网络延迟原因
【6月更文挑战第20天】
380 2
|
7月前
|
Ubuntu
在Ubuntu 20.04 x64系统中增加中文支持
将 Ubuntu 系统语言设置为中文: 1. 更新系统语言包: `sudo apt update` 和 `sudo apt install language-pack-zh-hans`。 2. 修改区域设置:编辑 `/etc/default/locale` 文件,设置 `LANG=zh_CN.UTF-8` 和 `LANGUAGE=zh_CN:zh`。 3. 生成中文 locale: `sudo locale-gen zh_CN.UTF-8` 和 `sudo update-locale`。 4. 重启系统: `sudo reboot`。 5. 验证设置: `locale` 命令检查是否生效。
466 1
|
7月前
|
Windows
Windows硬盘扩容
如果云服务器扩容硬盘或新加盘未生效,可按以下步骤操作: 1. 新加硬盘:右键硬盘选择“联机”。 2. 扩容硬盘:进入“计算机管理”&gt;“磁盘管理”,右键要扩展的分区,点击“扩展卷”。 3. 增加分区:右键未分配空间,选择“新建卷”。 通过这些步骤可确保硬盘变更生效。
221 0
|
10月前
|
SQL 分布式计算 DataWorks
DataWorks智能交互式数据开发与分析之旅
本次实验将带您进行DataWorks Notebook的快速入门,包含:Notebook新建、多引擎SQL开发与分析、Python开发、交互式分析等,同时,使用DataWorks Copilot体验智能数据开发,体验智能交互式数据探索之旅。
2880 11
|
11月前
|
安全
HTTP 协议的请求方法
【10月更文挑战第21天】
|
11月前
|
JSON 缓存 API
随机天文图[NASA官方]免费API接口教程
此接口用于随机获取NASA官方发布的宇宙图像,支持POST或GET请求。需提供用户ID、用户KEY、返回格式(JSON/TXT)和图像质量(高清/普清)。返回状态码及图片地址或错误信息。示例ID与KEY有调用限制,建议使用个人ID与KEY。
|
缓存 资源调度 Kubernetes
阿里云云效产品使用合集之如何将两个独立的代码仓库构建并部署到同一个容器内
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
机器学习/深度学习 分布式计算 大数据
大数据迷局:如何用PyODPS破解回归分析之门?
【8月更文挑战第20天】随着大数据技术的发展,回归分析在处理海量数据时愈发重要。PyODPS是阿里云MaxCompute上的Python库,支持高效的数据处理。本文通过示例展示如何使用PyODPS进行回归分析:从安装库、连接MaxCompute、读取销售数据,到数据预处理、构建线性回归模型、预测销售额及评估模型性能(如计算RMSE)。这一流程体现了PyODPS在大数据环境下的强大功能。
180 0
|
存储 运维 Kubernetes
在k8S中,生产环境的pv回收策略该如何选择?
在k8S中,生产环境的pv回收策略该如何选择?
|
自然语言处理 Python
Python实现词频统计
Python实现词频统计