Concatenate two unsigned chars to be one uint16_t - c

I'm trying to right something that will take two unsigned chars and grab the 4 lower bits of one and concatenate that on to the front of the other 8 bits.
x = 01234567
y = 23458901
doBitWise = 890101234567
Is an example of what I'm looking for.
unsigned char x = someNumber;
unsigned char y = someNumber;
uint16_t result = (x & (1 << 4) - 1) | (y);
But that gives me a warning saying the result is going to be bigger than a uint16_t? Am I missing something?

The warning is because there is arithmetic conversions happening in the expression uint16_t result = (x & (1 << 4) - 1) | (y);. Here (1<<4)-1 will have type int, and x is of type unsigned char, according to the rules of conversion, the result will be of type int, which does not fit into a uint16_t on your platform.
Reference, c11 std 6.3.1.8 on Usual arithmetic conversions:
Otherwise, if the type of the operand with signed integer type can represent
all of the values of the type of the operand with unsigned integer type, then
the operand with unsigned integer type is converted to the type of the
operand with signed integer type.
To get the 4 lower bit of x, use x & 0xF. Also cast it to uint16_t before applying the shift operation,
uint16_t result = (uint16_t)(((x & 0xF) << 8) | y);
This will put the lower 4 bit of x ahead of y. The expression you used will or lower 4 bits of x with y, it does not do what you want.

Thats what Im wanting to do, just take the last 4 bits of y and put it with all of x. Making a 12 bit result
x = 01234567
y = 23458901
doBitWise = 890101234567
In that case, you should left shift the y by 8, and mask the front 4 bits:
uint16_t result = (((unsigned short)y << 8) & 0xF00) | x; //result will be casted to uint16_t
Note: be careful of the operator precedence. + comes before <<, thus parentheses is needed
Note 2: to prevent undefined behavior when int is 16-bit and to ensure that the result of y << 8 will be having at least 16-bit, explicit casting to unsigned short is added (since y is originally unsigned char). Besides, the inserting of x is using bitwise OR operator |.

As others have said the problem here is that before doing arithmetic, narrow integer types are converted to int, a signed type. But the solution to that should be much simpler, just force unsigned arithmetic:
uint16_t result = (x & (1U << 4) - 1U) | (y);
Here, the literals are unsigned, so is then the result of the <<, &, - and then | operators. This is because these operators, if presented with int and unsigned always do a conversion of the int part to unsigned.
For the final conversion from unsigned to uint16_t, this always well defined by modulo arithmetic and no sane compiler should complain about this.

Related

How to combine two hex value(High Value & Low Value) at two different array positions?

