Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it a C standard to define how to store the temporary result of shift operation?

My C program is very simple, and runs in 64-bit Linux:

#include <stdio.h>
int main(void)
{
    unsigned char a = 0xff;
    unsigned  short b = (a << 6) ;
    return 0;
}

I am curious about where the temporary result of (a << 6) is stored, so I check the assembly code:

0x0000000000400474 <+0>:     push   %rbp
0x0000000000400475 <+1>:     mov    %rsp,%rbp
0x0000000000400478 <+4>:     movb   $0xff,-0x3(%rbp)
0x000000000040047c <+8>:     movzbl -0x3(%rbp),%eax
0x0000000000400480 <+12>:    shl    $0x6,%eax
0x0000000000400483 <+15>:    mov    %ax,-0x2(%rbp)
0x0000000000400487 <+19>:    mov    $0x0,%eax
0x000000000040048c <+24>:    leaveq
0x000000000040048d <+25>:    retq

From the assembly code, I can see the eax is used to store the temporary result of shift operation.

So I want to know is it a C standard to use signed/unsigned 32-bit integer to store the temporary result of shift operation?

I have checked section 6.5.7 Bitwise shift operators of n1570 specification, but nothing can be found.

like image 732
Nan Xiao Avatar asked Mar 17 '14 06:03

Nan Xiao


People also ask

What are shift operations in C?

It is a binary operator that requires two operands to shift or move the position of the bits to the left side and add zeroes to the empty space created at the right side after shifting the bits.

Does C perform logical right shifts?

Most C and C++ implementations, and Go, choose which right shift to perform depending on the type of integer being shifted: signed integers are shifted using the arithmetic shift, and unsigned integers are shifted using the logical shift.

What is purpose of shift operation?

A shift operator performs bit manipulation on data by shifting the bits of its first operand right or left.

What are shift operators in C++?

The bitwise shift operators are the right-shift operator (>>), which moves the bits of shift_expression to the right, and the left-shift operator (<<), which moves the bits of shift_expression to the left.


2 Answers

The standard does not specify those low-level details but you missed one important part in the draft C11 standrd section 6.5.7 paragraph 2 says (emphasis mine):

The integer promotions are performed on each of the operands.[...]

This is covered in section 6.3.1 Arithmetic operands subsection 6.3.1.1 Boolean, characters, and integers paragraph 2 which says:

The following may be used in an expression wherever an int or unsigned int may be used:

and includes the following bullet:

An object or expression with an integer type (other than int or unsigned int) whose integer conversion rank is less than or equal to the rank of int and unsigned int.

which includes short and char and goes on to say (emphasis mine):

If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.58) All other types are unchanged by the integer promotions.

So both a and 6 has to be promoted to int and that will provide a lower bound on which register can be used to store the intermediate results.

Note, as Keith points out in your code sample since the assignment and shift have no observable behavior the compiler would be free to optimize those instructions out.

like image 186
Shafik Yaghmour Avatar answered Sep 19 '22 04:09

Shafik Yaghmour


The C compiler can store the result anywhere it likes: you specified a as char (8 bits typically) and b as short int (16 bits typically), both of them easily fit within the 32-bit %eax.

If you define a and b as long long int (64 bits), you'll note that the compiler has to use a 64 bit register (e.g. %rax).

like image 25
Christian Aichinger Avatar answered Sep 18 '22 04:09

Christian Aichinger