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.
Related
I've a function that takes int8_t val and converts it to int7_t.
//Bit [7] reserved
//Bits [6:0] = signed -64 to +63 offset value
// user who calls this function will use it correctly (-64 to +63)
uint8_t func_int7_t(int8_t val){
uint8_t val_6 = val & 0b01111111;
if (val & 0x80)
val_6 |= 0x40;
//...
//do stuff...
return val_6;
}
What is the best and fastest way to manipulate the int8 to int7? Did I do it efficient and fast? or there is better way?
The target is ARM Cortex M0+ if that matters
UPDATE:
After reading different answers I can say the question was asked wrong? (or my code in the question is what gave wrong assumptions to others) I had the intension to make an int8 to int7
So it will be done by doing nothing because
8bit:
63 = 0011 1111
62 = 0011 1110
0 = 0000 0000
-1 = 1111 1111
-2 = 1111 1110
-63 = 1100 0001
-64 = 1100 0000
7bit:
63 = 011 1111
62 = 011 1110
0 = 000 0000
-1 = 111 1111
-2 = 111 1110
-63 = 100 0001
-64 = 100 0000
the faster way is probably :
uint8_t val_7 = (val & 0x3f) | ((val >> 1) & 0x40);
val & 0x3f get the 6 lower bits (truncate) and ((val >> 1) & 0x40) move the bit to sign from the position 8 to 7
The advantage to not use a if is to have a shorter code (even you can use arithmetic if) and to have a code without sequence break
To clear the reserved bit, just
return val & 0x7f;
To leave the reserved bit exactly like how it was from input, nothing needs to be done
return val;
and the low 7 bits will contain the values in [-64, 63]. Because in two's complement down casting is done by a simple truncation. The value remains the same. That's what happens for an assignment like (int8_t)some_int_value
There's no such thing as 0bX1100001. There's no undefined bit in machine language. That state only exists in hardware, like the high-Z state or undefined state in Verilog or other hardware description languages
Use bitfield to narrow the value and let compiler to choose what sequence of shifts and/or masks is most efficient for that on your platform.
inline uint8_t to7bit(int8_t x)
{
struct {uint8_t x:7;} s;
return s.x = x;
}
If you are not concerned about what happens to out-of-range values, then
return val & 0x7f;
is enough. This correctly handles values in the range -64 <= val <= 63.
You haven't said how you want to handle out-of-range values, so I have nothing to say about that.
Updated to add: The question has been updated so stipulate that the function will never be called with out-of-range values. So this method qualifies unambiguously as "best and fastest".
the user who calls this function he knows he should put data -64 to +63
So not considering any other values, the really fastest thing you can do is not doing anything at all!
You have a 7 bit value stored in eight bits. Any value within specified range will have both bit 7 and bit 6 the same value, and when you process the 7-bit value, you just ignore the MSB (of 8-bit value), no matter if set or not, e. g.:
for(unsigned int bit = 0x40; bit; bit >>= 1)
// NOT: 0x80!
std::cout << (value & bit);
The other way round is more critical: whenever you receive these seven bits via some communication channel, then you need to do manual sign extension for eight (or more) bits to be able to correctly use that value.
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
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.
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
I am having trouble understanding what is happening in the two lines with the 0xFF7F and the one below it. There is a link here that explains it to some degree.
http://www.herongyang.com/java/Bit-String-Set-Bit-to-Byte-Array.html
I don't know if 0xFF7F>>posBit) & oldByte) & 0x00FF
are supposed to be 3 values 'AND'ed together or how this is supposed to be read. If anyone can clarify what is happening here a little better, I would greatly appreciate it.
private static void setBit(byte[] data,
final int pos,
final int val) {
int posByte = pos/8;
int posBit = pos%8;
byte oldByte = data[posByte];
oldByte = (byte) (((0xFF7F>>posBit) & oldByte) & 0x00FF);
byte newByte = (byte) ((val<<(8-(posBit+1))) | oldByte);
data[posByte] = newByte;
}
passed into this method as parameters from a selectBits method was setBit(out,i,val);
out = is byte[] out = new byte[numOfBytes]; (numOfBytes can be 7 in this situation)
i = which is number [57], the original number from the PC1 int array holding the 56-integers.
val = which is the bit taken from the byte array from the getBit() method.
First of all 0xFF7F is 1111 1111 0111 1111. This is shifted right by an amount of bits calculated from the bit you pass as a parameter (so the one you want to set).
If you specify third bit posBit = 3 % 8 = 3 so
0xFF7F 1111 1111 0111 1111
>> 3 0001 1111 1110 1111
this value is then ANDed with the original byte you are modifying, the result is that every bit is kept equal to oldBit original bit except the one that is anded with the 0 bit, suppose you have for example oldByte == 0111 1010, you'll obtain:
0111 1010
& 1110 1111
-------------
0110 1010
Then the value is anded with 0xFF just to discard any bit that doesn't fit a byte (because it's at least the ninth bit) before doing the cast.
A better way to write this would be:
private static void setBit(byte[] data, int index, boolean value)
{
final int byteIndex = index / 8;
final int bitIndex = 7 - (index % 8);
final byte mask = (byte) (1 << bitIndex);
final byte valueBit = value ? mask : 0;
data[byteIndex] = (byte) ((data[byteIndex] & ~mask) | valueBit);
}