Can someone explain this bitwise C code? - c

I don't know what's going on with this:
#define _PACK32(str, x) \
{ \
*(x) = ((int) *((str) + 3) ) \
| ((int) *((str) + 2) << 8) \
| ((int) *((str) + 1) << 16) \
| ((int) *((str) + 0) << 24); \
}
the str it's a integer and the x it's a integer pointer

Well, as mentioned, str is not an integer. It's a pointer, as it is being dereference with * operator.
*((str) + 3) is equivalent to *(str + sizeof(str[0])*3), thus this depends on the type of str, as seen here. Same goes for other dereference operator.
So what's going on? Well, it takes the least significant 8bit of str[0], str1, str[2], and assemble them to one 32 bit size integer.
For instance, let W, X, Y, Z, A be arbitrary bit. Then,
*(str + 3) = WWWWWWWWWWWWWWWWWWWWWWWWXXXXXXXX
*(str + 2) = WWWWWWWWWWWWWWWWWWWWWWWWYYYYYYYY
*(str + 1) = WWWWWWWWWWWWWWWWWWWWWWWWZZZZZZZZ
*(str + 0) = WWWWWWWWWWWWWWWWWWWWWWWWAAAAAAAA
The last 3 are shifted, 8, 16, and 24, respectively, thus,
*(str + 3) = WWWWWWWWWWWWWWWWWWWWWWWWXXXXXXXX
*(str + 2) = WWWWWWWWWWWWWWWWYYYYYYYY00000000
*(str + 1) = WWWWWWWWZZZZZZZZ0000000000000000
*(str + 0) = AAAAAAAA000000000000000000000000
Note that the least significant digits of the last 3 are replaced with 0 during the shift.
Last, they are OR'ED, which is then assigned to X,
X = AAAAAAAAZZZZZZZZYYYYYYYYXXXXXXXX
Edit: O'Ring is not as straightforward as it might seem seems W's could be anything.

Looks like str is a pointer to an array of 4 bytes, and x is a pointer to a 32 bit value. str would actually point to the first byte (LSB) of a little endian 32 bit number, and this macro would read it and store in the variable pointed by x.

Correctly written as an inline function this should look something like:
void pack32(void const*p, unsigned* x) {
unsigned char const* str = p;
*x = str[0];
*X = *x<<8 | str[1];
*X = *x<<8 | str[2];
*X = *x<<8 | str[3];
}
you should use unsigned types when you do bit shifting, otherwise your result can overflow. And perhaps it also makes the idea clearer. The suposedly 8 bit of each byte are placed in the different bits of the target x.

Related

Why does this program print 23 after casting?

int main() {
uint32_t x;
uint32_t* p = (uint32_t*)malloc(sizeof(uint32_t));
uint32_t array[9] = {42, 5, 23, 82, 127, 21, 324, 3, 8};
*p = *(uint32_t*) ((char*) array + 8);
printf("l: %d\n", *p);
return 0;
}
Why does *p print the value of the second index of array after *p = *(uint32_t*) ((char*) array + 8); ?
Perhaps the question revolves around operator precedence and associativity. This expression ...
*(uint32_t*) ((char*) array + 8)
... is equivalent to ...
*((uint32_t*) (((char*) array) + 8))
... NOT ...
*((uint32_t*) ((char*) (array + 8))) // not equivalent
Typecast operators have very high precedence, higher than binary +, in particular. Pointer arithmetic works in units of the pointed-to type, and the type of ((char *) array) is, or course, char *. Its pointed to type is char. Therefore, (((char*) array) + 8) evaluates to a pointer to the 8th char past the beginning of the array.
Your implementation has 8-bit chars, which is exceedingly common (but not universal). Type uint32_t has exactly 32 bits, and so comprises four 8-bit chars. It follows that (((char*) array) + 8) points to the first char of the third uint32_t in array, as the 8 bytes skipped are exactly the bytes of the first two uint32_ts.
When that pointer is converted back to type uint32_t *, it points to the whole third uint32_t of the array, and the value of that element, 23, is read back by dereferencing the pointer with the unary * operator.
sizeof(uint32_t) is 4
sizeof(char) is 1 => 8 * sizeof(char) == 8
8 / sizeof(uint32_t) = 2
then ((char *)array) + 8 == array + (8 / sizeof(uint32_t))
p = array + (8 / sizeof(uint32_t)) => p = array + 2
then *p == array[2] == 23

C math function with _BYTE and