I received two hex values where at array[1] = lowbyte and at array[2] = highbyte where for my example lowbyte = 0xF4 and highbyte = 0x01 so the value will be in my example 1F4(500). So I want to combine these two values and compare but how do I do that without any library function?
Please help and sorry for my bad English.
I did some research and I found this as my solution and it seems to be working fine:
int temp = (short)(((HIGHBYTE) & 0xFF) << 8 | (LOWBYTE) & 0xFF);
Just a basic example showing how to combine values of two different variables into one:
#include <stdio.h>
int main (void)
{
char highbyte = 0x01;
unsigned char lowbyte = 0xF4; //Edited as per comments from #Fe2O3,
short int val = 0;
val = (highbyte << 8) | lowbyte; // If lowbyte declared as signed, then masking is required `lowbyte & 0xFF`
printf("0x%hx\n", val);
return 0;
}
Tested this on Linux PC.
Based on the answer where you converted to short, it seems you may want to combine the two bytes to produce a 16-bit two’s complement integer. This answer shows how to do that in three ways for which the behavior is fully defined by the C standard, as well as a fourth way that requires knowledge of the C implementation being used. Methods 1 and 3 are also defined in C++.
Given two eight-bit unsigned bytes with the more significant byte in highbyte and the less significant byte in lowbyte, four options for constructing the 16-bit two’s complement value they represent are:
Assemble the bytes in the desired order and copy them into an int16_t: uint16_t t = (uint16_t) highbyte << 8 | lowbyte; int16_t result; memcpy(&result, &t, sizeof result);.
Assemble the bytes in the desired order and use a union to reinterpret them: int16_t result = (union { uint16_t u; int16_t i; }) { (uint16_t) highbyte << 8 | lowbyte } .i;.
Construct the result arithmetically: int16_t result = ((highbyte ^ 128) - 128) * 256 + lowbyte;.
If it is given that the code will be used only with C implementations that define conversion to a signed integer to wrap, then a conversion may be used: int16_t result = (int16_t) ((uint16_t) highbyte << 8 | lowbyte);.
(In the last, the conversion to int16_t is implicit in the initialization, but a cast is used because, without it, some compilers will produce a warning or error, depending on switches.)
Note: int16_t and uint16_t are defined by including <stdint.h>. Alternatively, if it is given that short is 16 bits, then short and unsigned short may be used in place of int16_t and uint16_t.
Here is more information about the first three of these.
1. Assemble the bytes and copy
(uint16_t) highbyte << 8 | lowbyte converts to a type suitable for shifting without sign-bit issues, moves the more significant byte into the upper 8 bits of 16, and puts the less significant byte into the lower 8 bits.
Then uint16_t = …; puts those bits into a uint16_t.
memcpy(&result, &t, sizeof result); copies those bits into an int16_t. C 2018 7.20.1.1 1 guarantees that int16_t uses two’s complement. C 2018 6.2.6.2 2 guarantees that the value bits in int16_t have the same position values as their counterparts in uint16_t, so the copy produces the desired arrangement in result.
2. Assemble the bytes and use a union
(type) { initial value } is a compound literal. (union { uint16_t u; int16_t i; }) { (uint16_t) highbyte << 8 | lowbyte } makes a compound literal that is a union and initializes its u member to have the value described above. Then .i reads the i member of the union, which reinterprets the bits using the type int16_t, which is two’s complement as describe above. Then int16_t result = …; initializes result to this value.
3. Construct the result arithmetically
Here we start with the more significant byte separately, interpreting the eight bits of highbyte as two’s complement. In eight-bit two’s complement, the sign bit represents 0 if it is off and −128 if it is on. (For example, 111111002 as unsigned binary represents 128+64+32+16+8+4 =252, but, in two’s complement, it is −128+64+32+16+8+4 = −4.)
Consider highbyte ^ 128) - 128. If the first bit is off, ^ 128 turns it on, which adds 128 to its unsigned binary meaning. Then - 128 subtracts 128, producing a net effect of zero. If the first bit is on, ^ 128 turns it off, which cancels its unsigned binary meaning. Then - 128 gives the desired value. Thus (highbyte ^ 128) - 128 reinterprets the first bit to have a value of 0 if it is off and −128 if it is on.
Then ((highbyte ^ 128) - 128) * 256 moves this to the more significant byte of 16 bits (in an int type at this point), and + lowbyte puts the less significant byte in the less significant position. And of course int16_t result = …; initializes result to this computed value.

bits shift exceeding width of type in C [duplicate]

This question already has answers here:
warning: left shift count >= width of type
(6 answers)
Closed 1 year ago.
I have a uint64_t variable called vpn and I'm trying to get its left 9 bits.
I know vpn is 45 bits long, so I tried the following:
uint64_t nineMSB = (vpn & (511 << 36)) >> 36;
but I get the following warning:
left shift count >= width of type
Why is that? 511 is 9 ones in binary so 511 << 36 should give me 45 bits, and I'm doing an AND with a uint64_t so the result should not exceed 64 bits..
Thank you!
The constant 511 has type int. Your system most likely has a 32-bit int, so this means you're shifting a value by an amount larger than its bit length. Doing so triggers undefined behavior.
This is dictated by section 6.5.7p3 of the C standard regarding bitwise shift operators:
The integer promotions are performed on each of the operands. The type
of the result is that of the promoted left operand. If the
value of the right operand is negative or is greater than or
equal to the width of the promoted left operand, the behavior is
undefined.
You can fix this by using the ULL suffix on the constant, which will give it type unsigned long long which is guaranteed to be at least 64 bits in length.
uint64_t nineMSB = (vpn & (511ULL << 36)) >> 36;
integer constants without any suffixes or prefixes have type of int. On many systems int is 32bit long, but it can also be only 16bits long (avr port).
uint64_t foo(uint64_t vpn)
{
uint64_t nineMSB = (vpn & (511ULL << 36)) >> 36;
return nineMSB;
}
uint64_t foo1(uint64_t vpn)
{
uint64_t nineMSB = (vpn & ((uint64_t)511 << 36)) >> 36;
return nineMSB;
}

arithmetic right shift shifts in 0s when MSB is 1

