char和正常的算术转换规则 [英] char and the usual arithmetic conversion rules
问题描述
我知道这个问题已经被问,看似在回答一个极大次,但我似乎无法答案符合我自己的经验。
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 toint
before arithmetic is performed. (There is an exception for perverse machines whereunsigned char
andint
have the same size. In this case,unsigned char
values are promoted tounsigned int
rather thanint
. 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 anunsigned char
object, the sum is converted to aunsigned char
. This conversion essentially discards bits beyond the bits that fit in anunsigned 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 ofa
andb
. In this case, usingunsigned char
arithmetic to do the addition could yield a different result than converting the values toint
and usingint
arithmetic. E.g., ifa
is 250 andb
is 200, then their sum asunsigned char
values is 194 (250 + 200 % 256), but their sum inint
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
andb
or could otherwise prove that the sum fit in anunsigned char
, then the compiler could again useunsigned char
arithmetic.)这篇关于char和正常的算术转换规则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!