- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
该帖子旨在用作有关C中隐式整数提升的FAQ,尤其是由通常的算术转换和/或整数提升引起的隐式提升。
示例1)
为什么这会给出一个奇怪的大整数而不是255?
unsigned char x = 0;
unsigned char y = 1;
printf("%u\n", x - y);
unsigned int a = 1;
signed int b = -2;
if(a + b > 0)
puts("-1 is larger than 0");
short
可以解决问题?
unsigned short a = 1;
signed short b = -2;
if(a + b > 0)
puts("-1 is larger than 0"); // will not print
最佳答案
C被设计为隐式和无声地更改表达式中使用的操作数的整数类型。在某些情况下,该语言会迫使编译器将操作数更改为更大的类型,或者更改其符号。
其背后的原理是为了防止算术期间意外溢出,而且还允许具有不同符号的操作数在同一表达式中共存。
不幸的是,隐式类型提升的规则弊大于利,以至于它们可能是C语言中最大的缺陷之一。这些规则通常对于普通C程序员来说甚至都不为人所知,因此会引起各种非常细微的错误。
通常情况下,您会看到程序员说“只需强制转换为x即可使用它”的情况-但他们不知道为什么。或者,这些bug表现为看似简单而直接的代码中罕见的间歇性现象。隐式提升在执行位操作的代码中尤其麻烦,因为在给定有符号操作数的情况下,C中大多数位操作符的行为都定义不明确。
整数类型和转换等级
C中的整数类型为char
,short
,int
,long
,long long
和enum
。_Bool
/ bool
在类型促销中也被视为整数类型。
所有整数都有指定的转换等级。 C11 6.3.1.1,重点放在最重要的部分:
每个整数类型都有一个整数转换等级,定义如下:
—即使两个有符号整数类型具有相同的表示形式,也不应具有相同的等级。
—有符号整数类型的等级应大于精度较低的任何有符号整数类型的等级。
— long long int
的等级应大于long int
的等级,该等级应大于int
的等级,该等级应大于short int
的等级,后者应大于signed char
的等级。 stdint.h
。
—任何无符号整数类型的等级应等于相应的有符号整数类型的等级(如果有)。
—任何标准整数类型的秩应大于相同宽度的任何扩展整数类型的秩。
—字符的等级应等于有符号字符和无符号字符的等级。
— _Bool的等级应小于所有其他标准整数类型的等级。
—任何枚举类型的等级应等于兼容整数类型的等级(见6.7.2.2)。int32_t
中的类型也在这里排序,与它们在给定系统上对应的任何类型的排名相同。例如,在32位系统上,int
与int
具有相同的等级。
此外,C11 6.3.1.1指定哪些类型被视为小整数类型(不是形式术语):
在unsigned int
或int
可能在的表达式中可以使用以下内容
使用:
—具有整数类型(unsigned int
或int
除外)的对象或表达式,其整数转换等级小于或等于unsigned int
和_Bool
的等级。
在实践中,这种有点神秘的文字意味着char
,short
和int8_t
(还有uint8_t
,int
等)是“小整数类型”。如下所述,这些内容将以特殊方式处理并受到隐式提升。
整数促销
每当在表达式中使用小整数类型时,它都会隐式转换为始终带有符号的int
。这称为整数提升或整数提升规则。
正式而言,规则说(C11 6.3.1.1):
如果int
可以表示原始类型的所有值(对于位字段,受宽度限制),则该值将转换为unsigned int
;否则,它将转换为int
。这些称为整数促销。
这意味着,在大多数表达式中使用时,所有小的整数类型(无论是否带符号)都将隐式转换为(带符号的)unsigned short
。
该文本经常被误解为:“所有小的带符号整数类型都转换为带符号的int,而所有小的带符号整数类型都转换为无符号的int”。这是不正确的。这里的无符号部分仅意味着,例如,如果我们有一个int
操作数,并且short
在给定系统上恰好具有与unsigned short
相同的大小,则unsigned int
操作数将转换为short
。在这种情况下,什么都没有真正发生。但是,如果int
是小于int
的类型,则始终将其转换为(带符号的)char
,而不管短代码是带符号的还是无符号的!
整数提升引起的严酷现实意味着,在C中几乎无法对short
或int
之类的小字符执行任何操作。操作始终在unsigned char
或更大的类型上进行。
这听起来像是胡说八道,但是幸运的是编译器被允许优化代码。例如,包含两个int
操作数的表达式将把操作数提升为int
,并将操作作为int
进行。但是,可以预期,编译器可以优化表达式以实际以8位运算的形式执行。但是,问题来了:不允许编译器优化由整数提升引起的有符号性的隐式更改。因为编译器无法判断程序员是故意依赖隐式升级还是非故意的。
这就是为什么问题中的示例1失败的原因。两个无符号char操作数都提升为int
类型,对该类型的x - y
执行该操作,并且int
的结果为-1
类型。意味着我们得到的是255
而不是预期的int
。编译器可能会生成使用8位指令而不是printf("%u
来执行代码的机器代码,但可能无法优化签名的更改。这意味着我们最终得到一个否定的结果,这反过来导致在调用unsigned char
时产生一个怪异的数字。可以通过将操作结果转换回类型++
来修复示例1。
除了sizeof
和if-else if
运算符之类的一些特殊情况外,整数提升适用于C中几乎所有的运算,无论是否使用一元,二进制(或三进制)运算符。
通常的算术转换
每当在C中执行二进制运算(带有2个操作数的运算)时,运算符的两个操作数都必须具有相同的类型。因此,在操作数为不同类型的情况下,C强制将一个操作数隐式转换为另一操作数的类型。如何完成此操作的规则称为通常的人工转换(有时非正式地称为“平衡”)。这些在C11 6.3.18中指定:
(将此规则视为长的嵌套long double
语句,可能更容易阅读:))
6.3.1.8常规算术转换
许多期望算术类型的操作数的运算符会导致转换并产生结果
以类似的方式输入。目的是确定操作数的通用实型
结果。对于指定的操作数,将转换每个操作数,而无需更改类型
域,将其转换为对应的实型是普通实型的类型。除非
除非另有明确说明,否则普通实型也是对应的实型
结果,如果它们是相同的,则其类型域是操作数的类型域,
否则就很复杂。这种模式称为通常的算术转换:
首先,如果一个操作数的相应实型为long double
,则将另一个操作数转换为相应实型为double
的类型,而不会改变类型域。
否则,如果任一操作数的相应实型为double
,则将另一个操作数转换为相应实型为float
的类型,而不会改变类型域。
否则,如果任一操作数的对应实型为int
,则另一个操作数将转换为对应实型为float的类型,而不会改变类型域。
否则,将对两个操作数执行整数提升。然后
以下规则适用于提升的操作数:
如果两个操作数具有相同的类型,则无需进一步转换。
否则,如果两个操作数都具有符号整数类型或都具有无符号
整数类型,具有较小整数转换等级的类型的操作数为
转换为具有更高等级的操作数的类型。
否则,如果具有无符号整数类型的操作数的秩更大或
等于另一个操作数类型的等级,然后是
有符号整数类型将转换为无符号操作数的类型
整数类型。
否则,如果带符号整数类型的操作数的类型可以表示
具有无符号整数类型的操作数类型的所有值,然后
无符号整数类型的操作数将转换为
带符号整数类型的操作数。
否则,两个操作数都将转换为无符号整数类型
对应于带符号整数类型的操作数的类型。
这里值得注意的是,通常的算术转换适用于浮点数和整数变量。如果是整数,我们还可以注意到,整数促销是从常规算术转换中调用的。之后,当两个操作数的秩至少为a + b
时,运算符将被平衡为具有相同符号的相同类型。
这就是为什么示例2中的int
给出奇怪结果的原因。这两个操作数都是整数,并且它们的排名至少为a
,因此整数提升不适用。操作数的类型不同-unsigned int
是b
,signed int
是b
。因此,运算符unsigned int
临时转换为类型short
。在此转换过程中,它会丢失符号信息并最终产生较大的值。
在示例3中将类型更改为short
的原因解决了该问题,这是因为int
是小的整数类型。这意味着两个操作数都是整数,提升为带符号的int
类型。整数提升后,两个操作数具有相同的类型(
关于c - 隐式类型提升规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60243654/
我需要在 nginx-ingress 版本上允许来自多个来源的请求:http://localhost:4200、http://localhost:4242 等1.7.1.但我无法对多个来源执行此操作,
我正在部署我使用 APIGILITY 开发的 API到 IIS。由于 IIS 不支持 .htaccess,我试图从 .htaccess 文件的内容创建 web.config 文件。我使用 IISv7.
我正在尝试更改上面 css 样式中的“宽度”规则。在“inspect element”中你可以看到宽度是1008px。我不希望它是 1008px 但它不会让我在 css 样式中更改它你可以看到它被“删
外部css赋值有2种方法,我用的是第一种;大多数网站使用第二种方法。我想知道我是否做错了! 第一种方法: 为几乎每个 css 规则创建一个类并在任何地方使用它们。 blah blah .f_
RDF使用 WEB 标识符 (URIs) 来标识资源,使用属性和属性值来描述资源 RDF 资源、属性和属性值 RDF使用 WEB 标识符来标识事物,并通过属性和属性值来描述资源。 关于资源、属性
我想挖掘特定的 rhs 规则。文档中有一个示例证明这是可能的,但仅适用于特定情况(如下所示)。先来一个数据集来说明我的问题: input {b=100002} 0.2500000 0.250000
我想让 nginx 从网站根目录(:http://localhost:8080/)提供一个静态文件,但它为我的代理通行证提供服务;它提供“/”规则而不是“=/”。 这是我的 nginx 配置的样子:
根据gnu make documentation , 如果一个规则通过一次调用生成多个目标(例如,一个配方执行一个带有多个输出文件的工具),你可以使用 '&:' 规则语法来告诉 make。但是,当在多
我已阅读Firebase Documentation并且不明白什么是 .contains()。 以下是文档中 Firebase 数据库的示例规则: { "rules": { "rooms"
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 6 年前。 Improv
我正在尝试做一些多态性练习,但我无法弄清楚这种多态性是如何工作的。我没有找到任何关于这种练习的深入信息。希望大家能给我一些解释。 练习1: class Top { public void m(
为了调试复杂的 XSLT 转换,我将其分为几个部分:首先构建 %.1.xml,然后使用它构建 %.2.xml ,最后构建 %.3.xml。一切正常,但如果我要求 Make 构建最后一个,Make 总是
我尝试了 hacerrank 的 slove 练习 Click我不知道如何添加这些规则: ► 它可以包含 4 个一组的数字,并用一个连字符“-”分隔。 ► 不得有 4 个或更多连续重复数字。 这是我的
我正在尝试编写一个小测验,我希望“再试一次”按钮遵循与“else”之前的“if”语句相同的规则 using System; public class Program { public stat
在我的 Spring/Boot Java 项目中,我有一组服务方法,例如以下一个: @Override public Decision create(String name, String descr
我正在阅读 Covariant virtual function .上面写着 假设 B::f 覆盖了虚函数 A::f。如果满足以下所有条件,A::f 和 B::f 的返回类型可能不同: 1) The
我工作的公司想要分发(在公共(public)链接中)具有内部签名的应用程序。我很确定 Apple 否认这种事情,但我在官方文档/契约(Contract)中没有找到任何相关信息。 有谁知道它到底是如何工
我是 CSS 新手。我观察到一个奇怪的 CSS 行为,其中一个元素具有以下 CSS 属性 .container .header{ color: #FFFFFF; font-size: 2em;
这个问题在这里已经有了答案: Is there a CSS selector for elements containing certain text? (21 个答案) 关闭 7 年前。
我有以下 CSS: workoutcal.css: .errorlist{ color:red; } 以下基本模板: base.html: {% load static %} {
我是一名优秀的程序员,十分优秀!