integral promotion

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

I have a few questions regarding the C standard and how it is implemented in gcc.

My task is to check if a checksum is valid for an array of data. The array is unsigned byte values. The checksum is a 16-bit value made up of the last two bytes in the array. I loop through the array and calculate my own version of the checksum, then compare it to the checksum in the array. Here is the code for the comparison:

uint16_t cksum=0;
uint8_t data[MAX_VAL]; /* this actually has data in it */

/* snip - calculate cksum */

/* compare calculated cksum to actual */
if (cksum == (data[i]<<8) + data[i+1])
    /* good checksum */

What surprised me was that this worked. I originally thought that since data[i] is a uint8_t that shifting it 8 bits would cause it to be 0, so I would lose the high byte of my checksum. However, it appears that data[i] is being promoted to an int (this is what the C standard states) and I am fortunate that an int is 16 bits with the avr target. Is this what is actually happening?

My next question is, how can I insure that the two bytes are being promoted to 16 bits without relying on the compiler to be standards compliant? Would it be this way:

if (cksum == (uint16_t)((data[i]<<8) + data[i+1]))

or this way:

if (cksum == (uint16_t)(data[i]<<8) + (uint16_t)data[i+1])

?

My feeling is the second way.

Any help or insight would be great.

Thanks,
Jon

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1) yes.. but beware a compiler switch line -mint8 will break that behaviour.

2) actually neither, because you are applying the cast after the shift. Also note that you only need to apply the cast to the value being shifted, as that's the only one that would be affected by being undersized.

if (cksum == (((uint16_t)data[i])<<8) + data[i+1]) 

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

Last Edited: Tue. Jun 26, 2007 - 05:33 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
if (cksum == ((uint16_t)data[i]<<8) + data[i+1])

The operation that we need to ensure is done with 16 bits (were it not for integer promotion) is the shift. Where you will need this, i.e., where integer promotion does not help when int is 16 bits, is, e.g.:

uint32_t result;
uint16_t high16bits;
uint16_t low16bits;
.
.
result = ((uint32_t)high16bits << 16) + low16bits;

/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you both very much. I see now that my second method of casting is not correct either. I appreciate the help.

Jon

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
as that's the only one that would be affected by being undersized

And because the add comes after the cast of the first byte, the second will necessarily be promoted anyways since it is being added to a 16 bit int.

Regards,
Steve A.

The Board helps those that help themselves.