32 bit hex in one variable - c

How can I put this hex 0x0a01 into a 32 bit var in C. What I'm trying to do is to parse a protocol. Part of the it has a length value. The problem is that I'm getting the received packet as an array, so the length 0x0a01 would be 0x0a on lets say [1] and 0x01 on [2], and I want them both to be 0a01 in one var so I can run a compare to a constant or use in a for loop.

ah 32 bit is a int in most current platforms (or int32_t defined in stdint.h)
and bit operations are made for this:
int var = buff[1]<<8|buff[2];
<< is the left shift so 0x0a gets transformed into 0x0a00 and | is the or operator so that is gets combined properly

uint32_t var;
char buff[128];
...
var = ((buff[1] & 0xFF) << 8) | (buff[2] & 0xFF);
Notice we use (buff[1] & 0xFF) << 8 and not buff[1] << 8, because if buff is a char array and char is signed, sign extension would occur on the promoted buff[1] when the value is negative.

Related

Problem of converting byte order for unsigned 64-bit number in C

I am playing with little endian/big endian conversion and found something that a is a bit confusing but also interesting.
In first example, there is no problem using bit shift to convert byte order for type of uint32_t. It basically cast a uint32_t integer to an array of uint8_t and try to access each byte and bit shift.
Example #1:
uint32_t htonl(uint32_t x)
{
uint8_t *s = (uint8_t*)&x;
return (uint32_t)(s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]);
}
However, if I try to do something similar on a uint64_t below, the compiler throws a warning about 's[0] width is less than 56 bits` as in Example #2 below.
Example #2:
uint64_t htonl(uint64_t x)
{
uint8_t *s = (uint8_t*)&x;
return (uint64_t)(s[0] << 56 ......);
}
To make it work, I have to fetch each byte into a uint64_t so I can do bit shift without any errors as in Example #3 below.
Example #3:
uint64_t htonll2(uint64_t x)
{
uint64_t byte1 = x & 0xff00000000000000;
uint64_t byte2 = x & 0x00ff000000000000;
uint64_t byte3 = x & 0x0000ff0000000000;
uint64_t byte4 = x & 0x000000ff00000000;
uint64_t byte5 = x & 0x00000000ff000000;
uint64_t byte6 = x & 0x0000000000ff0000;
uint64_t byte7 = x & 0x000000000000ff00;
uint64_t byte8 = x & 0x00000000000000ff;
return (uint64_t)(byte1 >> 56 | byte2 >> 40 | byte3 >> 24 | byte4 >> 8 |
byte5 << 8 | byte6 << 24 | byte7 << 40 | byte8 << 56);
}
I am a little bit confused by Example #1 and Example #2, as far as I understand, both s[i] is of uint8_t size, but somehow if it only shift 32 bits or less there is no problem at all, but there is an issue when shifting like 56 bits. I am running this program on Ubuntu with GCC 8.3.0.
Does the compiler implicitly convert s[i] into 32-bit numbers in this case? sizeof(s[0]) is 1 when I added debug messages to that.
Values with a type smaller than int are promoted to int when used in an expression. Assuming an int is 32 bit on your platform this works in most cases when converting a 32 bit value. The time it won't work is if you shift a 1 bit into the sign bit.
In the 64 bit case this means you're attempting to shift a value more than its bit length which is undefined behavior.
You need to cast each byte to a uint64_t in both cases to allows the shifts to work properly.
The s[0] expression has an 8-bit wide integral type, which is promoted to a 32-bit unsigned integer when operated on by the shift operator – so s[0] << 24 in the first example works OK, as the shift by 24 does not exceed the uint length.
OTOH the shift by 56 bits moves data outside the result's length as the offset exceeds the length of integer, so it certainly causes a loss of information, hence the warning.

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.
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().
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
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.
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.

How to make a word from Byte []?

I am new to programming world, I want to convert two bytes into a word.
So basically, I have a Byte array where index 0 is Buffer[0]=08 and index 1 is Buffer[1]=06
I want to create a word from these two bytes
where word ETHType to be 0x0806
You would use bitwise operators and bit shifting.
uint16_t result = ((uint16_t)Buffer[0] << 8) | Buffer[1];
This does the following:
The value of Buffer[0] is shifted 8 bits to the left. That gives you 0x0800
A bitwise OR is performed between the prior value and the value of Buffer[1]. This sets the low order 8 bits to Buffer[1], giving you 0x0806
word ETHType = 0;
ETHType = (Buffer[0] << 8) | Buffer[1];
edit: You should probably add a mask to each operation to make sure there is no bit overlap, and you can do it safely in one line.
word ETHType = (unsigned short)(((unsigned char)(Buffer[0] & 0xFF) << 8) | (unsigned char)(Buffer[1] & 0xFF)) & 0xFFFF;
Here's a macro I use for this very thing:
#include <stdint.h>
#define MAKE16(a8, b8) ((uint16_t)(((uint8_t)(((uint32_t)(a8)) & 0xff)) | ((uint16_t)((uint8_t)(((uint32_t)(b8)) & 0xff))) << 8))

