IN C Programming, how do I combine (note: not add) two integers into one big integer? So if i have
int a = 8
int b = 6
in binary it would be
int a = 1000
int b = 0110
so combined it would be = 01101000
You would use a combination of the << shift operator and the bitwise | operator. If you are trying to build an 8-bit value from two 4-bit inputs, then:
int a = 8;
int b = 6;
int result = (b << 4) | a;
If you are trying to build a 32-bit value from two 16-bit inputs, then you would write
result = (b << 16) | a;
Example:
#include <stdio.h>
int main( void )
{
int a = 8;
int b = 6;
printf( "a = %08x, b = %08x\n", (unsigned int) a, (unsigned int) b );
int result = (b << 4) | a;
printf( "result = %08x\n", (unsigned int) result );
result = (b << 8) | a;
printf( "result = %08x\n", (unsigned int) result );
result = (b << 16) | a;
printf( "result = %08x\n", (unsigned int) result );
return 0;
}
$ ./bits
a = 00000008, b = 00000006
result = 00000068
result = 00000608
result = 00060008
You can do it as follow using binary mask & 0x0F and bit translation <<:
int a = 0x08
int b = 0x06
int c = (a & 0x0F) + ((b & 0x0F) << 4 )
I hope that it helped
Update 1:
As mentionned in the comment addition + or binary or | are both fine.
What is important to highlight in this answer is the mask & 0x0F, I strongly recommand to use this kind of mecanism to avoid any overflow.
you could use or operator.
int a = 8 ;
int b = 6 ;
int c = (a << 8) | b;
You can use the bit-shift operator << to move the bits into the correct position:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main()
{
uint8_t a = 8;
uint8_t b = 6;
uint16_t c = (b << 4) | a;
printf( "The result is: 0x%" PRIX16 "\n", c );
}
This program will print the following:
The result is: 0x68
Note that this program uses fixed-width integer types, which are recommended in this situation, as you cannot rely on the size of an int or unsigned int to have a certain width.
However, there is no need for the result to be 16-bits, if you are only shifting one value by 4 bits, as you are doing in your example. In that case, an integer type with a width of 8-bits would have been sufficient. I am only using 16-bits for the result because you explicitly asked for it.
The macro PRIX16 will probably expand to "hX" or "X" on most platforms. But it is still recommended to use this macro when using fixed-width integer types, as you cannot rely on %hX or %X being the correct format specifier for uint16_t on all platforms.
Related
I have a byte array represented as
char * bytes = getbytes(object); //some api function
I want to check whether the bit at some position x is set.
I've been trying this
int mask = 1 << x % 8;
y= bytes[x>>3] & mask;
However y returns as all zeros? What am I doing incorrectly and is there an easier way to check if a bit is set?
EDIT:
I did run this as well. It didn't return with the expected result either.
int k = x >> 3;
int mask = x % 8;
unsigned char byte = bytes[k];
return (byte & mask);
it failed an assert true ctest I ran. Byte and Mask at this time where "0002" and 2 respectively when printed from gdb.
edit 2: This is how I set the bits in the first place. I'm just trying to write a test to verify they are set.
unsigned long x = somehash(void* a);
unsigned int mask = 1 << (x % 8);
unsigned int location = x >> 3;
char* filter = getData(ref);
filter[location] |= mask;
This would be one (crude perhaps) way from the top of my head:
#include "stdio.h"
#include "stdlib.h"
// this function *changes* the byte array
int getBit(char *b, int bit)
{
int bitToCheck = bit % 8;
b = b + (bitToCheck ? (bit / 8) : (bit / 8 - 1));
if (bitToCheck)
*b = (*b) >> (8 - bitToCheck);
return (*b) & 1;
}
int main(void)
{
char *bytes = calloc(2, 1);
*(bytes + 1)= 5; // writing to the appropiate bits
printf("%d\n", getBit(bytes, 16)); // checking the 16th bit from the left
return 0;
}
Assumptions:
A byte is represented as:
----------------------------------------
| 2^7 | 2^6 | 2^5 | 2^4 | 2^3 |... |
----------------------------------------
The left most bit is considered bit number 1 and the right most bit is considered the max. numbered bit (16th bit in a 2 byte object).
It's OK to overwrite the actual byte object (if this is not wanted, use memcpy).
static unsigned int read24(unsigned char *ptr)
{
unsigned int b0;
unsigned int b1;
unsigned int b2;
unsigned int b3;
b0 = *ptr++;
b1 = *ptr++;
b2 = *ptr++;
b3 = *ptr;
return ( ((b0 >> 24) & 0x000000ff) |
((b1 >> 8) & 0x0000ff00) |
((b2 << 8) & 0x00ff0000) |
(b3 << 24) & 0x00000000 // this byte is not important so make it zero
);
}
Here i have written a function and am trying to read 32 bits (4bytes) using a char pointer and return those 32 bits (4bytes).I have a doubt if this will work properly.Also,am i using/wasting too much memory by defining 4 different integer variables?Is there a better way to write this function. Thank you for your time.
First, drop b3, since you're apparently meaning to read 24 bits you shouldn't even try to access that extra byte (what if it's not even allocated?).
Second, I think you have your shifts wrong. b0 will always be in the range [0..255], so if you >> 24, it'll become zero. There's also no need to mask anything out, since you're coming from unsigned char you know you'll only have 8 bits set. You probably want either:
return (b0 << 16) | (b1 << 8) | b2;
or
return (b2 << 16) | (b1 << 8) | b0;
depending on the endianness of your data.
As for using those intermediate ints, if you have a decent compiler it won't matter (the compiler will optimize them out). If however you're writing for an embedded platform or otherwise have a less-than state of the are compiler, it's possible that eliding the intermediate ints may help your performance. In this case, don't put multiple ptr++s in the same statement, use ptr[n] instead to avoid undefined behavior from multiple increments.
Well, I'm not too clear on what you're attempting to do. If I'm not mistaken you want to input a char* (Most likely 4 bytes if you're running a 32 bit system) and get the same organization of bytes as an int* (4 bytes)
If all you want is the int* version of a char* set of bytes you can use type-casting:
unsigned int* result = (unsigned int*)ptr;
If you want the same collection of bytes BUT you want the most significant byte to be equal to 0 then you can do this:
unsigned int* result = (unsigned int*)ptr & 0x0FFF;
Some additional info:
-Type Casting is a method of temporarily "casting" a variable as any type you want via the use of a temporary copy that is of the type your casting the variable to You can make a variable act as any type you want if you typecast it:
Example:
unsigned int varX = 48;
//Prints "Ascii decimal value 48 corresponds with: 0"
printf ("Ascii decimal value 48 corresponds with: %c\n", (char)varX);
-Hexidicamal digits occupy one byte each. So in your code:
0x000000ff -> 8 bytes of data
0x implies that each of the place holders are a hexidecimal value and
I think what you were going for was 0x000F, which would make all the other bytes 0 except the least significant byte
ANSI-C can process hexidecimal(prefix -> 0x), octal(prefix -> 0) and decimal
Hope this helped!
When building your number from the individual pointers, you must shift the numbers to the left as you incrementally Or the values together. (for little endian machines). Think of it this way, after you read b0, that will be the least significant byte in your final number. Where do more significant bytes go? (to the left).
When you read a pointer value into b0, b1, b2, b3, all they hold is one byte each. They have no way of knowing where they came from in the original number, so there is no "relative" shifting required. You just start with the least significant byte, and incrementally shift each successive byte to the left by 1 byte more than the last.
Below, I have used all bytes in the building of the unsigned value from the unsigned char pointers as an example. You can simply omit bytes you do not need to meet your needs.
#include <stdio.h>
#include <stdlib.h>
#if defined(__LP64__) || defined(_LP64)
# define BUILD_64 1
#endif
#ifdef BUILD_64
# define BITS_PER_LONG 64
#else
# define BITS_PER_LONG 32
#endif
char *binstr (unsigned long n);
static unsigned int read24 (unsigned char *ptr);
int main (void) {
unsigned int n = 16975631;
unsigned int o = 0;
o = read24 ((unsigned char *)&n);
printf ("\n number : %u %s\n", n, binstr (n));
printf (" read24 : %u %s\n\n", o, binstr (o));
return 0;
}
static unsigned int read24 (unsigned char *ptr)
{
unsigned char b0;
unsigned char b1;
unsigned char b2;
unsigned char b3;
b0 = *ptr++; /* 00001111000001110000001100000001 */
b1 = *ptr++; /* b0 b1 b2 b3 */
b2 = *ptr++; /* b3 b2 b1 b0 */
b3 = *ptr; /* 00000001000000110000011100001111 */
return ((b0 & 0x000000ffU) |
((b1 << 8 ) & 0x0000ff00U) |
((b2 << 16) & 0x00ff0000U) |
((b3 << 24) & 0xff000000U));
}
/* simple return of binary string */
char *binstr (unsigned long n)
{
static char s[BITS_PER_LONG + 1] = {0};
char *p = s + BITS_PER_LONG;
if (!n) {
*s = '0';
return s;
}
while (n) {
*(--p) = (n & 1) ? '1' : '0';
n >>= 1;
}
return p;
}
Output
$ ./bin/rd_int_as_uc
number : 16975631 1000000110000011100001111
read24 : 16975631 1000000110000011100001111
Consider using the following approach for your task:
#include <string.h>
unsigned int read24b(unsigned char *ptr)
{
unsigned int data = 0;
memcpy(&data, ptr, 3);
return data;
}
This is for case if you want direct order of bits, but I suppose you do not...
Concerning your code - you must apply mask and then make shift, e.g.:
unsigned int read24(unsigned char *ptr)
{
unsigned char b0;
unsigned char b1;
unsigned char b2;
b0 = *ptr++;
b1 = *ptr++;
b2 = *ptr;
return ( (b0 & 0x0ff) >> 16 |
(b1 & 0x0ff) >> 8 |
(b2 & 0x0ff)
);
}
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;
}
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
I am learning bit manipulation in C and I have written a simple program. However the program fails. Can someone please look into this code?
Basically I want to extract and reassemble a 4 byte 'long' variable to its induvidual bytes and vice versa. Here is my code:
printf("sizeof char= %d\n", sizeof(char));
printf("sizeof unsigned char= %d\n", sizeof(unsigned char));
printf("sizeof int= %d\n", sizeof(int));
printf("sizeof long= %d\n", sizeof(long));
printf("sizeof unsigned long long= %d\n", sizeof(unsigned long long));
long val = 2;
int k = 0;
size_t len = sizeof(val);
printf("val = %ld\n", val);
printf("len = %d\n", len);
char *ptr;
ptr = (char *)malloc(sizeof(len));
//converting 'val' to char array
//val = b3b2b1b0 //where 'b is 1 byte. Since 'long' is made of 4 bytes, and char is 1 byte, extracting byte by byte of long into char
//do{
//val++;
for(k = 0; k<len; k++){
ptr[k] = ((val >> (k*len)) && 0xFF);
printf("ptr[%d] = %02X\n", k,ptr[k]);
}
//}while(val < 12);
//reassembling the bytes from char and converting them to long
long xx = 0;
int m = 0;
for(m = 0; m< len; m++){
xx = xx |(ptr[m]<<(m*8));
}
printf("xx= %ld\n", xx);
Why don't I see xx returning 2?? Also, irrespective of the value of 'val', the ptr[0] seems to store 1 :(
Please help
Thanks in advance
ptr[k] = ((val >> (k*len)) && 0xFF);
Should be
ptr[k] = ((val >> (k*8)) & 0xFF);
&& is used in conditional statements and & for bitwise and.
Also as you're splitting the value up into chars, each iteration of the loop you want to shift with as many bits as are in a byte. This is almost always 8 but can be something else. The header file limits.h has the info about that.
A few things I notice:
You're using the boolean && operator instead of bitwise &
You're shifting by "k*len" instead of "k*8"
You're allocating an array with "sizeof(len)", instead of just "len"
You're using "char" instead of "unsigned char". This will make the "(ptr[m]<<(m*8))" expression sometimes give you a negative number.
So a fixed version of your code would be:
printf("sizeof char= %d\n", sizeof(char));
printf("sizeof unsigned char= %d\n", sizeof(unsigned char));
printf("sizeof int= %d\n", sizeof(int));
printf("sizeof long= %d\n", sizeof(long));
printf("sizeof unsigned long long= %d\n", sizeof(unsigned long long));
long val = 2;
int k = 0;
size_t len = sizeof(val);
printf("val = %ld\n", val);
printf("len = %d\n", len);
unsigned char *ptr;
ptr = (unsigned char *)malloc(len);
//converting 'val' to char array
//val = b3b2b1b0 //where 'b is 1 byte. Since 'long' is made of 4 bytes, and char is 1 byte, extracting byte by byte of long into char
//do{
//val++;
for(k = 0; k<len; k++){
ptr[k] = ((val >> (k*8)) & 0xFF);
printf("ptr[%d] = %02X\n", k,ptr[k]);
}
//}while(val < 12);
//reassembling the bytes from char and converting them to long
long xx = 0;
int m = 0;
for(m = 0; m< len; m++){
xx = xx |(ptr[m]<< m*8);
}
printf("xx= %ld\n", xx);
Also, in the future, questions like this would be better suited to https://codereview.stackexchange.com/
As others have by now mentioned, I'm not sure if ptr[k] = ((val >> (k*len)) && 0xFF); does what you want it to. The && operator is a boolean operator. If (value >> (k*len)) is some non-zero value, and 0xFF is some non-zero value, then the value stored into ptr[k] will be one. That's the way boolean operators work. Perhaps you meant to use & instead of &&.
Additionally, you've chosen to use shift operators, which is appropriate for unsigned types, but has a variety of non-portable aspects for signed types. xx = xx |(ptr[m]<<(m*8)); potentially invokes undefined behaviour, for example, because it looks like it could result in signed integer overflow.
In C, sizeof (char) is always 1, because the sizeof operator tells you how many chars are used to represent a type. eg. sizeof (int) tells you how many chars are used to represent ints. It's CHAR_BIT that changes. Thus, your code shouldn't rely upon the sizeof a type.
In fact, if you want your code to be portable, then you shouldn't be expecting to be able to store values greater than 32767 or less than -32767 in an int, for example. This is regardless of size, because padding bits might exist. To summarise: the sizeof a type doesn't necessarily reflect the set of values it can store!
Choose the types of your variables for their application, portably. If your application doesn't need values beyond that range, then int will do fine. Otherwise, you might want to think about using a long int, which can store values between (and including) -2147483647 and 2147483647, portably. If you need values beyond that, use a long long int, which will give you the guaranteed range consisting of at least the values between -9223372036854775807 and 9223372036854775807. Anything beyond that probably deserves a multi-precision arithmetic library such as GMP.
When you don't expect to use negative values, you should use unsigned types.
With consideration given to your portable choice of integer type, it now makes sense that you can devise a portable way to write those integers into files, and read those integers from files. You'll want to extract the sign and absolute value into unsigned int:
unsigned int sign = val < 0; /* conventionally 1 for negative, 0 for positive */
unsigned int abs_val = val;
if (val < 0) { abs_val = -abs_val; }
... and then construct an array of 8-bit chunks of abs_val and sign, merged together. We've already decided using portable decision-making that our int can only store 16 bits, because we're only ever storing values between -32767 and 32767 in it. As a result, there is no need for a loop, or bitwise shifts. We can use multiplication to move our sign bit, and division/modulo to reduce our absolute value. Consider that the sign conventionally goes with the most significant bit, which is either at the start (big endian) or the end (little endian) of our array.
unsigned char big_endian[] = { sign * 0x80 + abs_val / 0x100,
abs_value % 0x100 };
unsigned char lil_endian[] = { abs_value % 0x100,
sign * 0x80 + abs_val / 0x100 };
To reverse this process, we perform the opposite operations in reverse of each other (that is, using division and modulo in place of multiplication, multiplication in place of division and addition, extract the sign bit and reform the value):
unsigned int big_endian_sign = array[0] / 0x80;
int big_endian_val = big_endian_sign
? -((array[0] % 0x80) * 0x100 + array[1])
: ((array[0] % 0x80) * 0x100 + array[1]);
unsigned int lil_endian_sign = array[1] / 0x80;
int lil_endian_val = lil_endian_sign
? -((array[1] % 0x80) * 0x100 + array[0])
: ((array[1] % 0x80) * 0x100 + array[0]);
The code gets a little more complex for long, and it becomes worthwhile to use binary operators. The extraction of sign and absolute value remains essentially the same, with the only changes being the type of the variables. We still don't need loops, because we made a decision that we only care about values representable portably. Here's how I'd convert from a long val to an unsigned char[4]:
unsigned long sign = val < 0; /* conventionally 1 for negative, 0 for positive */
unsigned long abs_val = val;
if (val < 0) { abs_val = -abs_val; }
unsigned char big_endian[] = { (sign << 7) | ((abs_val >> 24) & 0xFF),
(abs_val >> 16) & 0xFF,
(abs_val >> 8) & 0xFF,
abs_val & 0xFF };
unsigned char lil_endian[] = { abs_val & 0xFF,
(abs_val >> 8) & 0xFF,
(abs_val >> 16) & 0xFF,
(sign << 7) | ((abs_val >> 24) & 0xFF) };
... and here's how I'd convert back to the signed value:
unsigned int big_endian_sign = array[0] >> 7;
long big_endian_val = big_endian_sign
? -((array[0] & 0x7F) << 24) + (array[1] << 16) + (array[2] << 8) + array[3]
: ((array[0] & 0x7F) << 24) + (array[1] << 16) + (array[2] << 8) + array[3];
unsigned int lil_endian_sign = array[3] >> 7;
long lil_endian_val = lil_endian_sign
? -((array[3] & 0x7F) << 24) + (array[2] << 16) + (array[1] << 8) + array[0]
: ((array[3] & 0x7F) << 24) + (array[2] << 16) + (array[1] << 8) + array[0];
I'll leave you to devise a scheme for unsigned and long long types... and open up the floor for comments: