char和正常的算术转换规则 [英] char and the usual arithmetic conversion rules

查看:136
本文介绍了char和正常的算术转换规则的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道这个问题已经被问,看似在回答一个极大次,但我似乎无法答案符合我自己的经验。

C标准规定,为增加两个操作数应具有算术类型(6.5.6.1)。 Arithemitc类型包括整型和浮点型(6.2.5.18),最后整数类型的char,short,int和长,很长很长所存在的符号和无符号类型(6.2.5.4和6.2.5.6)。根据对正常的算术转换规则如果两个操作数具有相同的类型,则不需要进一步的转换。到目前为止好。

据我的理解,这里离的C书为例,这是其中不可或缺的应用推广[N] 0运算用C在precision比int短则做了。我能找到在标准中没有提及这个由我似乎已经看到了这无数次。

由于unsigned char型是一个算术类型和相同类型的操作数不需要转换正常的算术转换状态的规则,为什么需要整体推进?

我测试使用两种不同的编译器。我写了一个简单的程序,做焦炭另外:

  unsigned char型A = 1;
unsigned char型B = 2;
unsigned char型C = A + B;

目标平台是爱特梅尔的Mega8的uC使用一个8位架构。因此一个整数除将需要使用两个寄存器,如果操作数应该受到积分推广。

这编译使用imagecraft AVR编译器没有优化和启用严格的ANSI C便携性选项产量本届大会code:

  MOV R16,R20
加入R16,R18

使用AVR-GCC(我不知道一个ANSI的转换类似于GCC的-strict):

  $ AVR-gcc的-O0 -mmcu = atmega8的-S -c main.c中

所得到的组件:

  LDD R25,Y + 1
LDD R24,Y + 2
加入R24,R25
STD Y + 3,R24

在这两种情况下所得到的code上的一个字节进行操作。我得到的按位类似的结果|和&安培;和逻辑||和&功放;&放;.这是否意味着那么这个标准允许在性格特征类型的算术运算而无需提升或者这仅仅意味着这些编译器不是标准complient?


其他:

原来这一切取决于结果存储在类型。当结果被存储在一个字符上面所示的例子是仅真实的,它不依赖于另外的结果。一到0xFF和b设置为1,产生完全相同的组装code。

如果C的类型更改为unsigned int类型生成的程序集是这样的:

  MOV R2,R20
CLR R3
MOV R16,R18
CLR R17
加入R16,R2
ADC R17,R3

即使在结果可以在一个单一的字节,即= 1和b = 2被保持的情况。


解决方案

Ç2011(n1570)6.3.1.8(通常的算术转换)1规定,整数促销活动执行的的考虑是否类型是相同的:


  

另外,整数促销活动是在两个操作数执行。然后下面的规则被施加到推动操作数:


  
  

    

如果两个操作数具有相同的类型,则不需要进一步转化...


  

因此​​,在C抽象机, unsigned char型值必须进行算术运算之前,晋升为 INT 。 (这里是不正当的机器异常,其中 unsigned char型 INT 具有相同的尺寸。在这种情况下, unsigned char型值提升到 unsigned int类型,而不是 INT 。这是深奥和不需要在正常情况下可以考虑。)

在实际的机器,操作必须在得到相同的结果的方式执行的,如果的他们在抽象机执行。因为只有结果关系,实际中间操作不需要对抽象机完全匹配。

在两个 unsigned char型值的总和被分配到 unsigned char型对象时,总和转换一个 unsigned char型。这种转换实际上丢弃位超越适合在 unsigned char型

这意味着,C实现获得相同的结果是否确实是:


  • 转换值 INT

  • INT 算术添加值。

  • 转换结果 unsigned char型

或本


  • unsigned char型算术添加值。

由于其结果是一样的,C实现可以使用任何一种方法