I used IDA to decompile a function a program and i don`t know what exactly this code work.
flag[i] ^= *((_BYTE *)&v2 + (signed int)i % 4);
How does this work?
This could be used for xor-"decrypting" (or encrypting, the operation is symmetric) a buffer with a 4-byte key. See the following code, which might be a bit better readable, than the decompiler output
char flag[SIZE];
char key[4];
for (int i = 0; i < SIZE; i++) {
flag[i] = flag[i] ^ key[i%4];
}
So if your data is "ZGUIHUOHJIOJOPIJMXAR" and your key is "akey", then the snippet basically does
ZGUIHUOHJIOJOPIJMXA
^ akeyakeyakeyakeyake
=====================
yourplaintextresult (<- not really the result here, but you get the idea)
(_BYTE *)&v2
This says the address of v2 should be an address to a variable of type byte
(signed int)i % 4
This says the remainder of integer i divided by 4 (i is probably a loop counter)
(_BYTE *)&v2 + (signed int)i % 4
This says address that v2 points to it, should be incremented by (i % 4).
*((_BYTE *)&v2 + (signed int)i % 4)
This is to dereference the content in memory at position (v2 + i%4)
flag[i] ^= *((_BYTE *)&v2 + (signed int)i % 4);
This says the i th element of flag array should be XOR-ed with the result of the content in memory at the position of (v2 + i%4)

Circular buffer increment using alternate method

I am not able to understand how does the last statement increments the pointer.Can somebody explain me with few examples?
The code, as shown:
aptr = (aptr + 1) & (void *)(BUFFERSIZE - 1);
// |________| incremented here
Since it is a circular buffer AND the buffer size is a power of 2, then the & is an easy and fast way to roll over by simply masking. Assuming that the BUFFERSIZE is 256, then:
num & (256 - 1) == num % 256
num & (0x100 - 1) == num % 0x100
num & (0x0ff) == num % 0x100
When the number is not a power of 2, then you can't use the masking technique:
num & (257 - 1) != num % 257
num & (0x101 - 1) != num % 0x101
num & 0x100 != num % 0x101
The (void *) allows the compiler to choose an appropriate width for the BUFFERSIZE constant based on your pointer width... although it is generally best to know - and use! - the width before a statement like this.
I added the hex notation so to make more clear why the & results in an emulated rollover event. Note that 0xff is binary 0x11111111, so the AND operation is simply masking off the upper bits.
2 problems with this approach.
A) Using a pointer with a bit-wise operation is not portable code. #Ilja Everilä
char *aptr;
// error: invalid operands to binary & (have 'char *' and 'void *')
// The following increments the index: (not really)
// aptr = (aptr + 1) & (void *)(BUFFERSIZE-1);
B) With compilers that support the non-standard math on a void * akin to a char *, the math is wrong if aptr point to an object wider than char and BUFFERSIZE is the number of elements in the buffer and not the byte-size. Of course this depends on how the non-standard complier implements some_type * & void *. Why bother to unnecessarily code to use some implementation specific behavior?
Instead use i % BUFFERSIZE. This portable approach works when BUFFERSIZE is a power-of-2 and well as when it is not. When a compiler sees i % power-of-2 and i is some unsigned type, then the same code is certainly emitted as i & (power-of-2 - 1).
For compilers that do not recognize this optimization, then one should consider a better compiler.
#define BUFFERSIZE 256
int main(void) {
char buf[BUFFERSIZE];
// pointer solution
char *aptr = buf;
aptr = &buf[(aptr - buf + 1) % BUFFERSIZE];
// index solution
size_t index = 0;
index = (index + 1) % BUFFERSIZE;
}

Convert char to short

I need to copy the data from 2 char (8 bit long) to a single short (16 bit long). I tried two different ways, but can't get it to work.
void char2short(char* pchar, short* pshort)
{
memcpy(pshort , pchar + 1 , 1);
memcpy(pshort + 1, pchar , 1);
}
And the other one:
void char2short(char* pchar, short* pshort)
{
short aux;
aux = ((*pchar & 0x00FF) << 8) | ((*(pchar+1) & 0xFF00) >> 8);
*pshort = aux;
}
#include <stdio.h>
void char2short(unsigned char* pchar, unsigned short* pshort)
{
*pshort = (pchar[0] << 8) | pchar[1];
}
int main()
{
unsigned char test[2];
unsigned short result = 0;
test[0] = 0xAB;
test[1] = 0xCD;
char2short(test, &result);
printf("%#X\n",result);
return 0;
}
this will do the job.
Assuming pchar is an array that contains your 2 chars, how about:
*pshort = (uint16_t)(((unsigned int)pchar[0]) |
(((unsigned int)pchar[1])<<8));
P.S. This work for little endianess.
Others didn't explain why your code didn't work, so I'll take a quick stab at it:
memcpy(pshort , pchar + 1 , 1);
memcpy(pshort + 1, pchar , 1);
Adding to a pointer TYPE * p moves the pointer by increments of sizeof( TYPE ) (so it does point at the next element, remember this is only defined if inside an array). So while pchar + 1 is correct, pshort + 1 is not (as it's addressing the next short).
aux = ((*pchar & 0x00FF) << 8) | ((*(pchar+1) & 0xFF00) >> 8);
Errr.... the right hand side is broken in more ways than one. First, *(pchar+1) is a char, and & 0xFF00 on a char will always yield 0 (because a char is only 8 bits to begin with, at least on contemporary machines...). And then you shift that 8 bits to the right...?
And just in case you weren't aware of it, if you hadn't used 0x00FF on the left hand side (promoting *pchar to the width of the right-hand operand) but (char-sized) 0xFF, the result of that operation would still be of type char, and shifting that 8 bits to the left doesn't make much sense either (as the type doesn't get expanded magically).
Another way to go about this not mentioned yet is the union:
#include <stdio.h>
struct chars_t
{
// could also go for char[2] here,
// whichever makes more sense semantically...
char first;
char second;
};
union combo_t
{
// elements of a union share the memory, i.e.
// reside at the same address, not consecutive ones
short shrt;
struct chars_t chrs;
};
int main()
{
union combo_t x;
x.chrs.first = 0x01;
x.chrs.second = 0x02;
printf( "%x", x.shrt );
return 0;
}
If you're using this in a larger context, beware of struct padding.
When doing bitwise operations, use robust code with real fixed-size integers, of known signedness. This will prevent you from writing bugs related to implicit type conversions, causing unintended signedness. The char type is particularly dangerous, since it has implementation-defined signedness. It should never be used for storing numbers.
#include <stdint.h>
void char2short(const uint8_t* pchar, uint16_t* pshort)
{
*pshort = ((uint16_t)pchar[0] << 8) | (uint16_t)pchar[1];
}

Placing '0' and '1' character in C string

I've recently begun working with C again (haven't touched it since my first couple semesters of school) and have been dealing with strings.
Currently, I'm writing a function that will convert an integer into its binary representation in the form of a string.
Here is the code I have to do this:
#include <stdio.h>
float power(int, int); //My version of the pow() function from math.h
char* itob(int);
int main ()
{
int x = 63;
const char * bin_x = itob(x);
printf("x = %d (%s)",x,bin_x);
return 0;
}
char* itob(int a){
static char bin[100];
int i;
for(i=0;((int) power(2,i) < a);i++){
bin[i] = (int)((a & ((int) power(2,i))) >> i);
}
bin[i] = '\0';
return (char*)&bin;
}
The issue I'm having is that the result of the binary operations on a I'm storing into an element of bin[] seems to be '\001' or '\000' as opposed to simply '1' or '0'. Because of this, when I printf() the result in main(), the output looks like a missing character box or if there is a 0 (if x=62 instead of 63) this is interpreted as an end of string character '\0'.
Am I storing these elements into my string incorrectly?
Yes, you are storing it incorrectly. You are storing either a 0 or a 1, but you need to store its encoding instead.
Try to replace this line:
bin[i] = (int)((a & ((int) power(2,i))) >> i);
With:
bin[i] = (int)((a & ((int) power(2,i))) >> i) ? '1' : '0';
And you can simply return bin;, there is no need neither for the cast, nor for the use of the address of operator.
Do not use pow for powers of 2, that's very inefficient, just a shift is enough. Your program wastes lots of time converting between int and float, and another tens of hundreds of cycles for the power while shifting generally takes only 1 cycle (or a little more depending on architecture). And no need to cast to int, any type shorter or equal to int will be automatically promoted to int
bin[i] = a & (1 << i) ? '1' : '0'; // or:
bin[i] = (a >> i) & 1 ? '1' : '0';
Much cleaner, shorter and faster. Another way if branching results in bad performance
bin[i] = ((a >> i) & 1) + '0';

Resources