John Doe
John Doe

Reputation: 89

How to extract bytes from an int variable(hexadecimal value stored in int variable)?

Im trying to extract 4 bytes from hexadecimal value stored in int variable.

My idea is to "push" wanted byte to the end by using right shift operator( >> ) and then use AND operator with 0xFF value to get only last 8 bits of value. Its working fine with number values(73 for example) but its not working with values a-f(3f for example). I have tried using different formats for printf, like %02x , and i have also tried changing the mask for AND operator to 0x000000FF.

int variable = 0x12cd34f4; 
char byte0, byte1, byte2, byte3; 

byte0 = (char)(variable & 0xFF);
byte1 = (char)((variable >> 8) & 0xFF);
byte2 = (char)((variable >> 16) & 0xFF);
byte3 = (char)((variable >> 24) & 0xFF);

printf("%x\n",byte0);// prints fffffff4 
printf("%x\n",byte1);// prints 34
printf("%x\n",byte2);//prints ffffffcd
printf("%x\n",byte3);//prints 12

I expected it to print f4 for byte0, 34 for byte1, cd for byte2 and 12 for byte3, but actual output for byte0 is fffffff4 and for byte2 ffffffcd. I dont understand why those F values are added, and how can i get rid of them.

Upvotes: 1

Views: 1443

Answers (4)

dbush
dbush

Reputation: 225757

Your byte variables are declared as char, which on most implementations is signed. When you pass these values to printf, it doesn't know the exact type of what you pass in because it's a variadic function. So the char arguments get promoted to int. And because you have values which are negative, they get sign extended as part of the promotion.

Change the type of these variables to unsigned char. When the positive values are then promoted to int there will be no sign extension.

Upvotes: 2

Govind Parmar
Govind Parmar

Reputation: 21572

First, the %x format specifier, without any modifiers, on its own, is for the type unsigned int, which apparently on your system is 32-bits.

The most significant bits of the bytes F4 and CD are 1. This is the sign bit, so it is sign-extended to the full 32-bits (hence the FFFFFF), which are printed out.

Observe that when you print them out as %d, you see the sign bit in play too:

-12
52
-51
18

To solve this, you can make the bytes of type unsigned char, do a bitwise and on each printf argument with 0xFF, and use the correct format specifier for an unsigned char in hex, which is %hhX.

Upvotes: 2

glglgl
glglgl

Reputation: 91149

char can be signed or unsigned, that is system dependent (and, maybe, as well depending on compiler options).

In your case, it is obviously signed. Values between 0x80 and 0xFF (and not only those starting from 0xA0!) have bit #7 set and are interpreted as signed value (e. g., 0xFF is -1, 0xF0 is -16, etc.).

When extending them to int (that's what happens when calling printf()), they are sign-extended (that's what the Fs come from) and thus retain their "interpreted value". printf(), however, is told to treat them as unsigned again, so the -16 is represented as 0xFFFFFFF0.

Either use unsigned char resp. uint8_t or add & 0xFF when calling printf().

Upvotes: 3

bruno
bruno

Reputation: 32594

Just force char to be unsigned :

#include <stdio.h>

int main()
{
  int variable = 0x12cd34f4; 
  unsigned char byte0, byte1, byte2, byte3; 

  byte0 = (char)(variable & 0xFF);
  byte1 = (char)((variable >> 8) & 0xFF);
  byte2 = (char)((variable >> 16) & 0xFF);
  byte3 = (char)((variable >> 24) & 0xFF);

  printf("%x\n",byte0);
  printf("%x\n",byte1);
  printf("%x\n",byte2);
  printf("%x\n",byte3);
}

Compilation and execution :

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra c.c
pi@raspberrypi:/tmp $ ./a.out
f4
34
cd
12

Note that the & 0xFF are useless when a char has 8 bits

Upvotes: 2

Related Questions