为了便于比较,我们可以考虑这句话代替: INT C = A + B; 。此外,假设编译器不知道 A B 的值。在这种情况下,使用 unsigned char型算术做加法可能产生的结果不同的值转换为 INT 和使用 INT 算术。例如,如果 A 250和 B 为200,则其总和为 unsigned char型值是194(250 + 200%256),但他们在 INT 算术之和为450因为是有区别的,C实现的必须使用指令得到正确的总和,450。

(如果编译器都知道的值 A B 或可能以其他方式证明该款项适合一个 unsigned char型,那么编译器可以再次使用 unsigned char型算术)。

I know this question has been asked and seemingly answered a gazillion times over but I can't seem to match the answers to my own experience.

The C standard specifies that for addition "both operands shall have arithmetic type" (6.5.6.1). Arithemitc types covers integer and floating types (6.2.5.18) and finally integer types are char, short, int, long and long long which exist as signed and unsigned types (6.2.5.4 and 6.2.5.6). According to the rules for usual arithmetic conversion "If both operands have the same type, then no further conversion is needed." So far so good.

It has been my understanding, as exemplified here from "The C Book", that "[n]o arithmetic is done by C at a precision shorter than int" which is where integral promotion is applied. I can find no reference to this in the standard by I seem to have seen this numerous times.

Since unsigned char is an arithmetic type and the rules for usual arithmetic conversion states that operands of the same type does not need conversion, why the need for integral promotion?

I tested this using two different compilers. I wrote a simple program which does char addition:

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

The target platform is an Atmel Mega8 uC using an 8 bit architecture. An integer addition would therefore require use of two registers if the operands should be subject to integral promotion.

Compiling this using imagecraft avr compiler with no optimization and with strict and ANSI C portability options enabled yields this assembly code:

mov R16, R20
add R16, R18

Using avr-gcc (I am not aware of an ANSI switch similar to gcc's -strict):

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

The resulting assembly:

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

The resulting code in both cases operates on a single byte. I get similar results for bitwise | and & and logical || and &&. Does this mean then that standard allows arithmetic operations on charecter types without integral promotion or does it simply mean that these compilers are not standard complient?


Additional:

Turns out it all depends on the type the result is stored in. The example shown above is only true when the result is stored in a char, and it does not depend on the result of the addition. Setting a to 0xFF and b to 1 produces the exact same assembly code.

If the type of c is changed to unsigned int the resulting assembly looks like this:

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

Even in the case where the result can be held in a single byte, i.e. a=1 and b=2.

解决方案

C 2011 (n1570) 6.3.1.8 ("Usual arithmetic conversions") 1 states that the integer promotions are performed before considering whether the types are the same:

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…

Thus, in the C abstract machine, unsigned char values must be promoted to int before arithmetic is performed. (There is an exception for perverse machines where unsigned char and int have the same size. In this case, unsigned char values are promoted to unsigned int rather than int. This is esoteric and need not be considered in normal situations.)

In the actual machine, operations must be performed in a way that gets the same results as if they were performed in the abstract machine. Because only the results matter, the actual intermediate operations do not need to exactly match the abstract machine.

When the sum of two unsigned char values is assigned to an unsigned char object, the sum is converted to a unsigned char. This conversion essentially discards bits beyond the bits that fit in an unsigned char.

This means that the C implementation gets the same result whether it does this:

  • Convert values to int.
  • Add values with int arithmetic.
  • Convert result to unsigned char.

or this:

  • Add values with unsigned char arithmetic.

Because the result is the same, the C implementation may use either method.

For comparison, we can consider this statement instead: int c = a + b;. Also, suppose the compiler does not know the values of a and b. In this case, using unsigned char arithmetic to do the addition could yield a different result than converting the values to int and using int arithmetic. E.g., if a is 250 and b is 200, then their sum as unsigned char values is 194 (250 + 200 % 256), but their sum in int arithmetic is 450. Because there is a difference, the C implementation must use instructions that get the correct sum, 450.

(If the compiler did know the values of a and b or could otherwise prove that the sum fit in an unsigned char, then the compiler could again use unsigned char arithmetic.)

这篇关于char和正常的算术转换规则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