Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

char and the usual arithmetic conversion rules

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). Arithmetic 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 but 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 an 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 the standard allows arithmetic operations on character 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.

like image 699
Kenneth Avatar asked Oct 11 '12 13:10

Kenneth


People also ask

What are the types of conversion?

There are two types of conversion: implicit and explicit. The term for implicit type conversion is coercion. Explicit type conversion in some specific way is known as casting. Explicit type conversion can also be achieved with separately defined conversion routines such as an overloaded object constructor.

What is conversion write about the rules of conversion?

To be conversion, a taking of property must be without the owner's consent. There must be some act giving the taker some control over the object, though actual physical removal is not essential. The taking need not be malicious or even knowledgeable.

What is the use of type conversion write the standard conversion rules in C ++?

Type Conversion in C++ Done by the compiler on its own, without any external trigger from the user. Generally takes place when in an expression more than one data type is present. In such condition type conversion (type promotion) takes place to avoid lose of data.

What is type of conversion in C?

In C programming, we can convert the value of one data type ( int, float , double , etc.) to another. This process is known as type conversion.


1 Answers

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.)

like image 130
Eric Postpischil Avatar answered Sep 22 '22 01:09

Eric Postpischil