c - C是整数数学等价于无符号数学?
问题描述
那么我可以将这些值转换为无符号值,进行操作并转换回来,并得到相同的结果吗?我想这样做是因为无符号整数可能溢出,而有符号整数不能。
解决方案
无符号整数算术在 C 术语中不会溢出,因为它被定义为对模 2 N进行包装,其中N是根据 C 2018 6.2.5 9 操作的无符号类型中的位数:
... 涉及无符号操作数的计算永远不会溢出,因为无法由结果无符号整数类型表示的结果会以比结果类型可以表示的最大值大一的数字为模减少。
对于其他类型,如果发生溢出,则行为未由 C 标准定义,每 6.5 5:
如果在计算表达式期间出现异常情况(即,如果结果未在数学上定义或不在其类型的可表示值范围内),则行为未定义。请注意,不仅结果是未定义的;程序的整个行为是未定义的。它可能会给出您不期望的结果,它可能会陷入陷阱,或者它可能会执行与您期望的完全不同的代码。
关于你的问题:
那么我可以将这些值转换为无符号值,执行操作并返回,并获得相同的结果吗?
我们有两个问题。首先,考虑a + b
给定int a, b;
。如果a + b
溢出,则行为未由 C 标准定义。所以我们不能说转换为unsigned
、添加和转换回是否int
会产生相同的结果,因为一开始没有定义的结果a + b
。
其次,根据 C 6.3.1.3,转换回部分是实现定义的。考虑int c = (unsigned) a + (unsigned) b;
,它将unsigned
总和隐式转换为 anint
以存储在c
. 第 1 段告诉我们,如果 sum 的值可以表示为int
,则它是转换的结果。但是第 3 段告诉我们如果值在 中不可表示会发生什么int
:
否则,新类型是有符号的,值不能在其中表示;结果是实现定义的,或者引发了实现定义的信号。
例如,GCC将结果定义为包装模 2 N的结果。因此,对于,GCC将产生与包装模 2 Nint c = (unsigned) a + (unsigned) b;
相同的结果。但是,GCC 不保证后者。优化时,GCC 预计不会发生溢出,这可能导致它消除程序允许发生溢出的任何代码分支。(GCC 可能有一些关于溢出处理的选项。)int c = a + b;
a + b
此外,即使有符号算术和无符号算术都进行了换行,使用无符号值执行操作并转换回来在数学上也不会产生与使用有符号值执行操作相同的结果。例如,考虑-3/2
. 结果int
为 -1。但如果-3
转换为 32 位无符号,则结果值为 2 32 -3,然后(int) ((unsigned) -3 / (unsigned) 2)
是 2 -31 -2 = 2,147,483,646。
推荐阅读
- hibernate - 通过连接表的@OrderColumn 对 JPA 查询的结果集合进行排序
- centering - 在 Bigcartel 中居中产品照片 - 模板:Luna
- graph - 关于在图数据库中建模选举数据的问题
- c# - 将值存储在列表c#中的问题
- c# - 将 asp.net core web api 部署到 aws elastic beanstalk 时出现错误 404
- javascript - 未捕获的类型错误:无法使用 websockets 读取未定义的属性“原型”
- windows - 在系统上禁用休眠时的 Pwrtest S4 场景
- macos - Mac OS 终端中的 WHOIS 没有执行任何操作
- filter - 如何使用 concat 过滤器加入相同的视频流?
- javascript - 按钮 onClick 不适用于 useToggle 挂钩