0

I am writing a C program that has to show each operation in a hexadecimal answer but you have to show all the bytes corresponding to the data type.

for example if its an int it should show 8 bytes, if its a short 4 bytes.

It works for every other data type including char where it only shows two bytes. But short is always showing 8 bytes when I print it

char x5 = 0xa1;
short z5 = x5;

printf("\nProblem 1f: %x\n", z5);

and it prints "Problem 1f: ffffffa1"

a classmate found a solution where %hx prints the correct amount of bytes but I dont understand why this %x prints extra bytes, where are these bytes coming from?

Thanks in advance!

Mornet
  • 1
  • 1
  • 2
    Possible duplicate of [Why does C print my hex values incorrectly?](https://stackoverflow.com/questions/8441257/why-does-c-print-my-hex-values-incorrectly) – Ken Y-N Feb 21 '18 at 23:37
  • 1
    This happens because of integer promotion. You `char` is a 8-bit signed value, `0xa1` is `b1010 0001`, the most significant bit is set to 1, so when it gets promoted to integer (with the short assignment and later in the `printf`, sign extension is applied, that fills all other 3 bytes with ones. You end up with `b1111 1111 1111 1111 1111 1111 1010 0001` which is `ffffffa1`. – Pablo Feb 21 '18 at 23:47
  • Looks correct to me. `char` is one byte, printed as two hex digits. `short` is 4 bytes, printed as 8 hex digits. – Lee Daniel Crocker Feb 21 '18 at 23:50
  • @Pablo is right. Try this: What happens when `x5=0x7f` – MFisherKDX Feb 21 '18 at 23:58
  • Possible duplicate of [printf adds extra \`FFFFFF\` to hex print from a char array](https://stackoverflow.com/questions/31090616/printf-adds-extra-ffffff-to-hex-print-from-a-char-array) – phuclv Feb 22 '18 at 02:26

2 Answers2

2

This is due to silent integer type-promotion. Since 0xa1 is negative value (-95 dec) char, short will be promoted to 4 bytes int and printed negative by printf function.

To prevent promotion you can use unsigned types.

Program below illustrates the behaviour for signed and unsigned types:

#include<stdio.h>
#include<stdlib.h>

int main() {

    char x5 = 0xa1;
    short z5 = x5;
    int i5 = x5;

    unsigned char ux5 = 0xa1;
    unsigned short uz5 = 0xa1;
    unsigned int ui5 = 0xa1;

    size_t sx5 = sizeof(x5);
    size_t sz5 = sizeof(z5);
    size_t si5 = sizeof(i5);


    printf("%zu %zu %zu\n", sx5, sz5, si5);  

    printf("%x %x %x\n", x5, z5, i5);     // silent promotion to 32 bit negative integers

    printf("%x %x %x\n", ux5, uz5, ui5);  // no promotion

    ux5 = x5;   
    uz5 = z5; // remember that z5 is negative number
    ui5 = i5; // same for i5

    printf("%x %x %x\n", ux5, uz5, ui5); // no promotion but numbers are negative ones

   return 0;
}

Output:

1 2 4
ffffffa1 ffffffa1 ffffffa1
a1 a1 a1
a1 ffa1 ffffffa1
sg7
  • 6,108
  • 2
  • 32
  • 40
0

Since x5 large enough (anything over 127 or 0x7F in a single-byte data type) to have the highest bit set (1010 0001), it's interpreted as a negative when using the default signed type. As the other answer mentioned, using an unsigned char fixes the issue. However typecasting x5 will work as well, since short uses two bytes to store the value and will not see it as negative even if it is signed (0000 0000 1010 0001).

typecasting will work:

char x5 = 0xa1;
short z5 = (unsigned char) x5;

and so will using an unsigned char:

unsigned char x5 = 0xa1;
short z5 = x5;

but you should really specify unsigned for everything if you're using it this way to avoid such scenarios.

unsigned char x5 = 0xa1;
unsigned short z5 = x5;
RyanArr
  • 73
  • 6