Accessing the bits in a char? - c

I have experience with Java and Python, but this is my first time really using C, for my first assignment also haha.
I'm having trouble figuring out how to convert an unsigned char to a bit, so I would be able to get/set/swap some bit values.
I'm not looking for someone to do my assignment of course, I just need help accessing the bit. I came across this Access bits in a char in C
But it seems like that method only showed how to get the last two bits.
Any help or guidance is much appreciated. I tried Googling to see if there was some sort of documentation on this, but couldn't find any. Thanks in advance!

Edit: Made changes in accordance with Chux's comment. Also introduced rotl function which rotates bits. Originally reset function was wrong (should have used the rotation instead of shift tmp = tmp << n;
unsigned char setNthBit(unsigned char c, unsigned char n) //set nth bit from right
{
unsigned char tmp=1<<n;
return c | tmp;
}
unsigned char getNthBit(unsigned char c, unsigned char n)
{
unsigned char tmp=1<<n;
return (c & tmp)>>n;
}
//rotates left the bits in value by n positions
unsigned char rotl(unsigned char value, unsigned char shift)
{
return (value << shift) | (value >> (sizeof(value) * 8 - shift));
}
unsigned char reset(unsigned char c, unsigned char n) //set nth bit from right to 0
{
unsigned char tmp=254; //set all bits to 1 except the right=most one
//tmp = tmp << n; <- wrong, sets to zero n least signifacant bits
//use rotl instead
tmp = rotl(tmp,n);
return c & tmp;
}
//Combine the two for swapping of the bits ;)
char swap(unsigned char c, unsigned char n, unsigned char m)
{
unsigned char tmp1=getNthBit(c,n), tmp2=getNthBit(c,m);
char tmp11=tmp2<<n, tmp22=tmp1<<m;
c=reset(c,n); c=reset(c,m);
return c | tmp11 | tmp22;
}

Related

How to edit single bits from an unsigned char

My goal is to write a function which receives an unsigned char as input, and returns a modified unsigned char as an output.
The char should be modified so that its first three bits are set as zeros, and the rest are left untouched. Example function written below.
Any help is greatly appreciated. Apologies for the somewhat incomplete question, this is the most accurate description I can give.
unsigned char Changebits(unsigned char b)
{
//set the first three bits of the input to zeros (for example 10110111 -> 00010111)
return //insert the modified unsigned char here
}
Please read something about bitmanipulation in C.
So your solution looks something like this (assuming 1 byte char)
unsigned char Changebits(unsigned char b)
{
return (b & 0x1Fu);
}
unsigned char Changebits(unsigned char b)
{
return b&0x1F;
}
I am assuming you know about bitwise AND operation.
suppose we have 10110111 as input. to make first three digits 0, we can simply do a bitwise on it with a number with contains 0 in first three positions and have 1 in remaining positions(00011111).
unsigned char Changebits(unsigned char b)
{
unsigned char modifier = 31; //00011111in binary is equal to 11100000 in decimal
return b & modifier; // in c '&' represents bitwise AND operation
}
Another cool way to define modifier is:
unsigned char modifier = (1<<5)-1; //using bitwise left shift

unsigned char to unsigned char array of 8 original bits

