There are two variables,
uint8_t x (8 bit type)
uint16_t y (16 bit type)
, that together hold information about the value of an int num. Say num consists of four bytes abcd (where a is most significant). Then x needs to be copied to b, and y needs to be compied to cd. What is the best way/code to do this?
This works for me:
#include <stdio.h>
#include <stdint.h>
int main()
{
uint8_t x = 0xF2;
uint16_t y = 0x1234;
int a = 0x87654321;
// The core operations that put x and y in a.
a = (a & 0xFF000000) | (x<<16);
a = (a & 0xFFFF0000) | y;
printf("x: %X\n", x);
printf("y: %X\n", y);
printf("a: %X\n", a);
}
Here's the output:
x: F2
y: 1234
a: 87F21234
you can use a union (although be careful with padding/alignment)
typedef union
{
uint32_t abcd;
struct
{
uint8_t a;
uint8_t b;
uint16_t cd;
} parts;
} myvaluetype;
myvaluetype myvalue = {0};
uint8_t x = 42;
uint16_t y = 2311;
myvalue.parts.b = x;
myvalue.parts.cd = y;
printf( "%u\n", myvalue.abcd );
Bytemasks will do. something like below
int8 x = a & 0xff;
int16 y = a & 0xff00;
Related
I'm currently working to create a function which accepts two 4 byte unsigned integers, and returns an 8 byte unsigned long. I've tried to base my work off of the methods depicted by this research but all my attempts have been unsuccessful. The specific inputs I am working with are: 0x12345678 and 0xdeadbeef, and the result I'm looking for is 0x12de34ad56be78ef. This is my work so far:
unsigned long interleave(uint32_t x, uint32_t y){
uint64_t result = 0;
int shift = 33;
for(int i = 64; i > 0; i-=16){
shift -= 8;
//printf("%d\n", i);
//printf("%d\n", shift);
result |= (x & i) << shift;
result |= (y & i) << (shift-1);
}
}
However, this function keeps returning 0xfffffffe which is incorrect. I am printing and verifying these values using:
printf("0x%x\n", z);
and the input is initialized like so:
uint32_t x = 0x12345678;
uint32_t y = 0xdeadbeef;
Any help on this topic would be greatly appreciated, C has been a very difficult language for me, and bitwise operations even more so.
This can be done based on interleaving bits, but skipping some steps so it only interleaves bytes. Same idea: first spread out the bytes in a couple of steps, then combine them.
Here is the plan, illustrated with my amazing freehand drawing skills:
In C (not tested):
// step 1, moving the top two bytes
uint64_t a = (((uint64_t)x & 0xFFFF0000) << 16) | (x & 0xFFFF);
// step 2, moving bytes 2 and 6
a = ((a & 0x00FF000000FF0000) << 8) | (a & 0x000000FF000000FF);
// same thing with y
uint64_t b = (((uint64_t)y & 0xFFFF0000) << 16) | (y & 0xFFFF);
b = ((b & 0x00FF000000FF0000) << 8) | (b & 0x000000FF000000FF);
// merge them
uint64_t result = (a << 8) | b;
Using SSSE3 PSHUFB has been suggested, it'll work but there is an instruction that can do a byte-wise interleave in one go, punpcklbw. So all we need to really do is get the values into and out of vector registers, and that single instruction will then just care of it.
Not tested:
uint64_t interleave(uint32_t x, uint32_t y) {
__m128i xvec = _mm_cvtsi32_si128(x);
__m128i yvec = _mm_cvtsi32_si128(y);
__m128i interleaved = _mm_unpacklo_epi8(yvec, xvec);
return _mm_cvtsi128_si64(interleaved);
}
With bit-shifting and bitwise operations (endianness independent):
uint64_t interleave(uint32_t x, uint32_t y){
uint64_t result = 0;
for(uint8_t i = 0; i < 4; i ++){
result |= ((x & (0xFFull << (8*i))) << (8*(i+1)));
result |= ((y & (0xFFull << (8*i))) << (8*i));
}
return result;
}
With pointers (endianness dependent):
uint64_t interleave(uint32_t x, uint32_t y){
uint64_t result = 0;
uint8_t * x_ptr = (uint8_t *)&x;
uint8_t * y_ptr = (uint8_t *)&y;
uint8_t * r_ptr = (uint8_t *)&result;
for(uint8_t i = 0; i < 4; i++){
*(r_ptr++) = y_ptr[i];
*(r_ptr++) = x_ptr[i];
}
return result;
}
Note: this solution assumes little-endian byte order
You could do it like this:
uint64_t interleave(uint32_t x, uint32_t y)
{
uint64_t z;
unsigned char *a = (unsigned char *)&x; // 1
unsigned char *b = (unsigned char *)&y; // 1
unsigned char *c = (unsigned char *)&z;
c[0] = a[0];
c[1] = b[0];
c[2] = a[1];
c[3] = b[1];
c[4] = a[2];
c[5] = b[2];
c[6] = a[3];
c[7] = b[3];
return z;
}
Interchange a and b on the lines marked 1 depending on ordering requirement.
A version with shifts, where the LSB of y is always the LSB of the output as in your example, is:
uint64_t interleave(uint32_t x, uint32_t y)
{
return
(y & 0xFFull)
| (x & 0xFFull) << 8
| (y & 0xFF00ull) << 8
| (x & 0xFF00ull) << 16
| (y & 0xFF0000ull) << 16
| (x & 0xFF0000ull) << 24
| (y & 0xFF000000ull) << 24
| (x & 0xFF000000ull) << 32;
}
The compilers I tried don't seem to do a good job of optimizing either version so if this is a performance critical situation then maybe the inline assembly suggestion from comments is the way to go.
use union punning. Easy for the compiler to optimize.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
typedef union
{
uint64_t u64;
struct
{
union
{
uint32_t a32;
uint8_t a8[4]
};
union
{
uint32_t b32;
uint8_t b8[4]
};
};
uint8_t u8[8];
}data_64;
uint64_t interleave(uint32_t a, uint32_t b)
{
data_64 in , out;
in.a32 = a;
in.b32 = b;
for(size_t index = 0; index < sizeof(a); index ++)
{
out.u8[index * 2 + 1] = in.a8[index];
out.u8[index * 2 ] = in.b8[index];
}
return out.u64;
}
int main(void)
{
printf("%llx\n", interleave(0x12345678U, 0xdeadbeefU)) ;
}
I am pretty new in c programming and I am trying to figure out more about bits, binary e.c.t
For example, I have three int variables m1 =255 or 11111111 in binary; m2 =255 or 11111111 in binary, m3 = 255 or 11111111 in binary and m4 =0 or 00000000. I am trying to put all theme together into single int variable temp. Something like this (11111111 11111111 11111111 00000000)
Here is the piece of code that I have:
int x1;
unsigned char x2;
unsigned char x3;
unsigned char x4;
int temp;
x1 = x1|m1;
printf("x1:%d\n", x1);
x2 = x2|m2;
printf("x2:%d\n", x2);
temp = x1<<8;
printf("temp:%d\n", temp);
temp = temp|x2;
printf("temp:%d\n", temp);
x3 = x3|m3;
printf("x3:%d\n", x3);
temp = temp<<8;
printf("temp:%d\n", temp);
temp = temp|x3;
printf("temp:%d\n", temp);
x4 = x4|m4;
printf("x4:%d\n", x4);
temp = temp<<8;
printf("temp:%d\n", x1);
temp = temp|x4;
printf("%d\n", temp);
I am using left shift and OR operators here. But I got a little bit wierd output. (I printed out every to step to find out what is wrong).
I got next output:
x1:255
x2:255
temp:65280
temp:65535
x3:255
temp:16776960
temp:16777215
x4:0
temp:-256
temp:-256
Everything goes fine until temp becomes -256 and I do not know why.
I appreciate any help! Thank you!
You're using %d format and it treats variables as signed integers, you need to use %u and change the variable types to unsigned.
unsigned char x1;
unsigned int temp;
You really have a couple of choices in C. First, what it appears you are attempting to do is the following. (note: you should include stdint.h and use uint32_t guaranteed width values instead of int) Your problems surround invoking Undefined Behavior by OR'ing uninitialized values, and failing to properly shift the values for x1, ..., x4.
To do what it looks like you are attempting to do, you could:
#include <stdio.h>
int main (void) {
unsigned int x1 = 0, x2 = 0, x3 = 0, x4 = 0;
unsigned char m1, m2, m3, m4 = 0;
m1 = m2 = m3 = 255;
x1 |= m1;
x2 |= ((unsigned)m2 << 8);
x3 |= ((unsigned)m3 << 16);
x4 = ((x1 | x2 | x3) << 8) | (unsigned)m4;
printf("x1: %u\n", x1);
printf("x2: %u\n", x2);
printf("x3: %u\n", x3);
printf("x4: %u\n", x4);
return 0;
}
Example Use/Output
$ ./bin/shiftx
x1: 255
x2: 65280
x3: 16711680
x4: 4294967040
You can also simplify your logic by simply using a two variables and the value 255. Essentially, you are setting your temp variable to 255 and shifting left by 8, 3-times. Your final value is the OR'ing of the first 3 temp values with a final shift by 8 to get your combined value with the least significant byte zero, e.g.
#include <stdio.h>
#include <stdint.h>
int main (void) {
uint32_t tmp = 0, val = 0;
uint8_t m = 255;
val = m;
printf ("tmp1 : %u\n", val);
tmp = val << 8;
printf ("tmp2 : %u\n", tmp);
val |= tmp;
tmp <<= 8;
printf ("tmp3 : %u\n", tmp);
val |= tmp;
tmp <<= 8;
printf ("tmp4 : %u\n", tmp);
val <<= 8;
printf ("val : %u\n", val);
return 0;
}
Example Use/Output
$ ./bin/shift1var
tmp1 : 255
tmp2 : 65280
tmp3 : 16711680
tmp4 : 4278190080
val : 4294967040
An improved version could make use of a union between a bitfield struct and a uint32_t value, guaranteeing a 32-bit width regardless of architecture. For example, you could:
#include <stdio.h>
#include <stdint.h>
typedef union {
struct {
uint32_t a : 8,
b : 8,
c : 8,
d : 8;
} bits;
uint32_t value;
} bitunion;
int main (void) {
bitunion bu = { .bits = {.a = 0, .b = 255, .c = 255, .d = 255} };
printf ("bu.bits.a: %u\n", bu.bits.a);
printf ("bu.bits.b: %u\n", bu.bits.b << 8);
printf ("bu.bits.c: %u\n", bu.bits.c << 16);
printf ("bu.bits.d: %u\n", bu.bits.d << 24);
printf ("value : %u\n", bu.value);
return 0;
}
(note: the bitfield is made up of d-c-b-a bytes)
Example Use/Output
$ ./bin/shiftxstruct
bu.bits.a: 0
bu.bits.b: 65280
bu.bits.c: 16711680
bu.bits.d: 4278190080
value : 4294967040
Now, don't think these are the only ways to do this. You can use any combination of shifts and OR's as long as you accurately account for the bytes within your final value. Look things over and let me know if you have additional questions.
poly8_bitslice() array if char as input, this input will be converted to bits(byte) by the function intToBits().
After the conversion I want to store the result in a long long variable. Is this possible?
Can I concatenate the result of intToBits()?
I want to do this with the following code:
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <string.h>
//#include <math.h>
typedef unsigned char poly8;
typedef unsigned long long poly8x64[8];
void intToBits(unsigned k, poly8 nk[8]) {
int i;
for(i=7;i>=0;i--){
nk[i] = (k%2);
k = (int)(k/2);
}
}
void poly8_bitslice(poly8x64 r, const poly8 x[64])
{
//TODO
int i;
for(i=0;i<64;i++){
poly8 xb[8];
intToBits(x[i], xb);
int j;
long long row;
for(j=0;j<8;j++){
row = row + x[j];
}
printf("row=%d \n", row);
}
}
int main()
{
poly8 a[64], b[64], r[64];
poly8x64 va, vb, vt;
int i;
FILE *urandom = fopen("/dev/urandom","r");
for(i=0;i<64;i++)
{
a[i] = fgetc(urandom);
b[i] = fgetc(urandom);
}
poly8_bitslice(va, a);
poly8_bitslice(vb, b);
fclose(urandom);
return 0;
}
I am not sure I fully understood your question but you can do something like this
char ch0 = 0xAA;
char ch1 = 0xBB;
char ch2 = 0xCC;
char ch3 = 0xDD;
long long int x = 0; // x is 0x00000000
x = (long long int)ch0; // x is 0x000000AA
x = x << 8; // x is 0x0000AA00
x = x | (long long int)ch1; // x is 0x0000AABB
x = x << 8; // x is 0x00AABB00
x = x | (long long int)ch2; // x is 0x00AABBCC
x = x << 8; // x is 0xAABBCC00
x = x | (long long int)ch3; // x is 0xAABBCCDD
In this case x would contain 0xAABBCCDD
The << operator will shift the content of the left hand operator by the number specified by the right hand operator. So 0xAA << 8 would become 0xAA00. Note that it will append zeros at the end while shifting.
The| operator will perform a bitwise or on both its operands. That is a bit by bit or. So the first bit of the left hand operator will be or'ed with the first bit of the right hand operator and the result will be placed in the first bit of the result.
Anything or'ed with zero results to its self so
0xAA00 | 0x00BB
would result in
0xAABB
In general a bit append function would be
long long int bitAppend(long long int x, char ch) {
return ((x << 8) | (long long int)ch);
}
This function would take the long long integer that you need to append to and the char to append to it and would return the appended long long int. Note that as soon as the 64 bits are filled up the high order bits will be shifted out.
For example
long long int x = 0x1122334455667788
x = x << 8; // x now is 0x2233445566778800
this would result into x being 0x2233445566778800 since there is only 64bits in a long long int so the high order bits had to move out.
I have this function called byte swap I am supposed to implement. The idea is that the function takes 3 integers (int x, int y, int z) and the function will swap the y and z bytes of the int x. The restrictions are pretty much limited to bit wise operations (no loops, and no if statements or logical operators such as ==).
I don't believe that I presented this problem adequately so Im going to re attempt
I now understand that
byte 1 is referring to bits 0-7
byte 2 is referring to bits 8-15
byte 3 16-23
byte 4 24-31
My function is supposed to take 3 integer inputs, x, y and z. The y byte and z byte on the x then would have to get switched
int byteSwap(int x, int y, int z)
ex of the working function
byteSwap(0x12345678, 1, 3) = 0x56341278
byteSwap(0xDEADBEEF, 0, 2) = 0xDEEFBEAD
My original code had some huge errors in it, namely the fact that I was considering a byte to be 2 bits instead of 8. The main problem that I'm struggling with is that I do not know how to access the bits inside of the given byte. For example, when I'm given byte 4 and 5, how do I access their respected bits? As far as I can tell I can't find a mathematical relationship between the given byte, and its starting bit. I'm assuming I have to shift and then mask, and save those to variables.Though I cannot even get that far.
Extract the ith byte by using ((1ll << ((i + 1) * 8)) - 1) >> (i * 8). Swap using the XOR operator, and put the swapped bytes in their places.
int x, y, z;
y = 1, z = 3;
x = 0x12345678;
int a, b; /* bytes to swap */
a = (x & ((1ll << ((y + 1) * 8)) - 1)) >> (y * 8);
b = (x & ((1ll << ((z + 1) * 8)) - 1)) >> (z * 8);
/* swap */
a = a ^ b;
b = a ^ b;
a = a ^ b;
/* put zeros in bytes to swap */
x = x & (~((0xff << (y * 8))));
x = x & (~((0xff << (z * 8))));
/* put new bytes in place */
x = x | (a << (y * 8));
x = x | (b << (z * 8));
When you say the 'the y and z bytes of x' this implies x is an array of bytes, not an integer. If so:
x[z] ^= x[y];
x[y] ^= x[z];
x[z] ^= x[y];
will do the trick, by swapping x[y] and x[z]
After your edit, it appears you want to swap individual bytes of a 32 bit integer:
On a little-endian machine:
int
swapbytes (int x, int y, int z)
{
char *b = (char *)&x;
b[z] ^= b[y];
b[y] ^= b[z];
b[z] ^= b[y];
return x;
}
On a big-endian machine:
int
swapbytes (int x, int y, int z)
{
char *b = (char *)&x;
b[3-z] ^= b[3-y];
b[3-y] ^= b[3-z];
b[3-z] ^= b[3-y];
return x;
}
With a strict interpretation of the rules, you don't even need the xor trick:
int
swapbytes (int x, int y, int z)
{
char *b = (char *)&x;
char tmp = b[z];
b[z] = b[y];
b[y] = tmp;
return x;
}
On a big-endian machine:
int
swapbytes (int x, int y, int z)
{
char *b = (char *)&x;
char tmp = b[3-z];
b[3-z] = b[3-y];
b[3-y] = tmp;
return x;
}
If you want to do it using bit shifts (note <<3 multiplies by 8):
int
swapbytes (unsigned int x, int y, int z)
{
unsigned int masky = 0xff << (y<<3);
unsigned int maskz = 0xff << (z<<3);
unsigned int origy = (x & masky) >> (y<<3);
unsigned int origz = (x & maskz) >> (z<<3);
return (x & ~masky & ~maskz) | (origz << (y<<3)) | (origy << (z<<3));
}
I'm trying to reverse the bytes for a 64 bit address pointer for an assignment and have this code:
char swapPtr(char x){
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
return x;
}
But, it just messes everything up. However, a similar function works perfectly for a 64bit long. Is there something different that needs to be done for pointers?
Could the way I'm making the function call be an issue?
For a pointer:
*(char*)loc = swapPtr(*(char*)loc);
For a long:
*loc = swapLong(*loc);
You cannot use char x for a pointer!!!! A char is only a single byte long.
You need at the very least
unsigned long int swapPtr(unsigned long int x) {
Or better, use the type of the pointer
void* swapPtr(void* x) {
Quite likely your compiler will complain when you start bit shifting pointers; in that case you're better off explicitly casting your argument to an unsigned 64 bit integer:
#include <stdint.h>
uint64_t x;
Note also that you have to call with the address of a variable, so you call with
result = swapLong(&loc);
not *loc (which looks at the place where loc is pointing - the value, not the address).
Complete program:
#include <stdio.h>
#include <stdint.h>
uint64_t swapLong(void *X) {
uint64_t x = (uint64_t) X;
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
return x;
}
int main(void) {
char a;
printf("the address of a is 0x%016llx\n", (uint64_t)(&a));
printf("swapping all the bytes gives 0x%016llx\n",(uint64_t)swapLong(&a));
}
Output:
the address of a is 0x00007fff6b133b1b
swapping all the bytes gives 0x1b3b136bff7f0000
EDIT you could use something like
#include <inttypes.h>
printf("the address of a is 0x%016" PRIx64 "\n", (uint64_t)(&a));
where the macro PRIx64 expands into "the format string you need to print a 64 bit number in hex". It is a little cleaner than the above.
You may also use _bswap64 intrinsic (which has latency of 2 and a throughput of 0.5 on Skylake Architecture). It is a wrapper for the assembly instruction bswap r64 so probably the most efficient :
Reverse the byte order of 64-bit integer a, and store the result in dst. This intrinsic is provided for conversion between little and big endian values.
#include <immintrin.h>
uint64_t swapLongIntrinsic(void *X) {
return __bswap_64((uint64_t) X);
}
NB: Don't forget the header
Here is an alternative way for converting a 64-bit value from LE to BE or vice-versa.
You can basically apply this method any type, by defining var_type:
typedef long long var_type;
Reverse by pointer:
void swapPtr(var_type* x)
{
char* px = (char*)x;
for (int i=0; i<sizeof(var_type)/2; i++)
{
char temp = px[i];
px[i] = px[sizeof(var_type)-1-i];
px[sizeof(var_type)-1-i] = temp;
}
}
Reverse by value:
var_type swapVal(var_type x)
{
var_type y;
char* px = (char*)&x;
char* py = (char*)&y;
for (int i=0; i<sizeof(var_type); i++)
py[i] = px[sizeof(var_type)-1-i];
return y;
}