Writing on MSB and on LSB of an unsigned Char - c++

I have an unsigned char and i want to write 0x06 on the four most significant, and i want to write 0x04 on its 4 least significant bits.
So the Char representation should be like 0110 0010
Can some can guide me how i can do this in C?

c = (0x06 << 4) | 0x04;
Because:
0x04 = 0000 0100
0x06 = 0000 0110
0x06<<4 = 0110 0000
or op: = 0110 0100

Shift values into the right position with the bitwise shift operators, and combine with bitwise or.
unsigned char c = (0x6 << 4) | 0x4;
To reverse the process and extract bitfields, you can use bitwise and with a mask containing just the bits you're interested in:
unsigned char lo4 = c & 0xf;
unsigned char hi4 = c >> 4;

First, ensure there are eight bits per unsigned char:
#include <limits.h>
#if CHAR_BIT != 8
#error "This code does not support character sizes other than 8 bits."
#endif
Now, suppose you already have an unsigned char defined with:
unsigned char x;
Then, if you want to completely set an unsigned char to have 6 in the high four bits and 4 in the low four bits, use:
x = 0x64;
If you want to see the high bits to a and the low bits to b, then use:
// Shift a to high four bits and combine with b.
x = a << 4 | b;
If you want to set the high bits to a and leave the low bits unchanged, use:
// Shift a to high four bits, extract low four bits of x, and combine.
x = a << 4 | x & 0xf;
If you want to set the low bits to b and leave the high bits unchanged, use:
// Extract high four bits of x and combine with b.
x = x & 0xf0 | b;
The above presumes that a and b contain only four-bit values. If they might have other bits set, use (a & 0xf) and (b & 0xf) in place of a and b above, respectively.

Related

I need to understand the logic behind this cpp code

int x = 25;
unsigned int g = x & 0x80000000;
how did this code read the most significant bit of in the address of x? does the reference to 0x80000000, or binary 1000 0000 0000 0000 accomplished that task, or was it something else?
For char the most significant bit is typically the sign bit as per Two's Complement, so this should be:
char x = 25;
unsigned int msb = x & (1 << 6);
Where (1 << 6) means the 6 bit, counting from 0, or the 7th counting from 1st. It's the second-to-top bit and equivalent to 0x40.
Since 25 is 0b00011001 you won't get a bit set. You'll need a value >= 64.

Expanding packed nibbles to 5-bit groups

I currently have an un unsigned int of 64 bits that contains:
0100
0100
0100
0100
0000...
And i would change it to :
01000
01000
01000
01000
00000...
Is there a way to to do that ?
Thanks
📎 Hi! It looks like you are trying to expand 4-bit nibbles into 5-bit groups.
In general, you can do it like this
uint64_t value = YOUR_DATA; //this has your bits.
for (int i; i< sizeof(value)*2; i++) {
uint8_t nibble = (value & 0xF);
nibble <<= 1; //shift left 1 bit, add 0 to end.
STORE(nibble, i);
value>>=4; //advance to next nibble
}
This will call STORE once for each group of 4 bits. The arguments to STORE are the "expanded" 5 bit value, and the nibble counter, where 0 represents the least significant 4 bits.
The design question to answer is how to store the result? 64 bits / 4 * 5 = 80 bits, so you either need 2 words, or to throw away the data at one end.
Assuming 2 words with the anchor at the LSB, STORE could look like
static uint64_t result[2] = {0,0};
void STORE(uint64_t result[], uint8_t value, int n) {
int idx = (n>12); //which result word?
result[idx] |= value << ( n*5 - idx*64 );
if (n==12) result[1] |= value>>4; //65th bit goes into 2nd result word
}
Omit the leading 0, it serves no purpose => shift left one bit

How do you copy certain bits from a variable in c to another variable?

Say I have a long 64 bit integer that starts with these bits:
0100 0000 0110 1101 .... .... ....
And I want a specific integer to hold this value:
0b10000000110
Which, as you can see are bits 2 through 12 in the original number.
How can I do this with bitwise operations is this possible?
Something like this should work:
uint64_t input = <0100 0000 0110 1101 .... .... ....>
uint64_t mask = (uint64_t)0x7FF << 52;
uint64_t output = (input & mask) >> 52;
0x7ff is eleven bits: 11111111111. Shift it left 52 bits to get it where you want, use it to mask the input value, and shift the return value back 52 bits.

bitwise shifts, unsigned chars

