after dereferencing a char pointer i get an unexpected output duplicate

  • char *ptr=buf; This is not valid C. Since the pointer types are not compatible, this is a violation of the constraints for “simple assignment”. A compiler must give you a dignostic message like a warning. You can fix this by casting before assignment: char*ptr = (char*)buf;

  • buf[1]=0xCCBB; etc stores the unsigned short in memory, and like any integer type it is stored according to endianess. In case you are using an x86 PC that’s little endian and 0xBB gets stored on the lowest address. That’s why they appear backwards when you later on print them byte by byte.

  • printf("%X\t",*ptr); A lot of strange things happen on this line.

    • First of all, we must learn that char has implementation-defined signedness, Is char signed or unsigned by default?. Therefore it is a type which should never be used for raw binary manipulation or any form of arithmetic.
    • On your specific compiler, char happened to be signed.
    • printf is a variadic function. Such functions are exotic (and bad practice) and come with a lot of special rules. One such special rule states that each parameter passed to a variadic function goes through a special kind of implicit promotion known as “the default argument promotions”. This rule says that all small integer types (such as char) are promoted to type int.
    • Whenever a signed char or any other small integer type is promoted to a larger signed type, it is sign extended, meaning that if it held a negative decimal value, the sign is preserved.
    • If your 8 bit signed char pointed at data 0xAA, then it gets treated as a negative number, since 0xAA is -86 decimal in 8-bit 2’s complement format. When this -86 value is converted to a 4 byte signed int, the sign is preserved, it still has value -86. But now the raw binary representation is 0xFFFFFFAA. This is why all your hex value bytes with MSB set got the 0xFFFFFF… appended to them, but those without the MSB set got printed as expected.
    • Finally, %X assumes that the passed parameter is an unsigned int, so printf makes an internal conversion from your temporary int with value -86 into the unsigned equivalent 0xFFFFFFAA, which is what gets printed.

We can fix the code like this:

#include <stdio.h>
#include <stdint.h>

int main()
{
  uint16_t buf[50];
  uint8_t* ptr = (uint8_t*)buf;
  
  buf[0]=0xAAAA;
  buf[1]=0xCCBB;
  buf[2]=0x1234;
  buf[3]=0xABCD;

  for(int i=0; i<8; i++)
  {
      printf("%X\t",*ptr);
      ptr++;
  }
}

Here the same default argument promotion of uint8_t to int occurs, but this time the original data is treated like unsigned before promotion, so no sign extension happens.

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top