Related
I have a decimal number that I need to manipulate 4 bits in with a given shift.
For example, if the number is 208, or 11010000 binary, and I want to change 4 bits to 1101 with a shift of 2. The new number will be 244.
When the change was: 11110100.
Here's my code:
void change_bit(int num, int bit, int shift)
{
num = (num & (0xfffffff0<<shift)) | (bit << shift);
printf("%d\n", num);
}
The shifting of 0xfffffff0 just adds '0' to the left size.
How can I fix it?
It is easier if you split complex expressions into smaller bits. It does not affect the efficiency of the code but it will be much easier for you read and understand.
unsigned change_bit(unsigned num, unsigned bit, int shift)
{
unsigned mask = ((1U << 4) - 1) << shift; // mask to reset the bits at the position
num &= ~mask; //reset the bits
num |= bit << shift; //set the bits
return num;
}
or more generally
unsigned change_bit(unsigned num, unsigned newval, int shift, int numbits)
{
unsigned mask = ((1 << numbits) - 1) << shift;
num &= ~mask;
num |= newval << shift;
return num;
}
and some test code:
void print(unsigned val)
{
for(unsigned x = 1U << 31; x ; x >>= 1)
{
printf("%d", !!(val & x));
}
printf("\n");
}
int main(void)
{
print(208);
print(change_bit(208, 0b1101, 2));
printf("%d\n", change_bit(208, 0b1101, 2));
}
You should also add some parameters checks.
I just want to ask if my method is correct to convert from little endian to big endian, just to make sure if I understand the difference.
I have a number which is stored in little-endian, here are the binary and hex representations of the number:
0001 0010 0011 0100 0101 0110 0111 1000
12345678
In big-endian format I believe the bytes should be swapped, like this:
1000 0111 0110 0101 0100 0011 0010 0001
87654321
Is this correct?
Also, the code below attempts to do this but fails. Is there anything obviously wrong or can I optimize something? If the code is bad for this conversion can you please explain why and show a better method of performing the same conversion?
uint32_t num = 0x12345678;
uint32_t b0,b1,b2,b3,b4,b5,b6,b7;
uint32_t res = 0;
b0 = (num & 0xf) << 28;
b1 = (num & 0xf0) << 24;
b2 = (num & 0xf00) << 20;
b3 = (num & 0xf000) << 16;
b4 = (num & 0xf0000) << 12;
b5 = (num & 0xf00000) << 8;
b6 = (num & 0xf000000) << 4;
b7 = (num & 0xf0000000) << 4;
res = b0 + b1 + b2 + b3 + b4 + b5 + b6 + b7;
printf("%d\n", res);
OP's sample code is incorrect.
Endian conversion works at the bit and 8-bit byte level. Most endian issues deal with the byte level. OP's code is doing a endian change at the 4-bit nibble level. Recommend instead:
// Swap endian (big to little) or (little to big)
uint32_t num = 9;
uint32_t b0,b1,b2,b3;
uint32_t res;
b0 = (num & 0x000000ff) << 24u;
b1 = (num & 0x0000ff00) << 8u;
b2 = (num & 0x00ff0000) >> 8u;
b3 = (num & 0xff000000) >> 24u;
res = b0 | b1 | b2 | b3;
printf("%" PRIX32 "\n", res);
If performance is truly important, the particular processor would need to be known. Otherwise, leave it to the compiler.
[Edit] OP added a comment that changes things.
"32bit numerical value represented by the hexadecimal representation (st uv wx yz) shall be recorded in a four-byte field as (st uv wx yz)."
It appears in this case, the endian of the 32-bit number is unknown and the result needs to be store in memory in little endian order.
uint32_t num = 9;
uint8_t b[4];
b[0] = (uint8_t) (num >> 0u);
b[1] = (uint8_t) (num >> 8u);
b[2] = (uint8_t) (num >> 16u);
b[3] = (uint8_t) (num >> 24u);
[2016 Edit] Simplification
... The type of the result is that of the promoted left operand.... Bitwise shift operators C11 §6.5.7 3
Using a u after the shift constants (right operands) results in the same as without it.
b3 = (num & 0xff000000) >> 24u;
b[3] = (uint8_t) (num >> 24u);
// same as
b3 = (num & 0xff000000) >> 24;
b[3] = (uint8_t) (num >> 24);
Sorry, my answer is a bit too late, but it seems nobody mentioned built-in functions to reverse byte order, which in very important in terms of performance.
Most of the modern processors are little-endian, while all network protocols are big-endian. That is history and more on that you can find on Wikipedia. But that means our processors convert between little- and big-endian millions of times while we browse the Internet.
That is why most architectures have a dedicated processor instructions to facilitate this task. For x86 architectures there is BSWAP instruction, and for ARMs there is REV. This is the most efficient way to reverse byte order.
To avoid assembly in our C code, we can use built-ins instead. For GCC there is __builtin_bswap32() function and for Visual C++ there is _byteswap_ulong(). Those function will generate just one processor instruction on most architectures.
Here is an example:
#include <stdio.h>
#include <inttypes.h>
int main()
{
uint32_t le = 0x12345678;
uint32_t be = __builtin_bswap32(le);
printf("Little-endian: 0x%" PRIx32 "\n", le);
printf("Big-endian: 0x%" PRIx32 "\n", be);
return 0;
}
Here is the output it produces:
Little-endian: 0x12345678
Big-endian: 0x78563412
And here is the disassembly (without optimization, i.e. -O0):
uint32_t be = __builtin_bswap32(le);
0x0000000000400535 <+15>: mov -0x8(%rbp),%eax
0x0000000000400538 <+18>: bswap %eax
0x000000000040053a <+20>: mov %eax,-0x4(%rbp)
There is just one BSWAP instruction indeed.
So, if we do care about the performance, we should use those built-in functions instead of any other method of byte reversing. Just my 2 cents.
I think you can use function htonl(). Network byte order is big endian.
"I swap each bytes right?" -> yes, to convert between little and big endian, you just give the bytes the opposite order.
But at first realize few things:
size of uint32_t is 32bits, which is 4 bytes, which is 8 HEX digits
mask 0xf retrieves the 4 least significant bits, to retrieve 8 bits, you need 0xff
so in case you want to swap the order of 4 bytes with that kind of masks, you could:
uint32_t res = 0;
b0 = (num & 0xff) << 24; ; least significant to most significant
b1 = (num & 0xff00) << 8; ; 2nd least sig. to 2nd most sig.
b2 = (num & 0xff0000) >> 8; ; 2nd most sig. to 2nd least sig.
b3 = (num & 0xff000000) >> 24; ; most sig. to least sig.
res = b0 | b1 | b2 | b3 ;
You could do this:
int x = 0x12345678;
x = ( x >> 24 ) | (( x << 8) & 0x00ff0000 )| ((x >> 8) & 0x0000ff00) | ( x << 24) ;
printf("value = %x", x); // x will be printed as 0x78563412
One slightly different way of tackling this that can sometimes be useful is to have a union of the sixteen or thirty-two bit value and an array of chars. I've just been doing this when getting serial messages that come in with big endian order, yet am working on a little endian micro.
union MessageLengthUnion
{
uint16_t asInt;
uint8_t asChars[2];
};
Then when I get the messages in I put the first received uint8 in .asChars[1], the second in .asChars[0] then I access it as the .asInt part of the union in the rest of my program.
If you have a thirty-two bit value to store you can have the array four long.
I am assuming you are on linux
Include "byteswap.h" & Use int32_t bswap_32(int32_t argument);
It is logical view, In actual see, /usr/include/byteswap.h
one more suggestion :
unsigned int a = 0xABCDEF23;
a = ((a&(0x0000FFFF)) << 16) | ((a&(0xFFFF0000)) >> 16);
a = ((a&(0x00FF00FF)) << 8) | ((a&(0xFF00FF00)) >>8);
printf("%0x\n",a);
A Simple C program to convert from little to big
#include <stdio.h>
int main() {
unsigned int little=0x1234ABCD,big=0;
unsigned char tmp=0,l;
printf(" Little endian little=%x\n",little);
for(l=0;l < 4;l++)
{
tmp=0;
tmp = little | tmp;
big = tmp | (big << 8);
little = little >> 8;
}
printf(" Big endian big=%x\n",big);
return 0;
}
OP's code is incorrect for the following reasons:
The swaps are being performed on a nibble (4-bit) boundary, instead of a byte (8-bit) boundary.
The shift-left << operations of the final four swaps are incorrect, they should be shift-right >> operations and their shift values would also need to be corrected.
The use of intermediary storage is unnecessary, and the code can therefore be rewritten to be more concise/recognizable. In doing so, some compilers will be able to better-optimize the code by recognizing the oft-used pattern.
Consider the following code, which efficiently converts an unsigned value:
// Swap endian (big to little) or (little to big)
uint32_t num = 0x12345678;
uint32_t res =
((num & 0x000000FF) << 24) |
((num & 0x0000FF00) << 8) |
((num & 0x00FF0000) >> 8) |
((num & 0xFF000000) >> 24);
printf("%0x\n", res);
The result is represented here in both binary and hex, notice how the bytes have swapped:
0111 1000 0101 0110 0011 0100 0001 0010
78563412
Optimizing
In terms of performance, leave it to the compiler to optimize your code when possible. You should avoid unnecessary data structures like arrays for simple algorithms like this, doing so will usually cause different instruction behavior such as accessing RAM instead of using CPU registers.
#include <stdio.h>
#include <inttypes.h>
uint32_t le_to_be(uint32_t num) {
uint8_t b[4] = {0};
*(uint32_t*)b = num;
uint8_t tmp = 0;
tmp = b[0];
b[0] = b[3];
b[3] = tmp;
tmp = b[1];
b[1] = b[2];
b[2] = tmp;
return *(uint32_t*)b;
}
int main()
{
printf("big endian value is %x\n", le_to_be(0xabcdef98));
return 0;
}
You can use the lib functions. They boil down to assembly, but if you are open to alternate implementations in C, here they are (assuming int is 32-bits) :
void byte_swap16(unsigned short int *pVal16) {
//#define method_one 1
// #define method_two 1
#define method_three 1
#ifdef method_one
unsigned char *pByte;
pByte = (unsigned char *) pVal16;
*pVal16 = (pByte[0] << 8) | pByte[1];
#endif
#ifdef method_two
unsigned char *pByte0;
unsigned char *pByte1;
pByte0 = (unsigned char *) pVal16;
pByte1 = pByte0 + 1;
*pByte0 = *pByte0 ^ *pByte1;
*pByte1 = *pByte0 ^ *pByte1;
*pByte0 = *pByte0 ^ *pByte1;
#endif
#ifdef method_three
unsigned char *pByte;
pByte = (unsigned char *) pVal16;
pByte[0] = pByte[0] ^ pByte[1];
pByte[1] = pByte[0] ^ pByte[1];
pByte[0] = pByte[0] ^ pByte[1];
#endif
}
void byte_swap32(unsigned int *pVal32) {
#ifdef method_one
unsigned char *pByte;
// 0x1234 5678 --> 0x7856 3412
pByte = (unsigned char *) pVal32;
*pVal32 = ( pByte[0] << 24 ) | (pByte[1] << 16) | (pByte[2] << 8) | ( pByte[3] );
#endif
#if defined(method_two) || defined (method_three)
unsigned char *pByte;
pByte = (unsigned char *) pVal32;
// move lsb to msb
pByte[0] = pByte[0] ^ pByte[3];
pByte[3] = pByte[0] ^ pByte[3];
pByte[0] = pByte[0] ^ pByte[3];
// move lsb to msb
pByte[1] = pByte[1] ^ pByte[2];
pByte[2] = pByte[1] ^ pByte[2];
pByte[1] = pByte[1] ^ pByte[2];
#endif
}
And the usage is performed like so:
unsigned short int u16Val = 0x1234;
byte_swap16(&u16Val);
unsigned int u32Val = 0x12345678;
byte_swap32(&u32Val);
Below is an other approach that was useful for me
convertLittleEndianByteArrayToBigEndianByteArray (byte littlendianByte[], byte bigEndianByte[], int ArraySize){
int i =0;
for(i =0;i<ArraySize;i++){
bigEndianByte[i] = (littlendianByte[ArraySize-i-1] << 7 & 0x80) | (littlendianByte[ArraySize-i-1] << 5 & 0x40) |
(littlendianByte[ArraySize-i-1] << 3 & 0x20) | (littlendianByte[ArraySize-i-1] << 1 & 0x10) |
(littlendianByte[ArraySize-i-1] >>1 & 0x08) | (littlendianByte[ArraySize-i-1] >> 3 & 0x04) |
(littlendianByte[ArraySize-i-1] >>5 & 0x02) | (littlendianByte[ArraySize-i-1] >> 7 & 0x01) ;
}
}
Below program produce the result as needed:
#include <stdio.h>
unsigned int Little_To_Big_Endian(unsigned int num);
int main( )
{
int num = 0x11223344 ;
printf("\n Little_Endian = 0x%X\n",num);
printf("\n Big_Endian = 0x%X\n",Little_To_Big_Endian(num));
}
unsigned int Little_To_Big_Endian(unsigned int num)
{
return (((num >> 24) & 0x000000ff) | ((num >> 8) & 0x0000ff00) | ((num << 8) & 0x00ff0000) | ((num << 24) & 0xff000000));
}
And also below function can be used:
unsigned int Little_To_Big_Endian(unsigned int num)
{
return (((num & 0x000000ff) << 24) | ((num & 0x0000ff00) << 8 ) | ((num & 0x00ff0000) >> 8) | ((num & 0xff000000) >> 24 ));
}
#include<stdio.h>
int main(){
int var = 0X12345678;
var = ((0X000000FF & var)<<24)|
((0X0000FF00 & var)<<8) |
((0X00FF0000 & var)>>8) |
((0XFF000000 & var)>>24);
printf("%x",var);
}
Here is a little function I wrote that works pretty good, its probably not portable to every single machine or as fast a single cpu instruction, but should work for most. It can handle numbers up to 32 byte (256 bit) and works for both big and little endian swaps. The nicest part about this function is you can point it into a byte array coming off or going on the wire and swap the bytes inline before converting.
#include <stdio.h>
#include <string.h>
void byteSwap(char**,int);
int main() {
//32 bit
int test32 = 0x12345678;
printf("\n BigEndian = 0x%X\n",test32);
char* pTest32 = (char*) &test32;
//convert to little endian
byteSwap((char**)&pTest32, 4);
printf("\n LittleEndian = 0x%X\n", test32);
//64 bit
long int test64 = 0x1234567891234567LL;
printf("\n BigEndian = 0x%lx\n",test64);
char* pTest64 = (char*) &test64;
//convert to little endian
byteSwap((char**)&pTest64,8);
printf("\n LittleEndian = 0x%lx\n",test64);
//back to big endian
byteSwap((char**)&pTest64,8);
printf("\n BigEndian = 0x%lx\n",test64);
return 0;
}
void byteSwap(char** src,int size) {
int x = 0;
char b[32];
while(size-- >= 0) { b[x++] = (*src)[size]; };
memcpy(*src,&b,x);
}
output:
$gcc -o main *.c -lm
$main
BigEndian = 0x12345678
LittleEndian = 0x78563412
BigEndian = 0x1234567891234567
LittleEndian = 0x6745239178563412
BigEndian = 0x1234567891234567
Is there a way to use the fwrite method to read into a variable (a dynamic array) instead of a FILE *, or some alternative method that lets me do this? I need to read a binary file containing 16 bit chunks, but only read the last 12 bits of each chunk. Ideally I want something like:
fwrite(&(x+4),sizeof(x)-4,1,var);
But currently, I cant write into a var directly, only a file.
I know its possible using bitmasks/bitops, but this is a much simpler way so I'd prefer to use it if possible.
No, fwrite writes to something that an be accessed like a file (FILE*).
Perhaps you want to use sprintf to format data into a string?
Read 16 bits. Assuming CHAR_BIT is 8 (the usual) that's 2 bytes:
size_t chk;
unsigned char data16[2];
chk = fread(data16, 2, 1, file);
if (chk != 1) {
/* handle error */
}
Now, depending on endianness issues, just ignore the right 4 of those 16 bits read:
data16 has, for instance: 01000101 11101011 (data16[0] == 0x45; data16[1] == 0xeb)
and you want these bits: ^^^^^.^^ ^..^^^.^
so ... mask and shift!
/* mask and shift, bit by bit */
data12[0] = 0;
data12[0] |= !!(data16[0] & (1 << 7)) << 3;
data12[0] |= !!(data16[0] & (1 << 6)) << 2;
data12[0] |= !!(data16[0] & (1 << 5)) << 1;
data12[0] |= !!(data16[0] & (1 << 4)) << 0;
data12[1] = 0;
data12[1] |= !!(data16[0] & (1 << 3)) << 7;
data12[1] |= !!(data16[0] & (1 << 1)) << 6;
data12[1] |= !!(data16[0] & (1 << 0)) << 5;
data12[1] |= !!(data16[1] & (1 << 7)) << 4;
data12[1] |= !!(data16[1] & (1 << 4)) << 3;
data12[1] |= !!(data16[1] & (1 << 3)) << 2;
data12[1] |= !!(data16[1] & (1 << 2)) << 1;
data12[1] |= !!(data16[1] & (1 << 0)) << 0;
EDITED TO ADD BETTER ANSWER
From the comments, it looks like you want to compress a buffer -- an array of 16-bit ints by stripping off 4 bits and packing them together, right?
This code should do the trick:
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <stdio.h>
typedef unsigned int UINT32 ;
typedef unsigned short UINT16 ;
void compress( UINT16 *buf , int *cnt )
{
UINT16 *src = buf ; // where we're copying from
UINT16 *tgt = buf ; // where we're copying to
UINT16 *limit = buf + *cnt ; // endpoint address
UINT16 bits = 0x0000 ;
int state = 0 ;
while ( src < limit )
{
switch ( state )
{
case 0 :
bits = (*src++ & 0x0FFF ) << 4 ;
state = 1 ;
break ;
case 1 :
bits |= (*src & 0x0F00 ) >> 8 ;
*tgt++ = bits ;
bits = (*src++ & 0x00FF ) << 8 ;
state = 2 ;
break ;
case 2 :
bits |= (*src & 0x0FF0 ) >> 4 ;
*tgt++ = bits ;
bits = (*src++ & 0x000F ) << 12 ;
state = 3 ;
break ;
case 3 :
bits |= (*src++ & 0x0FFF ) ;
*tgt++ = bits ;
bits = 0x000 ;
state = 0 ;
break ;
}
}
if ( state != 0 )
{
*tgt++ = bits ;
}
// hand back the new size ;
*cnt = (tgt - buf ) ;
while ( tgt < limit )
{
*tgt++ = 0x0000 ;
}
return ;
}
int main( int argc, char* argv[])
{
UINT16 buf[] = { 0xF123 , 0xE456 , 0xD789 , 0xCABC , 0xBDEF , } ;
int bufl = sizeof(buf) / sizeof(*buf) ;
compress( buf , &bufl ) ;
// buf now looks like { 0x1234 , 0x5678 , 0x9ABC , 0xDEF0 , 0x0000 }
return 0 ;
}
ORIGINAL ANSWER
If you actually wantg to read 16-bit structures from a file and that have 12 interesting bits and 4 unused (or not very interesting) bits, and you want to avoid bit-twiddling, you can use bit fields.
Note that implementations get a lot of leeway under the standard for how this stuff works, so it's not portable in the least: you'll probably need to tweak structure alignment and possibly field order, depending on the underlying CPU. You'll note my use of #pragma pack(2) to coerce the structure into a 16-bit size — that works in Visual Studio 2010 C++. YMMV and all that.
[You sure you don't want to just mask off the bits you don't want?]
At any rate, once you deal with all that, something like the following code should work for you:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#pragma pack(2) // necessary to get correct alignment
typedef struct
{
unsigned short unused : 4 ;
unsigned short value : 12 ;
} CHUNK ;
#define BUFFER_CHUNKS ((size_t)8192)
void process( FILE*input )
{
CHUNK *buf = (CHUNK*) calloc( BUFFER_CHUNKS , sizeof(CHUNK) ) ;
size_t bufl = BUFFER_CHUNKS * sizeof(CHUNK) ;
int chunks = 0 ;
while ( 0 > (chunks=(int)fread( (void*)buf , sizeof(CHUNK) , BUFFER_CHUNKS , input ) ) )
{
for ( int i = 0 ; i < chunks ; ++i )
{
int value = buf[i].value ;
printf( "%d: %d\n" , i , value ) ;
}
}
return ;
}
Good Luck!
C is byte oriented, not bit oriented.
read two 16 bit ints and combine them to 24 bits (3 bytes) by shaving off the top 4 bits.
for(;;) {
uint8_t current;
uint16_t d[2];
if(fread(d,sizeof d,2,my_file) != 2) //convert the int if it's in the
//oposite endian of your host.
return;
current = (d[0] & 0xff0) >> 4) ;
if(fwrite(¤t,1,1,my_outfile) != 1) //or store it in an array.
return;
current = (d[0] & 0xf) << 4;
current |= (d[1] & 0xf00) >> 8) ;
if(fwrite(¤t,1,1,my_outfile) != 1) //or store it in an array.
return;
current = d[1] & 0xff;
if(fwrite(¤t,1,1,my_outfile) != 1) //or store it in an array.
return;
}
Alternativly read them one 16 bit int at a time:
int state = 0;
uint8_t current;
for(;;) {
uint16_t d;
if(fread(&d,sizeof d,1,my_file) != 1) //convert the int if it's in the
//oposite endian of your host.
return;
switch(state)
case 0:
current = (d & 0xff0) >> 4) ;
if(fwrite(¤t,1,1,my_outfile) != 1) //or store it in an array.
return;
current = (d & 0xf) << 4;
state = 1;
break;
case 1;
current |= (d & 0xf00) >> 8) ;
if(fwrite(¤t,1,1,my_outfile) != 1) //or store it in an array.
return;
current = d & 0xff;
if(fwrite(¤t,1,1,my_outfile) != 1) //or store it in an array.
return;
state = 0;
break;
}
}
I have two bytes, 8 bit octets, which should be read as: [3 bits][4 bits][3 bits].
Example:
unsigned char octet1 = 0b11111111; // binary values
unsigned char octet2 = 0b00000011;
As integers: [7][15][7].
Anybody can give me a hint where to start?
In a kind of pseudocode
octet1 = 0b11111111
octet2 = 0b00000011
word = octet1 | octet2<<8
n1 = word & 0b111
n2 = word>>3 & 0b1111
n3 = word>>7 & 0b111
Hi here is a method that is tested and compiled using VC++9
#pragma pack( 1 )
union
{
struct
{
unsigned short val1:3;
unsigned short val2:4;
unsigned short val3:3;
unsigned short val4:6;
} vals;
struct
{
unsigned char octet1:8;
unsigned char octet2:8;
} octets;
short oneVal;
} u = {0xFFFF};
unsigned char octet1 = 0xFF; //1 1111 111
unsigned char octet2 = 0x03; //000000 11
//000000 111 1111 111 0 7 15 7
u.octets.octet1 = octet1;
u.octets.octet2 = octet2;
cout << "size of u.vals:" << sizeof(u.vals)<< endl;
cout << "size of u.octets:" << sizeof(u.octets)<< endl;
cout << "size of u.oneVal:" << sizeof(u.oneVal)<< endl;
cout << "size of u:" << sizeof(u)<< endl;
cout << endl;
cout << "Your values:" << endl;
cout << "oneVal in Hex: 0x";
cout.fill( '0' );
cout.width( 4 );
cout<< hex << uppercase << u.oneVal << endl;
cout << "val1: " << (int)u.vals.val1 << endl;
cout << "val2: " << (int)u.vals.val2 << endl;
cout << "val3: " << (int)u.vals.val3 << endl;
cout << "val4: " << (int)u.vals.val4 << endl;
cout << endl;
octet1 = 0xCC; //1 1001 100
octet2 = 0xFA; //111110 10
//111110 101 1001 100 62 5 9 4
u.octets.octet1 = octet1;
u.octets.octet2 = octet2;
cout << "Some other values:" << endl;
cout << "oneVal in Hex: 0x";
cout.fill( '0' );
cout.width( 4 );
cout<< hex << uppercase << u.oneVal << endl;
cout << dec;
cout << "val1: " << (int)u.vals.val1 << endl;
cout << "val2: " << (int)u.vals.val2 << endl;
cout << "val3: " << (int)u.vals.val3 << endl;
cout << "val4: " << (int)u.vals.val4 << endl;
cout << endl;
octet1 = 0xCC; //1 1001 100
octet2 = 0xFA; //111110 10
//111110 101 1001 100 62 5 9 4
u.oneVal = ( (( unsigned short )octet2 ) << 8 ) | ( unsigned short )octet1;
cout << "Some thing diffrent asignment:" << endl;
cout << "oneVal in Hex: 0x";
cout.fill( '0' );
cout.width( 4 );
cout<< hex << uppercase << u.oneVal << endl;
cout << dec;
cout << "val1: " << (int)u.vals.val1 << endl;
cout << "val2: " << (int)u.vals.val2 << endl;
cout << "val3: " << (int)u.vals.val3 << endl;
cout << "val4: " << (int)u.vals.val4 << endl;
cout << endl;
Also note that I uses #pragma pack( 1 ) to set the structure packing to 1 byte.
I also included a way of assigning the two octets into the one short value. Did this using bitwise shift "<<" and bitwise or "|"
You can simplify the access to u by dropping the named structures. But I wanted to show the sizes that is used for the structures.
Like this:
union
{
struct
{
unsigned short val1:3;
unsigned short val2:4;
unsigned short val3:3;
unsigned short val4:6;
};
struct
{
unsigned char octet1:8;
unsigned char octet2:8;
};
short oneVal;
} u = {0xFFFF};
Access would now be as simple as
u.oneVal = 0xFACC;
or
u.octet1 = 0xCC;
u.octet2 = 0xFA;
you can also drop either oneVal or octet1 and octet2 depending on what access method you like.
No need to put the two bytes together before extracting bits we want.
#include <stdio.h>
main()
{
unsigned char octet1 = 0b11111111;
unsigned char octet2 = 0b00000011;
unsigned char n1 = octet1 & 0b111;
unsigned char n2 = (octet1 >> 3) & 0b1111;
unsigned char n3 = (octet1 >> 7) | (octet2 + octet2);
printf("octet1=%u octet2=%u n1=%u n2=%u n3=%u\n",
octet1, octet2, n1, n2, n3);
}
oct2| oct1
000011|1 1111 111
---- ---- ---
7 0xf 7
Just a hint,(assuming it is homework)
Note: 0x11111111 doesn't mean 8 bits all set to 1. It's an hexadecimal number of 4 bytes, where any byte is set to 0x11.
0xFF is a single byte (8 bit) where any bit is set to 1.
Then, to achieve what you want you could use some MACROs to isolate the bits you need:
#define TOKEN1(x) ((x)>>7)
#define TOKEN2(x) ( ((x)>>3) & (0xFF>>5) )
#define TOKEN3(x) ( ((x)>>5) & (0xFF>>5) )
Didn't test it.
Another idea, could be that of putting in an union a char and a struct using bitfield chars
union {
struct { char a:3; char b:4; char c:3; };
char x;
};
This way you can use x to edit the whole octet, and a, b and c to access to the single tokens...
Edit: 3+4+3 != 8.
If you need 10 bits you should use a short instead of a char. If, instead, some of those bits are overlapping, the solution using MACRO will probably be easier: you'll need more than one struct inside the union to achieve the same result with the second solution...
You can use boolean opeations to get and set the individual values.
It's unclear which bits of your octets apply to which values but you only need & (bitwise AND), | (bitwise OR), << (left shift) and >> (right shift) to do this.
Start from writing a packing/unpacking functions for your 2-byte hybrids.
If you so the work with C/C++ - you may use the intrinsic support for this:
struct Int3 {
int a : 3;
int b : 4;
int c : 3;
};
Bitfields could be one option. You may need to pad your struct to get the bits to line up the way you want them to.
Refer to Bitfields in C++ or search StackOverflow for C++ and bitfields or you can use bitwise operators as outline in the other answers.
Do you mean, if we "concatenate" octets as octet2.octet1, we will get 000000[111][1111][111]?
Then you may use bit operations:
">>" and "<<" to shift bits in your value,
"&" to mask bits
"+" to combine values
For example, "middle" value (which is 4-bits-length) may be received in the following way:
middle = 15 & (octet1 >> 3);
assert(CHAR_BIT == 8);
unsigned int twooctets = (octet2 << 8) | (octet1); /* thanks, Jonas */
unsigned int bits0to2 = (twooctets & /* 0b0000_0000_0111 */ 0x007) >> 0;
unsigned int bits3to6 = (twooctets & /* 0b0000_0111_1000 */ 0x078) >> 3;
unsigned int bits7to9 = (twooctets & /* 0b0011_1000_0000 */ 0x380) >> 7;
I have an array of four unsigned chars. I want to treat it like a 32-bit number (assume the upper bits of the char are don't care. I only care about the lower 8-bits). Then, I want to circularly shift it by an arbitrary number of places. I've got a few different shift sizes, all determined at compile-time.
E.g.
unsigned char a[4] = {0x81, 0x1, 0x1, 0x2};
circular_left_shift(a, 1);
/* a is now { 0x2, 0x2, 0x2, 0x5 } */
Edit: To everyone wondering why I didn't mention CHAR_BIT != 8, because this is standard C. I didn't specify a platform, so why are you assuming one?
static void rotate_left(uint8_t *d, uint8_t *s, uint8_t bits)
{
const uint8_t octetshifts = bits / 8;
const uint8_t bitshift = bits % 8;
const uint8_t bitsleft = (8 - bitshift);
const uint8_t lm = (1 << bitshift) - 1;
const uint8_t um = ~lm;
int i;
for (i = 0; i < 4; i++)
{
d[(i + 4 - octetshifts) % 4] =
((s[i] << bitshift) & um) |
((s[(i + 1) % 4] >> bitsleft) & lm);
}
}
Obviously
While keeping in mind plain C the best way is
inline void circular_left_shift(char *chars, short shift) {
__int32 *dword = (__int32 *)chars;
*dword = (*dword << shift) | (*dword >> (32 - shift));
}
Uhmm, char is 16 bits long, was not clear for me. I presume int is still 32 bit.
inline void circular_left_shift(char *chars, short shift) {
int i, part;
part = chars[0] >> (16 - shift);
for (i = 0; i < 3; ++i)
chars[i] = (chars[i] << shift) | (chars[i + 1] >> (16 - shift));
chars[3] = (chars[3] << shift) | part;
}
Or you could just unwind this cycle.
You could dig further into asm instruction ror, on x86 it's capable of performing such shift up to 31 bits left. Something like a
MOV CL, 31
ROR EAX, CL
Use union:
typedef union chr_int{
unsigned int i;
unsigned char c[4];
};
It's safer (because of pointer aliasing) and easier to manipulate.
EDIT: you should have mention earlier that your char isn't 8 bits. However, this should do the trick:
#define ORIG_MASK 0x81010102
#define LS_CNT 1
unsigned char a[4] = {
((ORIG_MASK << LS_CNT ) | (ORIG_MASK >> (32 - LS_CNT))) & 0xff,
((ORIG_MASK << (LS_CNT + 8)) | (ORIG_MASK >> (24 - LS_CNT))) & 0xff,
((ORIG_MASK << LS_CNT + 16)) | (ORIG_MASK >> (16 - LS_CNT))) & 0xff,
((ORIG_MASK << (LS_CNT + 24)) | (ORIG_MASK >> ( 8 - LS_CNT))) & 0xff
};