I am trying to take a given unsigned char and store the 8 bit value in an unsigned char array of size 8 (1 bit per array index).
So given the unsigned char A
Id like to create an unsigned char array containing 0 1 0 0 0 0 0 1 (one number per index)
What would be the most effective way to achieve this? Happy Thanksgiving btw!!
The fastest (not sure if that's what you menat by "effective") way of doing this is probably something like
void char2bits1(unsigned char c, unsigned char * bits) {
int i;
for(i=sizeof(unsigned char)*8; i; c>>=1) bits[--i] = c&1;
}
The function takes the char to convert as the first argument and fills the array bits with the corresponding bit pattern. It runs in 2.6 ns on my laptop. It assumes 8-bit bytes, but not how many bytes long a char is, and does not require the input array to be zero-initialized beforehand.
I didn't expect this to be the fastest approach. My first attempt looked like this:
void char2bits2(unsigned char c, unsigned char * bits) {
for(;c;++bits,c>>=1) *bits = c&1;
}
I thought this would be faster by avoiding array lookups, by looping in the natural order (at the cost of producing the bits in the opposite order of what was requested), and by stopping as soon as c is zero (so the bits array would need to be zero-initialized before calling the function). But to my surprise, this version had a running time of 5.2 ns, double that of the version above.
Investigating the corresponding assembly revealed that the difference was loop unrolling, which was being performed in the former case but not the latter. So this is an illustration of how modern compilers and modern CPUs often have surprising performance characteristics.
Edit: If you actually want the unsigned chars in the result to be the chars '0' and '1', use this modified version:
void char2bits3(unsigned char c, unsigned char * bits) {
int i;
for(i=sizeof(unsigned char)*8; i; c>>=1) bits[--i] = '0'+(c&1);
}
You could use bit operators as recommended.
#include <stdio.h>
main() {
unsigned char input_data = 8;
unsigned char array[8] = {0};
int idx = sizeof(array) - 1;
while (input_data > 0) {
array[idx--] = input_data & 1;
input_data /= 2; // or input_data >>= 1;
}
for (unsigned long i = 0; i < sizeof(array); i++) {
printf("%d, ", array[i]);
}
}
Take the value, right shift it and mask it to keep only the lower bit. Add the value of the lower bit to the character '0' so that you get either '0' or '1' and write it into the array:
unsigned char val = 65;
unsigned char valArr[8+1] = {};
for (int loop=0; loop<8; loop++)
valArr[7-loop] = '0' + ((val>>loop)&1);
printf ("val = %s", valArr);

Can I access every byte of a int variable through a char* pointer?

I was wondering if I could use a char* value to access to each byte of an int value... So I tried to use a pointer value to access the first byte of the int and a for cycle to access the other bytes of int...
Here's the code:
int char_to_bin(char* d){
int p= (int)*d;
int i=0,number=0;
if (p>=0){
do{
number+= (p%2)*(pow(10,i));
i++;
p= p/2;
}while (p>0);
}
else{
p=p *(-1);
do{
number+= (p%2)*pow(10,i);
i++;
p=p/2;
}while (p>0);
number*=-1;
}
return number;
}
long int int_to_bin(int* p){
long int j=1,number=0,number1=0,number2=0,digits;
char* c=&p;
number=char_to_bin(c);
for (j;j<(sizeof(int)/sizeof(char));j++){
number1=char_to_bin(c+j);
digits=floor(log10(abs(number1))) + 1;
number2=number1*pow(10,digits);
number=number1+number2;
}
return number;
}
int main(){
char k= 100;
char* j= &k;
int inte=100;
int *h;
h= &inte;
int c= char_to_bin(j);
printf("%d\n",c);
long int d= int_to_bin(h);
printf("%ld\n",d);
}
the function int char_to_bin(char* d) converts a pointed char value to a binary number, and all the tests I've done on it show it works. But as I use int char_to_bin(char* d) in int_to_bin(int* p) something goes wrong.
Basically, int_to_bin(int* p) should convert the first byte of the pointed int in binary, and then convert the following bytes (since char* points at one only byte) to decimal, multiply the bytes for 10^(number of digits), so that I might get a number like "000000001100100" for example but something goes wrong and the result of the function is far different from binary, plus, i have tried to put a printf("%d \n",number1) in the int_to_bin(int* p) function, like this:
long int int_to_bin(int* p){
long int j=1,number=0,number1=0,number2=0,digits;
char* c=&p;
number=char_to_bin(c);
for (j;j<(sizeof(int)/sizeof(char));j++){
number1=char_to_bin(c+j);
printf("%d \n",number1); //---------------here------------------
digits=floor(log10(abs(number1))) + 1;
number2=number1*pow(10,digits);
number=number1+number2;
}
return number;
}
to check the value contained in the given memory address... As far as I know, int variable types occupy 4 bytes of memory, and the sum of the content of the bytes is the value or the variable... But I get results that summed are totally different from the variable value.
Is there anything to be done to fix this, or should I just give up and try to convert the int passed int_to_bin(int* p) into char and pass it to the char_to_bin(char* p) function?
As far as I know, int variable types occupy 4 bytes of memory, and the
sum of the content of the bytes is the value or the variable...
Well, int is sizeof(int) bytes, which is usually 4 on modern PC operating systems (both 64 and 32 bit), but it can be anything as long as sizeof(short) <= sizeof(int) <= sizeof(long). So always use sizeof instead of hard-coded value.
But value is not sum of contents... That would be very wasteful, same bytes in different order would give same int. Value is, depending on byte order, and assuming unsigned numbers:
(c[0] << 24) | (c[1] << 16) | (c[2] << 8) | (c[3] << 0); // big endian
or
(c[3] << 24) | (c[2] << 16) | (c[1] << 8) | (c[0] << 0); // little endian
where unsigned char *c = (unsigned char*)(&unsigned_int_variable);.
Note that even though char* pointers are exception (see comments), generally setting pointers of different types to point to values breaks so called "strict aliasing rules", which you should read about before doing this kind of thing.

2 Chars to Short in C

I've got 2 chars.
Char 128 and Char 2.
How do I turn these chars into the Short 640 in C?
I've tried
unsigned short getShort(unsigned char* array, int offset)
{
short returnVal;
char* a = slice(array, offset, offset+2);
memcpy(&returnVal, a, 2);
free(a);
return returnVal;
}
But that didn't work, it just displays it as 128. What's the preferred method?
Probably the easiest way to turn two chars, a and b, into a short c, is as follows:
short c = (((short)a) << 8) | b;
To fit this into what you have, the easiest way is probably something like this:
unsigned short getShort(unsigned char* array, int offset)
{
return (short)(((short)array[offset]) << 8) | array[offset + 1];
}
I found that the accepted answer was nearly correct, except i'd run into a bug where sometimes the top byte of the result would be 0xff...
I realized this was because of C sign extension. if the second char is >= 0x80, then converting 0x80 to a short becomes 0xff80. Performing an 'or' of 0xff80 with anything results in the top byte remaining 0xff.
The following solution avoids the issue by zeroing out the top byte of b during its implicit conversion to a short.
short c = (((short)a) << 8) | (0x00ff & b);
I see that there is already an answer, but I'm a bit puzzled about what was going on with your original attempt. The following code shows your way and a technique using a union. Both seem to work just fine. I suppose you might have been running into an endianness problem. Anyway, perhaps this demonstration will be useful even if your problem is already solved.
#include <stdio.h>
#include <string.h>
int main()
{
short returnVal;
char a[2];
union {
char ch[2];
short n;
} char2short;
a[0] = 128;
a[1] = 2;
memcpy(&returnVal, a, 2);
printf("short = %d\n", returnVal);
char2short.ch[0] = 128;
char2short.ch[1] = 2;
printf("short (union) = %d\n", char2short.n);
return 0;
}
Outputs:
short = 640
short (union) = 640
I see that you are not actually trying to shift bits but assemble the equivelant of hex values together, like you would color values in CSS.
Give this code a shot:
char b1=128,b2=2;
char data[16];
sprintf((char *)data,"%x%x",(BYTE)b2,(BYTE)b1);
short result=strtol(data,(char **)NULL, 16);

How do you perform an XOR operation of a unsigned long integer and a character array in C?

These are my two variables with which I want to do an xor operation (in C).
unsigned long int z=0xB51A06CD;
unsigned char array[] = {0xF0,0xCC,0xAA,0xF0};
desired output= 0X45D6AC3D
I know I cannot do a simple z ^ array, because it's a character array and not a single character. Will I have to do XOR of one byte at a time or is there a function for it in C?
I am trying all kinds of crazy things to get it done, but failing miserably all the time. If anyone can help me out with a small code snippet or at least a rough idea, I would be extremely grateful.
Cast the array, which is treat as a pointer to the first element in an expression like this one, to a long pointer instead of char pointer , and dereference it.
unsigned long result = z ^ *(unsigned long *)array;
Just make an unsigned long int out of your array (warning, it depends on the machine endianness!):
unsigned long int z=0xB51A06CD;
unsigned char array[] = {0xF0,0xCC,0xAA,0xF0};
unsigned long int w = 0;
w |= array[0] << 0;
w |= array[1] << 8;
w |= array[2] << 16;
w |= array[3] << 24;
unsigned long output = z ^ w;
unsigned long int z=0xB51A06CD;
unsigned char array[] = {0xF0,0xCC,0xAA,0xF0};
unsigned long tmp;
memcpy(&tmp, array, sizeof tmp);
... z ^ tmp ...
Note that this still makes a number of non-portable assumptions: that unsigned long is 4 bytes, and that the system's endianness is what you expect it to be.
As others mentioned, you have to worry about endianness and size of long. Here's how to make it safe:
1) instead of unsigned long, use uint32_t (from inttypes.h), to be sure you get a 4 byte type.
2) use htonl() as a platform-independent way to ensure you interpret the array as a big-endian value
z ^ htonl(*(uint32_t *)array);

Resources