As an exercise I have to write the following function:
multiply x by 2, saturating to Tmin / Tmax if overflow, using only bit-wise and bit-shift operations.
Now this is my code:
// xor MSB and 2nd MSB. if diferent, we have an overflow and SHOULD get 0xFFFFFFFF. otherwise we get 0.
int overflowmask = ((x & 0x80000000) ^ ((x & 0x40000000)<<1)) >>31;
// ^ this arithmetic bit shift seems to be wrong
// this gets you Tmin if x < 0 or Tmax if x >= 0
int overflowreplace = ((x>>31)^0x7FFFFFFF);
// if overflow, return x*2, otherwise overflowreplace
return ((x<<1) & ~overflowmask)|(overflowreplace & overflowmask);
now when overflowmask should be 0xFFFFFFFF, it is 1 instead, which means that the arithmetic bit shift >>31 shifted in 0s instead of 1s (MSB got XORed to 1, then shifted to the bottom).
x is signed and the MSB is 1, so according to C99 an arithmetic right shift should fill in 1s. What am I missing?
EDIT: I just guessed that this code isn't correct. To detect an overflow it suffices for the 2nd MSB to be 1.
However, I still wonder why the bit shift filled in 0s.
EDIT:
Example: x = 0xA0000000
x & 0x80000000 = 0x80000000
x & 0x40000000 = 0
XOR => 0x80000000
>>31 => 0x00000001
EDIT:
Solution:
int msb = x & 0x80000000;
int msb2 = (x & 0x40000000) <<1;
int overflowmask = (msb2 | (msb^msb2)) >>31;
int overflowreplace = (x >>31) ^ 0x7FFFFFFF;
return ((x<<1) & ~overflowmask) | (overflowreplace & overflowmask);
Even on twos-complement machines, the behaviour of right-shift (>>) on negative operands is implementation-defined.
A safer approach is to work with unsigned types and explicitly OR-in the MSB.
While you're at it, you probably also want to use fixed-width types (e.g. uint32_t) rather than failing on platforms that don't meet your expectations.
0x80000000 is treated as an unsigned number which causes everything to be converted to unsigned, You can do this:
// xor MSB and 2nd MSB. if diferent, we have an overflow and SHOULD get 0xFFFFFFFF. otherwise we get 0.
int overflowmask = ((x & (0x40000000 << 1)) ^ ((x & 0x40000000)<<1)) >>31;
// this gets you Tmin if x < 0 or Tmax if x >= 0
int overflowreplace = ((x>>31)^0x7FFFFFFF);
// if overflow, return x*2, otherwise overflowreplace
return ((x<<1) & ~overflowmask)|(overflowreplace & overflowmask);
OR write the constants in negative decimals
OR I would store all the constants in const int variables to have them guaranteed signed.
Never use bit-wise operands on signed types. In case of right shift on signed integers, it is up to the compiler if you get an arithmetic or a logical shift.
That's only one of your problems though. When you use a hex integer constant 0x80000000, it is actually of type unsigned int as explained here. This accidentally turns your whole expression (x & 0x80000000) ^ ... into unsigned type because of the integer promotion rule known as "the usual arithmetic conversions". Whereas the 0x40000000 expression is signed int and works as (the specific compiler) expected.
Solution:
All variables involved must be of type uint32_t.
All hex constants involved must be u suffixed.
To get something arithmetic shift portably, you would have to do
(x >> n) | (0xFFFFFFFFu << (32-n)) or some similar hack.

Manually adding a bitmask vs adding a bitwise shift

I am trying to add in a left-wise operator to replace the following:
unsigned long bitmask = 0b10000000000000000000000000000000;
printf("%lu\n", bitmask);
unsigned long bitmask2 = (1 << 31)-1;
printf("%lu\n", bitmask2);
However, the closest I'm able to get is -1. If I try doing (1 << 31), it looks like I get an overflow or something. What would be the proper way to do this?
# in the python shell
>>> 0b10000000000000000000000000000000
2147483648
>>> 1<<31
2147483648
>>> 0b10000000000000000000000000000000 == 1<<31
True
Since the type of the result of your shift is unsigned long, you should start with an unsigned long constant:
unsigned long bitmask2 = (1UL << 31) - 1;
Change
unsigned long bitmask2 = (1 << 31)-1;
to something like
unsigned long bitmask2 = (1UL << 31);
instead
The overflow was caused by you are bitwise shifting 31 places for 1 which exceed the boundary of a signed int. Please note that 1 is a signed int literal.
All integer constants like 1 have a type, in this case int. An int is signed and therefore has 31 data bits and 1 sign bit. You cannot left shift data into this sign bit - 1<<31 is a severe undefined behavior bug.
As a rule of thumb, never mix signed operands with bitwise operators. You can fix the bug by adding a 'u' suffix to the integer constant: 1u << 31. Now the type is unsigned int instead, 32 data bits.
Please note that the resulting type of a shift operation is that of the left operand. So there is no need to write for example 1u << 31u.

Getting four bits from the right only in a byte using bit shift operations

I wanted to try to get only the four bits from the right in a byte by using only bit shift operations but it sometimes worked and sometimes not, but I don't understand why.
Here's an example:
unsigned char b = foo; //say foo is 1000 1010
unsigned char temp=0u;
temp |= ((b << 4) >> 4);//I want this to be 00001010
PS: I know I can use a mask=F and do temp =(mask&=b).
Shift operator only only works on integral types. Using << causes implicit integral promotion, type casting b to an int and "protecting" the higher bits.
To solve, use temp = ((unsigned char)(b << 4)) >> 4;

Resources