Can anyone explain verbosely what this accomplishes? Im trying to learn c and am having a hard time wrapping my head around it.
void tonet_short(uint8_t *p, unsigned short s) {
p[0] = (s >> 8) & 0xff;
p[1] = s & 0xff;
}
void tonet_long(uint8_t *p, unsigned long l)
{
p[0] = (l >> 24) & 0xff;
p[1] = (l >> 16) & 0xff;
p[2] = (l >> 8) & 0xff;
p[3] = l & 0xff;
}
Verbosely, here it goes:
As a direct answer; both of them stores the bytes of a variable inside an array of bytes, from left to right. tonet_short does that for unsigned short variables, which consist of 2 bytes; and tonet_long does it for unsigned long variables, which consist of 4 bytes.
I will explain it for tonet_long, and tonet_short will just be the variation of it that you'll hopefully be able to derive yourself:
unsigned variables, when their bits are bitwise-shifted, get their bits shifted towards the determined side for determined amount of bits, and the vacated bits are made to be 0, zeros. I.e.:
unsigned char asd = 10; //which is 0000 1010 in basis 2
asd <<= 2; //shifts the bits of asd 2 times towards left
asd; //it is now 0010 1000 which is 40 in basis 10
Keep in mind that this is for unsigned variables, and these may be incorrect for signed variables.
The bitwise-and & operator compares the bits of two operands on both sides, returns a 1 (true) if both are 1 (true), and 0 (false) if any or both of them are 0 (false); and it does this for each bit. Example:
unsigned char asd = 10; //0000 1010
unsigned char qwe = 6; //0000 0110
asd & qwe; //0000 0010 <-- this is what it evaluates to, which is 2
Now that we know the bitwise-shift and bitwise-and, let's get to the first line of the function tonet_long:
p[0] = (l >> 24) & 0xff;
Here, since l is unsigned long, the (l >> 24) will be evaluated into the first 4 * 8 - 24 = 8 bits of the variable l, which is the first byte of the l. I can visualize the process like this:
abcd efgh ijkl mnop qrst uvwx yz.. .... //letters and dots stand for
//unknown zeros and ones
//shift this 24 times towards right
0000 0000 0000 0000 0000 0000 abcd efgh
Note that we do not change the l, this is just the evaluation of l >> 24, which is temporary.
Then the 0xff which is just 0000 0000 0000 0000 0000 0000 1111 1111 in hexadecimal (base 16), gets bitwise-anded with the bitwise-shifted l. It goes like this:
0000 0000 0000 0000 0000 0000 abcd efgh
&
0000 0000 0000 0000 0000 0000 1111 1111
=
0000 0000 0000 0000 0000 0000 abcd efgh
Since a & 1 will be simply dependent strictly on a, so it will be a; and same for the rest... It looks like a redundant operation for this, and it really is. It will, however, be important for the rest. This is because, for example, when you evaluate l >> 16, it looks like this:
0000 0000 0000 0000 abcd efgh ijkl mnop
Since we want only the ijkl mnop part, we have to discard the abcd efgh, and that will be done with the aid of 0000 0000 that 0xff has on its corresponding bits.
I hope this helps, the rest happens like it does this far, so... yeah.
These routines convert 16 and 32 bit values from native byte order to standard network(big-endian) byte order. They work by shifting and masking 8-bit chunks from the native value and storing them in order into a byte array.
If I see it right, I basically switches the order of bytes in the short and in the long ... (reverses the byte order of the number) and stores the result at an address which hopefully has enough space :)
explain verbosely - OK...
void tonet_short(uint8_t *p, unsigned short s) {
short is typically a 16-bit value (max: 0xFFFF)
The uint8_t is an unsigned 8-bit value, and p is a pointer to some number of unsigned 8-bit values (from the code we're assuming at least 2 sequential ones).
p[0] = (s >> 8) & 0xff;
This takes the "top half" of the value in s and puts it in the first element in the array p. So let's assume s==0x1234.
First s is shifted by 8 bits (s >> 8 == 0x0012)then it's AND'ed with 0xFF and the result is stored in p[0]. (p[0] == 0x12)
p[1] = s & 0xff;
Now note that when we did that shift, we never changed the original value of s, so s still has the original value of 0x1234, thus when we do this second line we simply do another bit-wise AND and p[1] get the "lower half" of the value of s (p[0] == 0x34)
The same applies for the other function you have there, but it's a long instead of a short, so we're assuming p in this case has enough space for all 32-bits (4x8) and we have to do some extra shifts too.
This code is used to serialize a 16-bit or 32-bit number into bytes (uint8_t). For example, to write them to disk, or to send them over a network connection.
A 16-bit value is split into two parts. One containing the most-significant (upper) 8 bits, the other containing least-significant (lower) 8 bits. The most-significant byte is stored first, then the least-significant byte. This is called big endian or "network" byte order. That's why the functions are named tonet_.
The same is done for the four bytes of a 32-bit value.
The & 0xff operations are actually useless. When a 16-bit or 32-bit value is converted to an 8-bit value, the lower 8 bits (0xff) are masked implicitly.
The bit-shifts are used to move the needed byte into the lowest 8 bits. Consider the bits of a 32-bit value:
AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD
The most significant byte are the 8 bits named A. In order to move them into the lowest 8 bits, the value has to be right-shifted by 24.
The names of the functions are a big hint... "to net short" and "to net long".
If you think about decimal... say we have a two pieces of paper so small we can only write one digit on each of them, we can therefore use both to record all the numbers from 0 to 99: 00, 01, 02... 08, 09, 10, 11... 18, 19, 20...98, 99. Basically, one piece of paper holds the "tens" column (given we're in base 10 for decimal), and the other the "units".
Memory works like that where each byte can store a number from 0..255, so we're working in base 256. If you have two bytes, one of them's going to be the "two-hundred-and-fifty-sixes" column, and the other the "units" column. To work out the combined value, you multiple the former by 256 and add the latter.
On paper we write numbers with the more significant ones on the left, but on a computer it's not clear if a more significant value should be in a higher or lower memory address, so different CPU manufacturers picked different conventions.
Consequently, some computers store 258 - which is 1 * 256 + 2 - as low=1 high=2, while others store low=2 high=1.
What these functions do is rearrange the memory from whatever your CPU happens to use to a predictable order - namely, the more significant value(s) go into the lower memory addresses, and eventually the "units" value is put into the highest memory address. This is a consistent way of storing the numbers that works across all computer types, so it's great when you want to transfer the data over the network; if the receiving computer uses a different memory ordering for the base-256 digits, it can move them from network byte ordering to whatever order it likes before interpreting them as CPU-native numbers.
So, "to net short" packs the most significant 8 bits of s into p[0] - the lower memory address. It didn't actually need to & 0xff as after taking the 16 input bits and shifting them 8 to the "right", all the left-hand 8 bits are guaranteed 0 anyway, which is the affect from & 0xFF - for example:
1010 1111 1011 0111 // = decimal 10*256^3 + 15*256^2 + 11*256 + 7
>>8 0000 0000 1010 1111 // move right 8, with left-hand values becoming 0
0xff 0000 0000 1111 1111 // we're going to and the above with this
& 0000 0000 1010 1111 // the bits that were on in both the above 2 values
// (the and never changes the value)

C++ copying integer to char[] or unsigned char[] error

So I'm using the following code to put an integer into a char[] or an unsigned char[]
(unsigned???) char test[12];
test[0] = (i >> 24) & 0xFF;
test[1] = (i >> 16) & 0xFF;
test[2] = (i >> 8) & 0xFF;
test[3] = (i >> 0) & 0xFF;
int j = test[3] + (test[2] << 8) + (test[1] << 16) + (test[0] << 24);
printf("Its value is...... %d", j);
When I use type unsigned char and value 1000000000 it prints correctly.
When I use type char (same value) I get 98315724 printed?
So, the question really is can anyone explain what the hell is going on??
Upon examining the binary for the two different numbers I still can't work out whats going on. I thought signed was when the MSB was set to 1 to indicate a negative value (but negative char? wth?)
I'm explicitly telling the buffer what to insert into it, and how to interpret the contents, so don't see why this could be happening.
I have included binary/hex below for clarity in what I examined.
11 1010 1001 1001 1100 1010 0000 0000 // Binary for 983157248
11 1011 1001 1010 1100 1010 0000 0000 // Binary for 1000000000
3 A 9 9 C A 0 0 // Hex for 983157248
3 B 9 A C A 0 0 // Hex for 1000000000
In addition to the answer by Kerrek SB please consider the following:
Computers (almost always) use something called twos-complement notation for negative numbers, with the high bit functioning as a 'negative' indicator. Ask yourself what happens when you perform shifts on a signed type considering that the computer will handle the signed bit specially.
You may want to read Why does left shift operation invoke Undefined Behaviour when the left side operand has negative value? right here on StackOverflow for a hint.
When you say i & 0xFF etc, you're creaing values in the range [0, 256). But (your) char has a range of [-128, +128), and so you cannot actually store those values sensibly (i.e. the behaviour is implementation defined and tedious to reason about).
Use unsigned char for unsigned values. The clue is in the name.
This all has to do with internal representation and the way each type uses that data to interpret it. In the internal representation of a signed character, the first bit of your byte holds the sign, the others, the value. when the first bit is 1, the number is negative, the following bits then represent the complement of the positive value. for example:
unsigned char c; // whose internal representation we will set at 1100 1011
c = (1 * 2^8) + (1 * 2^7) + (1 * 2^4) + (1 * 2^2) + (1 * 2^1);
cout << c; // will give 203
// inversely:
char d = c; // not unsigned
cout << d; // will print -53
// as if the first is 1, d is negative,
// and other bits complement of value its positive value
// 1100 1011 -> -(complement of 100 1011)
// the complement is an XOR +1 011 0101
// furthermore:
char e; // whose internal representation we will set at 011 0101
e = (1 * 2^6) + (1 * 2^5) + (1 * 3^2) + (1 * 2^1);
cout << e; // will print 53