0

I want to send some 8 bit data(in HEX format) out of 16 bit data from my buffer using char ptr, so for this purpose I took "Unsigned short int" array and dereferencing it using char.But in output extra "FFFFFF" is appended to my data.

code snippet:


unsigned short int buf[50]={0},j;
char *ptr=buf;
//entering some 16bit data manually
buf[0]=0xAAAA;
buf[1]=0xCCBB;
buf[2]=0x1234;
buf[3]=0xABCD;

for(j=0;j<8;j++)
{
    printf("%X\t",*p);
    p++;
}

output:


FFFFFFAA FFFFFFAA FFFFFFBB FFFFFFCC 34 12 FFFFFFCD FFFFFFAB

here for 0x1234 data it is getting in correct format but what about remaining other. can anyone helpme out

Sanith369
  • 11
  • 2
  • 2
    That's not your real code. You declare `ptr` and refer to `p`. By fixing that and adding just a few lines, you could show us something that we could compile and run ourselves. Didn't you get a warning on `char *ptr = buf;`? – Keith Thompson Oct 30 '20 at 06:10

3 Answers3

1

The type of the ptr pointer need to be unsigned here:

unsigned short int buf[50]={0},j;
unsigned char *ptr=buf;
//entering some 16bit data manually
buf[0]=0xAAAA;
buf[1]=0xCCBB;
buf[2]=0x1234;
buf[3]=0xABCD;

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

will give you the expected output: (byte ordering will depend on your endianness, here it is on X86/little-endian)

AA      AA      BB      CC      34      12      CD      AB
Robert
  • 2,711
  • 7
  • 15
  • Hi Robert , Greetings for the day. Thanks for your Response, Can you please elaborate it how "Signed and Unsigned" will effect the pointer in dereferencing the data. – Sanith369 Oct 30 '20 at 06:33
  • You might look at the following question https://stackoverflow.com/questions/27625301/difference-between-unsigned-and-signed-int-pointer – Robert Oct 30 '20 at 06:38
  • ok I got it now, thanks for your precious time Robert. – Sanith369 Oct 30 '20 at 07:02
1
  • 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.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • how this 8 bit data pointed by ptr is converted into 32bit. If it is done by %X, then is there any way to restrict this conversion so that we can our desired number of bits instead of 32 bits output – Sanith369 Oct 30 '20 at 09:26
  • @Sanith369 As explained, this is part of printf's weird behavior and it can't be avoided unless we stay clear of printf. The conversion is specified in the C language standard, so there's no easy way around it. However if you use the `stdint.h` types as in my example, you can also use another header `inttypes.h` which contains various format specifiers for printf that guarantee that it will behave correctly. In this case it would be `#include ... printf("%" PRIx8 "\t", *ptr);`. Then you don't have to worry about if/how the parameter gets promoted. – Lundin Oct 30 '20 at 10:01
0

First of all, your code should be sth like below;

unsigned short int buf[50] = {0}, j;
char *ptr = (char *)buf;
//entering some 16bit data manually
buf[0] = 0xAAAA;
buf[1] = 0xCCBB;
buf[2] = 0x1234;
buf[3] = 0xABCD;

for (j = 0; j < 8; j++) {
    printf("%X ", *ptr); // "p" is not defined any where
    ptr++;               // i think, it's got to be "ptr"
}

About the FF... prefix:

  1. After the first two lines;

    a) 50 * 2 (size of short) = 100 bytes are zeroed out,

    b) then, the first 8 bytes are assigned as aa aa bb cc 34 12 cd ab.

  2. Your pointer ptr is a (char *) (points to a single byte char), but your printf tries to print them as 4 bytes integer.

  3. As *ptr dereferences a single byte, printf converts it to a 4 byte integer. You'd better check your chapters of C book about conversion of char to int & binary numbers. Basically, that chapter would tell you that; in conversion from 1 byte to 4 bytes, the left most bit is copied towards left. That is;

  • 1 byte hex: aa is 1 byte bin: 10101010 converts to 4 byte bin: 11111111...10101010 (left most bit 1 is copied towards left when completing to 4 bytes; it's where the FF prefix comes from)
  • 1 byte hex: 12 is 1 byte bin: 00010010 converts to 4 byte bin: 00000000...00010010 (left most bit 0 is copied towards left when completing to 4 bytes; all zeroed and you do not see any FF prefixes).
ssd
  • 2,340
  • 5
  • 19
  • 37
  • Thanks for your response and valuable time This explanation clears my doubt of why F's are appended . – Sanith369 Oct 30 '20 at 07:06
  • 1
    There's big holes in this explanation. For example %X assumes unsigned int, so why would there be a sign extension of a signed integer? – Lundin Oct 30 '20 at 07:42
  • yes, still i am getting same output(undesired) along with F's . And one doubt is even though i am taking 16 bits ,why output is of 32 bits,did %X plays any role in converting 16 bits to 32 bits? – Sanith369 Oct 30 '20 at 09:04