How to shift bytes from char array into int

I would like to make a int varibale out of a char array in C.
The char array looks like this:
buffer[0] = 0xcf
buffer[1] = 0x04
buffer[2] = 0x00
buffer[3] = 0x00
The shifting looks like this
x = (buffer[1] << 8 )| (buffer[0] << 0) ;
After that x looks like this:
x = 0xffff04cf
Right now everthing would be fine, if the first two bytes wouldn't be ff.
If I try this line
x = (buffer[3] << 24 )| (buffer[2] << 16)| (buffer[1] << 8)| (buffer[0] << 0) ;
it still looks
x = 0xffff04cf
Even when I try to shift in the zeros before or after I shift in 04cf it looks still the same.
Is this the rigth idea to it or what am I doing wrong?
The issue is that you declared buffer by means of a signed type, probably (signed) char. When applying operator <<, integral promotions will be performed, and as the value 0xcf in an 8-bit signed type represents a negative value (i.e. -49), it will remain a negative value (yet represented by more bits, i.e. 0xffffffcf). Note that -1 is represented as 0xFFFFFFFF and vice versa.
To overcome this issue, simply define buffer as
unsigned char buffer[4]
And if you weren't allowed to change the data type of buffer, you could write...
unsigned x = ( (unsigned char)buffer[0] << 8 )| ((unsigned char)buffer[1] << 4) ;
For tasks like this I like using unions, for example:
union tag_int_chars {
char buffer[sizeof(int32_t)];
int32_t value;
} int_chars;
int_chars.value = 0x01234567;
int_chars.buffer[0] = 0xff;
This will automate the memory overlay without the need to shift. Set the value of the int and voila the chars have changed, change a char value and voila the int has changed.
The example will leave the int value = 0x012345ff on a little endian machine.
Another easy way is to use memcpy():
#include <string.h>
char buffer[sizeof(int32_t)];
int32_t value;
memcpy(&value, buffer, sizeof(int32_t)); // chars to int
memcpy(buffer, &value, sizeof(int32_t)); // int to chars

How to extract 2 bytes from a word, and how to make a word from 2 bytes (in C)?

I am trying to extract two bytes from a 16-bit word, and to make a 16-bit word from two bytes. This is what I have tried (byte = unsigned char, word = unsigned short):
Split grpix word into 2 bytes:
word grpix; // Assume that the value has been initialized
byte grpixl = grpix & 0x00FF;
byte grpixh = grpix & 0xFF00;
Make grpix word from 2 bytes
byte grpixh; // Assume that the value has been initialized
byte grpixl; // Assume that the value has been initialized
word grpix = grpixh;
grpix <<= 8;
grpix += grpixl;
For some reason, my code doesn't work as expected, and now I'm not sure if the "splitting" of the word is wrong, if the "making" of the word is wrong, or both... Could you give me some advice?
You're not shifting when you split the word. So if grpix is 0x1234, then grpixl gets the expected 0x34 but grpixh ends up as 0x1200. You should say
byte grpixh = grpix >> 8;
Of course, you're also ignoring any endianness concerns that may be present. You should probably convert your word to a known endian (with something like htons()) before attempting to split (and do the reverse conversion when joining).
Get to know: http://graphics.stanford.edu/~seander/bithacks.html for doing all manner of operations.
right_byte = short_val & 0xFF;
left_byte = ( short_val >> 8 ) & 0xFF
short_val = ( ( left_byte & 0xFF ) << 8 ) | ( right_byte & 0xFF );
I always do a &0xFF mask to assure I have no sign problems.
The simple code that I use to solve this, is:
word=(msb<<8)+lsb;
The following routines have proved very reliable for me:-
unsigned short get16int(a) char *a;{
unsigned short hi,lo;
hi = *a++ << 8;
lo = *a & 0x00ff; /* Needed to cater for sign extending when msb bit is set */
return (hi | lo);
}
put16int(a,i) char *a; int i;{
*a++ = i >> 8;
*a = i;
}
When you mask out the high byte, you need to also shift down by 8 bits, otherwise you just end up with a 16bit number with the bottom eight bits cleared.
byte grpixh = (grpix & 0xFF00) >> 8
Also your composition can be more efficient by using or-equals instead of plus-equals:
grpix |= grpixh << 8
word grpix = grpixl+256*grpixh;

Resources