char和通常的算术转换规则

前端之家收集整理的这篇文章主要介绍了char和通常的算术转换规则前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我知道这个问题已被提出并且似乎已经回答了无数次,但我似乎无法将答案与我自己的经验相匹配.

C标准规定,对于加法“两个操作数应具有算术类型”(6.5.6.1). Arithemitc类型包括整数和浮点类型(6.2.5.18),最后整数类型是char,short,int,long和long long,它们以有符号和无符号类型(6.2.5.4和6.2.5.6)存在.根据通常算术转换的规则“如果两个操作数具有相同的类型,则不需要进一步转换.”到现在为止还挺好.

我的理解,正如“C书”中所示,“[n] o算术由C以比int短的精度完成”,这是应用积分推广的地方.我在标准中找不到对此的参考,我似乎已经多次看过这个.

由于unsigned char是一种算术类型,并且通常算术转换的规则表明相同类型的操作数不需要转换,为什么需要进行积分提升?

我使用两个不同的编译器测试了这个.我写了一个简单的程序,它添加了char:

unsigned char a = 1;
unsigned char b = 2;
unsigned char c = a + b;

目标平台是使用8位架构的Atmel Mega8 uC.因此,如果操作数应该进行整体提升,则整数加法将需要使用两个寄存器.

使用imagecraft avr编译器进行编译,没有优化,并且启用了严格的ANSI C可移植性选项,产生了这个汇编代码

mov R16,R20
add R16,R18

使用avr-gcc(我不知道类似于gcc的-strict的ANSI开关):

$avr-gcc -O0 -mmcu=atmega8 -S -c main.c

结果汇编:

ldd r25,Y+1
ldd r24,Y+2
add r24,r25
std Y+3,r24

两种情况下的结果代码都在单个字节上运行.我得到类似的结果|和&和逻辑||和&&这是否意味着该标准允许对charecter类型进行算术运算而不进行整数提升,或者仅仅意味着这些编译器不是标准的兼容性?

额外:

事实证明,这一切都取决于存储结果的类型.上面显示的示例仅在结果存储在char中时才为真,并且它不依赖于添加的结果.将a设置为0xFF并将b设置为1会生成完全相同的汇编代码.

如果c的类型更改为unsigned int,则生成的程序集如下所示:

mov R2,R20
clr R3
mov R16,R18 
clr R17
add R16,R2 
adc R17,R3

即使在结果可以保持在单个字节中的情况下,即a = 1且b = 2.

解决方法

C 2011(n1570)6.3.1.8(“常用算术转换”)1表示在考虑类型是否相同之前执行整数提升:

Otherwise,the integer promotions are performed on both operands. Then the following rules are applied to the promoted operands:

If both operands have the same type,then no further conversion is needed…

因此,在C抽象机器中,必须在执行算术之前将unsigned char值提升为int. (对于perverse机器,有一个例外,其中unsigned char和int具有相同的大小.在这种情况下,unsigned char值被提升为unsigned int而不是int.这是深奥的,在正常情况下不需要考虑.)

在实际的机器中,必须以与在抽象机器中执行的结果相同的方式执行操作.因为只有结果很重要,所以实际的中间操作不需要与抽象机完全匹配.

将两个unsigned char值的总和分配给unsigned char对象时,总和将转换为unsigned char.这种转换实质上会丢弃超出适合无符号字符的位的位.

这意味着无论是否执行此操作,C实现都会获得相同的结果:

>将值转换为int.
>使用int算术添加值.
>将结果转换为unsigned char.

或这个:

>使用unsigned char算法添加值.

因为结果相同,所以C实现可以使用任一种方法.

为了比较,我们可以改为考虑这个陈述:int c = a b;.另外,假设编译器不知道a和b的值.在这种情况下,使用无符号字符算法进行添加可能会产生与将值转换为int并使用int算法不同的结果.例如,如果a为250且b为200,则它们作为无符号字符值的总和为194(250 200%256),但它们在int算术中的总和为450.因为存在差异,C实现必须使用获取的指令正确的总和,450.

(如果编译器确实知道a和b的值,或者可以证明总和适合unsigned char,那么编译器可以再次使用unsigned char算法.)

原文链接:https://www.f2er.com/c/116584.html

猜你在找的C&C++相关文章