Jump to content
elpaso

mspgcc right shift question (energia)

Recommended Posts

Hi, 

 

it might be my deep ignorance of C language but I'm not sure if this is the expected behaviour:


char c;

void setup() {

  Serial.begin(9600);

  c = 0b10000000;
  c = c >> 1;
  Serial.println((char)c, BIN);

  // Prints 11111111111111111111111111000000
  
  if(c == 0b01000000){
      Serial.println("ok");
  } else {
      Serial.println("ko");
  }
  
  // Prints ko
}

void loop() {
}

Right shifting a char 0b10000000 should yield  0b01000000 while yields 0b11000000.

 

I know that the CPU is 16 bits but why the 8 msb are set to 1 ?

 

I'm using latest energia.

 

 

 

 

Share this post


Link to post
Share on other sites

i don't know about the compiler, but here's how 2's complenent arithmetic would work:

it means we interpret the byte quantity as a 2's complement number, not as a bit pattern.

other machine instructions can interpret the byte 'logically' and fill from the left with zero, the carry bit, etc.

 

 

so, in 2's compl arith........................      this can be called 'sign extending'  where the msb is the + or - sign bit.

 

 

80 hex byte      =          -128 (decimal)

 

right shift -128 (arithmetically, ie divide by 2)    =   -64 (decimal)

 

-64 (decimal)        =      C0  hex byte

 

                            =  1100 0000     binary

 

 

(!!!!!!!   note that the msb is a 'one',  this a nice property of right shifting 2's complement numbers   !!!!!!!)

   (it is very standard)

 

 

now, even in a larger bit machine; such as 16, 32, or even 64 bits;   all those extra 'ones' on the left STILL make the same negative number !

 

so, the decimal number -64 can be

 

1100 0000                      binary byte

C0                                   hex byte

1111 1111 1100 0000    16-bit binary word

   FFC0                            hex word

 

 

etcetera

 

 

ciao

Share this post


Link to post
Share on other sites

i don't know about the compiler, but here's how 2's complenent arithmetic would work:

it means we interpret the byte quantity as a 2's complement number, not as a bit pattern.

other machine instructions can interpret the byte 'logically' and fill from the left with zero, the carry bit, etc.

 

 

so, in 2's compl arith........................      this can be called 'sign extending'  where the msb is the + or - sign bit.

 

 

80 hex byte      =          -128 (decimal)

 

right shift -128 (arithmetically, ie divide by 2)    =   -64 (decimal)

 

-64 (decimal)        =      C0  hex byte

 

                            =  1100 0000     binary

 

 

(!!!!!!!   note that the msb is a 'one',  this a nice property of right shifting 2's complement numbers   !!!!!!!)

   (it is very standard)

 

 

now, even in a larger bit machine; such as 16, 32, or even 64 bits;   all those extra 'ones' on the left STILL make the same negative number !

 

so, the decimal number -64 can be

 

1100 0000                      binary byte

C0                                   hex byte

1111 1111 1100 0000    16-bit binary word

   FFC0                            hex word

 

 

etcetera

 

 

ciao

 

 

Thanks, this solves my issue: changing from "char" to "unsigned char" works.

 

I just forgot that "char" is signed, I should stop using chars in favour of uint8_t in my code.

Share this post


Link to post
Share on other sites

The signedness of a char is undefined in the C standard. This means that it's up to the compiler to define this.

Would a char be signed then, if it contains the binary value 0b10000000 then the corresponding decimal value is not 128 as you might expect, but -128.

Shifting this value one to the right yields the result 0b11000000 which is equal to -64.

If you want your char to behave as a unsigned integer of 8 bits, declare your variables explicitly unsigned

unsigned char c;

 

Or even better, include stdint.h (or cstdint for C++) and delare your variable as a 8 bit unsigned variable

uint8_t c;

Share this post


Link to post
Share on other sites

Thanks, this solves my issue: changing from "char" to "unsigned char" works.

 

I just forgot that "char" is signed, I should stop using chars in favour of uint8_t in my code.

To slightly clarify roadrunner84's comment:  "char" is neither signed nor unsigned.  It is a type distinct from both "signed char" and "unsigned char", and the compiler must specify that its behavior is equivalent to one or the other.

 

gcc treats char as equivalent to signed char while IAR and CCS make it equivalent to unsigned char.

 

Using uint8_t and int8_t is the right choice of data type when operating on specifically 8-bit data (as opposed to character data, where char is correct).  I do use "unsigned char" when I mean "the unsigned form of the smallest integral data type supported by the processor", though, just as I'll use "unsigned int" for "the unsigned form of the native integral data type" in preference to uint16_t when it really isn't the range that I'm concerned about.  Thus I have no problem using unsigned char to hold the value of P1IN when programming an MSP430.

So many choices.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...