Can scanf() turn non-zero input into zero - c

In the following code, the scanf() in main() turns one of the input numbers from a non-zero number into zero, as shown by a debugging printf() in the while loop. I've tested it on several compilers but only to keep getting the same result. Please help me out by telling me why this is such. Thank you.
#include <stdio.h>
unsigned srl (unsigned x, int k)
{
/* perform shift arithmetically */
printf("x = %u, (int) x= %d\n", x, (int) x);
unsigned xsra = (int) x >> k;
printf("\nxsra before was: %u\n", xsra);
unsigned test = 0xffffffff;
test <<= ((sizeof (int) << 3) - k); // get e.g., 0xfff00...
printf("test after shift is: %x, xsra & test = %x\n", test, xsra & test);
if (xsra & test == 0) // if xsrl is positve
return xsra;
else
xsra ^= test; // turn 1s into 0s
return xsra;
}
int sra (int x, int k)
{
/* perform shift logically */
int xsrl = (unsigned) x >> k;
unsigned test = 0xffffffff;
test << ((sizeof (int) << 3) - k + 1); // get e.g., 0xffff00...
if (xsrl & test == 0) // if xsrl is positve
return xsrl;
else
xsrl |= test;
return xsrl;
}
int main(void)
{
int a;
unsigned b;
unsigned short n;
puts("Enter an integer and a positive integer (q or negative second number to quit): ");
while(scanf("%d%u", &a, &b) == 2 && b > 0)
{
printf("Enter the number of shifts (between 0 and %d): ", (sizeof (int) << 3) - 1);
scanf("%d", &n);
if (n < 0 || n >= ((sizeof (int)) << 3))
{
printf("The number of shifts should be between 0 and %d.\n", ((sizeof (int)) << 3) - 1);
break;
}
printf("\nBefore shifting, int a = %d, unsigned b = %u\n", a, b);
a = sra(a, n);
b = srl(b, n);
printf("\nAfter shifting, int a = %d, unsigned b = %u\n", a, b);
puts("\nEnter an integer and a positive integer (q or negative second number to quit): ");
}
puts("Done!");
return 0;
}

The problem is that n is an unsigned short, which has less size than a normal int. When you call scanf("%d", &n);, it reads the value into n and potentially overwrite the existing b value if b has the memory location right after n.
All you have to do is to change that problematic line into:
scanf("%hu", &n);
the h is a modifier for unsigned short int, from here.

Related

Circular right and left shift in C

I'm doing circular right shift and left shift in C, I'm wrong somewhere. For right rotation if I give the input as 123 and number of rotations as 3, the output what I get is wrong. Help me to find the mistake please.
#include<stdio.h>
#include <stdlib.h>
void rotateLeft(unsigned long int num,int n);
void rotateRight(unsigned long int num,int n);
void bin_print(unsigned long int num);
int main()
{
printf("\tThis program is to circular right & left shift the int number by n\n\n");
printf("Possible operations\n1. circular right shift\n2. circular left shift\n");
int choice,n;
unsigned long int num;
printf("Enter your choice: ");
scanf("%d",&choice);
printf("Enter a number: ");
scanf("%lu", &num);
bin_print(num);
printf("Enter number of rotation: ");
scanf("%d", &n);
(choice==1) ? rotateRight(num,n) : rotateLeft(num,n);
}
void bin_print(unsigned long int num)
{
for(int i = 31; i >= 0; i--)
{
if((num & (1 << i))) {
printf("%d",1); // The ith digit is one
}
else {
printf("%d",0); // The ith digit is zero
}
if(i%8==0) printf(" ");
}
printf("\n");
}
void rotateLeft(unsigned long int num, int n)
{
unsigned long int val = (num << n) | (num >> (32 - n));
bin_print(val);
printf("%ld",val);
}
void rotateRight(unsigned long int num,int n)
{
unsigned long int val = (num >> n) | (num << (32 - n));
bin_print(val);
printf("%ld",val);
}
Do not assume the width
Code assumes unsigned long is 32-bit. Its width must be at least 32-bit, but could be more, like 64.
int constant
1 << i is a shifted int, yet code needs a shifted unsigned long. Use 1UL << i.
Use a matching print specifier #Support Ukraine
This implies OP might not have enabled all warnings. Save time. Enable all compiler warnings.
// printf("%ld",val);
printf("%lu",val);
#include <limits.h>
#if ULONG_MAX == 0xFFFFFFFFu
#define ULONG_WIDTH 32
#elif ULONG_MAX == 0xFFFFFFFFFFFFFFFFu
#define ULONG_WIDTH 64
#else
#error TBD code
#endif
void bin_print(unsigned long int num) {
// for(int i = 31; i >= 0; i--)
for(int i = ULONG_WIDTH - 1; i >= 0; i--)
...
// if((num & (1 << i))) {
if((num & (1UL << i))) {
Advanced
A wonderful way to get the bit-width of an integer type's value bits:
// https://stackoverflow.com/a/4589384/2410359
/* Number of value bits in inttype_MAX, or in any (1<<k)-1 where 0 <= k < 2040 */
#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
#define ULONG_WIDTH IMAX_BITS(ULONG_MAX)
Shifting more than "32"
To handle n outside the [1 ... ULONG_WIDTH) range, reduce the shift.
void rotateLeft(unsigned long num, int n) {
// Bring n into (-ULONG_WIDTH ... ULONG_WIDTH) range,
n %= ULONG_WIDTH;
// Handle negative n.
if (n < 0) n += ULONG_WIDTH;
// Cope with 0 as a special case as `num >> (ULONG_WIDTH - 0)` is bad.
unsigned long val = n == 0 ? n : (num << n) | (num >> (ULONG_WIDTH - n));
bin_print(val);
printf("%lu\n", val);
}

C: How to use decimal number in hex one to one?

I want to "convert" a decimal number to a hex number. Not like 10 -> A.
E.g.: 10 -> 0x10, 55 -> 0x55, 2021 -> 0x2021, ...
My input is an int.
I already heard something about it. You can get the first digit with modulo 10. E.g. 55 % 10 is 5. But I don't know how to get the other digits and how to put it together.
I am using this function for other purpose but I did some changes and its work fine.
you can use this :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define CHECK_ALPHA_HEX(REC_CHAR) (unsigned)('#' < REC_CHAR && REC_CHAR < 'G')
#define CHECK_NUM(REC_CHAR) (unsigned)('/' < REC_CHAR && REC_CHAR < ':')
void DEC_TO_HEX(int in, int *outval ) {
uint8_t tbuff[5];
uint8_t chr_count = 0;
uint8_t len = sprintf(tbuff,"%d",in);
while(chr_count < len) {
tbuff[chr_count] -= CHECK_NUM(tbuff[chr_count]) ? '0' : CHECK_ALPHA_HEX(tbuff[chr_count]) ? '7' : tbuff[chr_count];
*outval |= (tbuff[chr_count] << (4 *((len-1) - chr_count)));
chr_count++;
}
}
int main() {
int out = 0;
int in = 2021;
DEC_TO_HEX(in,&out);`
printf("%x",out);
}
https://godbolt.org/z/8T9Wqb87n
how to get the other digits
Remove the extracted digit from input.
Repeat the extraction of one digit, until there are no more digits in input.
how to put it together.
Learn C programming language. Write a program that implements the algorithm.
As I understand, an integer value has to be converted to another integer. From there it's just basic arithmetic, where the process generatally consists of:
Getting one digit from input.
Putting it in output.
Removing that digit from input.
shifting input & output to desired state
I came up with 3 separate such convert_* function implementations. First one is similar to common simple int->string conversion algorithms - it first converts the digits and that the results is "inverted". The second one extract the digits from propor position from input - getting the most significant base10 digit from input and moving between base10 digits of input. The third one, puts base10 digits on the end of hex number (startign from the mast significant base16 digit), and then shifts hex number to the right to handle 0x55000000 trailing zeros in result.
#include <limits.h>
#include <stdio.h>
const unsigned maxhexdigits = sizeof(unsigned) * CHAR_BIT / 4;
unsigned convert_andrevert(unsigned n) {
unsigned o = 0;
unsigned hexdigits = 0;
// Convert hex digits from "the back"
while (n && hexdigits != maxhexdigits) {
o <<= 4;
o += n % 10;
n /= 10;
++hexdigits;
}
const unsigned swaps = hexdigits / 2;
//printf("a %#x %d %d \n", o, hexdigits, swaps);
// Invert hex digits
for (unsigned i = 0; i < swaps; ++i) {
const unsigned m1 = 0xFu << (i * 4);
const unsigned m2 = 0xFu << ((hexdigits - i - 1) * 4);
const unsigned road = (hexdigits - i * 2 - 1) * 4;
// extract bits m1
unsigned t = (o & m1) << road;
//printf("b o=%#x i=%#x 1=%#x m2=%#x t=%#x road=%d\n", o, i, m1, m2, t, road);
// set bit m1 in place of m2
o = (o & ~m1) | ((o & m2) >> road);
// set bit m2 in place of m1
o = (o & ~m2) | t;
}
return o;
}
unsigned mypow10u(unsigned i) {
unsigned r = 1;
while (i--) {
r *= 10;
}
return r;
}
unsigned convert_frommax(unsigned n) {
n %= mypow10u(maxhexdigits);
unsigned o = 0;
// always start from the maximuim digit, because
// we know it's location.
for (int i = maxhexdigits - 1; i >= 0; --i) {
o <<= 4;
//printf("o=%#x u=%d pow10u(i)=%u digit=%u rest=%u\n",
//o, i, mypow10u(i),
//n / mypow10u(i),
//n % mypow10u(i));
// extract leading base10 digit
o += n / mypow10u(i);
n %= mypow10u(i);
}
return o;
}
unsigned convert_andshift(unsigned n) {
unsigned o = 0;
unsigned hexdigits = 0;
// Convert hex digits from "the back"
// put put them from the front.
while (n && hexdigits != maxhexdigits) {
o >>= 4;
o += (n % 10) << (maxhexdigits * 4 - 4);
//printf("o=%#x %d\n", o, n%10);
n /= 10;
++hexdigits;
}
// Shift right to handle leading (trailing?) zeros.
o >>= ((maxhexdigits - hexdigits) * 4);
return o;
}
void testin(unsigned r, unsigned rr) {
printf(" -> %#x %s", rr, r == rr ? "OK" : "FAIL");
}
void TEST(unsigned a, unsigned r) {
printf("%u", a);
testin(r, convert_andrevert(a));
testin(r, convert_frommax(a));
testin(r, convert_andshift(a));
printf("\n");
}
int main() {
TEST(1, 0x1);
TEST(55, 0x55);
TEST(123, 0x123);
TEST(2021, 0x2021);
TEST(12345678, 0x12345678);
}
From basic profiling, convert_andshift is the fastest function.
Here is an approach:
#include<stdio.h>
int main()
{
int num = 0;
char cNumHex[20];
puts("Enter a decimal formed hex number: ");
scanf("%d",&num);
sprintf(cNumHex, "0x%d", num);
printf("\nThe entered as hex: %s\n", cNumHex);
return 0;
}
The output:
Enter a decimal formed hex number:
49478
The entered as hex: 0x49478

Error in Program to implement cyclic redundancy check

I have tried to implement crc in c.My logic is not very good.What I have tried is to copy the message(msg) in a temp variable and at the end I have appended number of zeros 1 less than the number of bits in crc's divisor div.
for ex:
msg=11010011101100
div=1011
then temp becomes:
temp=11010011101100000
div= 10110000000000000
finding xor of temp and div and storing it in temp
gives temp=01100011101100000 counting number of zeros appearing before the first '1' of temp and shifting the characters of div right to that number and then repeating the same process until decimal value of temp becomes less than decimal value of div. Which gives the remainder.
My problem is when I append zeros at the end of temp it stores 0's along with some special characters like this:
temp=11010011101100000$#UFI#->Jp#|
and when I debugged I got error
Floating point:Stack Underflow
here is my code:
#include<stdio.h>
#include<conio.h>
#include<math.h>
#include<string.h>
void main() {
char msg[100],div[100],temp[100];
int i,j=0,k=0,l=0,msglen,divlen,newdivlen,ct=0,divdec=0,tempdec=0;
printf("Enter the message\n");
gets(msg);
printf("\nEnter the divisor\n");
gets(div);
msglen=strlen(msg);
divlen=strlen(div);
newdivlen=msglen+divlen-1;
strcpy(temp,msg);
for(i=msglen;i<newdivlen;i++)
temp[i]='0';
printf("\nModified Temp:");
printf("%s",temp);
for(i=divlen;i<newdivlen;i++)
div[i]='0';
printf("\nModified div:");
printf("%s",div);
for(i=newdivlen;i>0;i--)
divdec=divdec+div[i]*pow(2,j++);
for(i=newdivlen;i>0;i--)
tempdec=tempdec+temp[i]*pow(2,k++);
while(tempdec>divdec)
{
for(i=0;i<newdivlen;i++)
{
temp[i]=(temp[i]==div[i])?'0':'1';
while(temp[i]!='1')
ct++;
}
for(i=newdivlen+ct;i>ct;i--)
div[i]=div[i-ct];
for(i=0;i<ct;i++)
div[i]='0';
tempdec=0;
for(i=newdivlen;i>0;i--)
tempdec=tempdec+temp[i]*pow(2,l++);
}
printf("%s",temp);
getch();
}
and this part of the code :
for(i=newdivlen;i>0;i--)
divdec=divdec+div[i]*pow(2,i);
gives error Floating Point:Stack Underflow
The problem is that you wrote a 0 over the NUL terminator, and didn't put another NUL terminator on the string. So printf gets confused and prints garbage. Which is to say that this code
for(i=msglen;i<newdivlen;i++)
temp[i]='0';
printf("\nModified Temp:");
printf("%s",temp);
should be
for(i=msglen;i<newdivlen;i++)
temp[i]='0';
temp[i] = '\0'; // <--- NUL terminate the string
printf("\nModified Temp:");
printf("%s",temp);
You have to do this with integers
int CRC(unsigned int n);
int CRC_fast(unsigned int n);
void printbinary(unsigned int n);
unsigned int msb(register unsigned int n);
int main()
{
char buf[5];
strcpy(buf, "ABCD");
//convert string to number,
//this is like 1234 = 1*1000 + 2*100 + 3*10 + 4, but with hexadecimal
unsigned int n = buf[3] * 0x1000000 + buf[2] * 0x10000 + buf[1] * 0x100 + buf[3];
/*
- "ABCD" becomes just a number
- Any string of text can become a sequence of numbers
- you can work directly with numbers and bits
- shift the bits left and right using '<<' and '>>' operator
- use bitwise operators & | ^
- use basic math with numbers
*/
//finding CRC, from Wikipedia example:
n = 13548; // 11010011101100 in binary (14 bits long), 13548 in decimal
//padding by 3 bits: left shift by 3 bits:
n <<= 3; //11010011101100000 (now it's 17 bits long)
//17 is "sort of" the length of integer, can be obtained from 1 + most significant bit of n
int m = msb(n) + 1;
printf("len(%d) = %d\n", n, m);
int divisor = 11; //1011 in binary (4 bits)
divisor <<= (17 - 4);
//lets see the bits:
printbinary(n);
printbinary(divisor);
unsigned int result = n ^ divisor;// XOR operator
printbinary(result);
//put this in function:
n = CRC(13548);
n = CRC_fast(13548);
return 0;
}
void printbinary(unsigned int n)
{
char buf[33];
memset(buf, 0, 33);
unsigned int mask = 1 << 31;
//result in binary: 1 followed by 31 zero
for (int i = 0; i < 32; i++)
{
buf[i] = (n & mask) ? '1' : '0';
//shift the mask by 1 bit to the right
mask >>= 1;
/*
mask will be shifted like this:
100000... first
010000... second
001000... third
*/
}
printf("%s\n", buf);
}
//find most significant bit
unsigned int msb(register unsigned int n)
{
unsigned i = 0;
while (n >>= 1)
i++;
return i;
}
int CRC(unsigned int n)
{
printf("\nCRC(%d)\n", n);
unsigned int polynomial = 11;
unsigned int plen = msb(polynomial);
unsigned int divisor;
n <<= 3;
for (;;)
{
int shift = msb(n) - plen;
if (shift < 0) break;
divisor = polynomial << shift;
printbinary(n);
printbinary(divisor);
printf("-------------------------------\n");
n ^= divisor;
printbinary(n);
printf("\n");
}
printf("result: %d\n\n", n);
return n;
}
int CRC_fast(unsigned int n)
{
printf("\nCRC_fast(%d)\n", n);
unsigned int polynomial = 11;
unsigned int plen = msb(polynomial);
unsigned int divisor;
n <<= 3;
for (;;)
{
int shift = msb(n) - plen;
if (shift < 0) break;
n ^= (polynomial << shift);
}
printf("result: %d\n\n", n);
return n;
}
Previous problems with string method:
This is infinite loop:
while (temp[i] != '1')
{
ct++;
}
Previous problems with string method:
This one is too confusing:
for (i = newdivlen + ct; i > ct; i--)
div[i] = div[i - ct];
I don't know what ct is. The for loops are all going backward, this makes the code faster sometimes (maybe 1 nanosecond faster), but it makes it very confusing.
There is another while loop,
while (tempdec > divdec)
{
//...
}
This may go on forever if you don't get the expected result. It makes it very hard to debug the code.

Is this the proper way to count the number of 0s in a binary number?

#include <stdio.h>
int NumberOfSetBits(int);
int main(int argc, char *argv[]) {
int size_of_int = sizeof(int);
int total_bit_size = size_of_int * 8;
// binary representation of 3 is 0000011
// C standard doesn't support binary representation directly
int n = 3;
int count = NumberOfSetBits(n);
printf("Number of set bits is: %d\n", count);
printf("Number of unset bits is: %d", total_bit_size - count);
}
int NumberOfSetBits(int x)
{
int count = 0;
//printf("x is: %d\n", x);
while (x != 0) {
//printf("%d\n", x);
count += (x & 1);
x = x >> 1;
}
return count;
}
Number of set bits is: 2
Number of unset bits is: 30
int size_of_int = sizeof(int);
int total_bit_size = size_of_int * 8;
^ that will get the size of the int on the system and times it by 8 which is the number of bits in each byte
EDITED: Without the use of the ~
/*
Calculate how many set bits and unset bits are in a binary number aka how many 1s and 0s in a binary number
*/
#include <stdio.h>
unsigned int NumberOfSetBits(unsigned int);
unsigned int NumberOfUnSetBits(unsigned int x);
int main() {
// binary representation of 3 is 0000011
// C standard doesn't support binary representation directly
unsigned int n = 3;
printf("Number of set bits is: %u\n", NumberOfSetBits(n));
printf("Number of unset bits is: %u", NumberOfUnSetBits(n));
return 0;
}
unsigned int NumberOfSetBits(unsigned int x) {
// counts the number of 1s
unsigned int count = 0;
while (x != 0) {
count += (x & 1);
// moves to the next bit
x = x >> 1;
}
return count;
}
unsigned int NumberOfUnSetBits(unsigned int x) {
// counts the number of 0s
unsigned int count = 0;
while(x != 0) {
if ((x & 1) == 0) {
count++;
}
// moves to the next bit
x = x >> 1;
}
return count;
}
returns for input 3
Number of set bits is: 2
Number of unset bits is: 0
unset bits is 0? Doesn't seem right?
if I use NumberOfSetBits(~n) it returns 30
You've got a problem on some systems because you right shift a signed integer in your bit-counting function, which may shift 1's into the MSB each time for negative integers.
Use unsigned int (or just unsigned) instead:
int NumberOfSetBits(unsigned x)
{
int count = 0;
//printf("x is: %d\n", x);
while (x != 0) {
//printf("%d\n", x);
count += (x & 1);
x >>= 1;
}
return count;
}
If you fix that part of the problem, you can solve the other with:
int nbits = NumberOfSetBits(~n);
where ~ bitwise inverts the value in n, and hence the 'set bit count' counts the bits that were zeros.
There are also faster algorithms for counting the number of bits set: see Bit Twiddling Hacks.
To solve the NumberOfSetBits(int x) version without assuming 2's complement nor absence of padding bits is a challenge.
#Jonathan Leffler has the right approach: use unsigned. - Just thought I'd try a generic int one.
The x > 0, OP's code work fine
int NumberOfSetBits_Positive(int x) {
int count = 0;
while (x != 0) {
count += (x & 1);
x = x >> 1;
}
return count;
}
Use the following to find the bit width and not count padding bits.
BitWidth = NumberOfSetBits_Positive(INT_MAX) + 1;
With this, the count of 0 or 1 bits is trivial.
int NumberOfClearBits(int x) {
return NumberOfSetBits_Positive(INT_MAX) + 1 - NumberOfSetBits(x);
}
int NumberOfSetBits_Negative(int x) {
return NumberOfSetBits_Positive(INT_MAX) + 1 - NumberOfSetBits_Positive(~x);
}
All that is left is to find the number of bits set when x is 0. +0 is easy, the answer is 0, but -0 (1's compliment or sign magnitude) is BitWidth or 1.
int NumberOfSetBits(int x) {
if (x > 0) return NumberOfSetBits_Positive(x);
if (x < 0) return NumberOfSetBits_Negative(x);
// Code's assumption: Only 1 or 2 forms of 0.
/// There may be more because of padding.
int zero = 0;
// is x has same bit pattern as +0
if (memcmp(&x, &zero, sizeof x) == 0) return 0;
// Assume -0
return NumberOfSetBits_Positive(INT_MAX) + 1 - NumberOfSetBits_Positive(~x);
}
here is a proper way to count the number of zeores in a binary number
#include <stdio.h>
unsigned int binaryCount(unsigned int x)
{
unsigned int nb=0; // will count the number of zeores
if(x==0) //for the case zero we need to return 1
return 1;
while(x!=0)
{
if ((x & 1) == 0) // the condition for getting the most right bit in the number
{
nb++;
}
x=x>>1; // move to the next bit
}
return nb;
}
int main(int argc, char *argv[])
{
int x;
printf("input the number x:");
scanf("%d",&x);
printf("the number of 0 in the binary number of %d is %u \n",x,binaryCount(x));
return 0;
}

Bitmask understanding in C program

I have a program that my professor gave me for a HW, and I want to see if any of y'all can explain me how bits work. Note: I don't want you guys to give me the answer; I want to learn so if you guys can explain me how this work would be awesome so I can go ahead an start on my hw.
Instructions:
a) unsigned setbits (unsigned x, int p, int n, unsigned y) that returns x with the n bits that begin at position p (right-adjusted) set to the rightmost n bits of y, leaving the other bits unchanged. Note: it does not change the values of x and y though.
b) unsigned invertbits (unsigned x, int p, int n) that returns x with the n bits that begin at position p (right-adjusted) inverted, i.e. 1 changed to 0 and vice versa, leaving the other bits unchanged. Note: it does not change the value of x though.
#include <stdio.h>
#include <limits.h>
void bit_print(int);
int pack(char, char, char, char);
char unpack(int, int);
unsigned getbits(unsigned, int, int);
void bit_print(int a){
int i;
int n = sizeof(int) * CHAR_BIT;
int mask = 1 << (n-1); // mask = 100...0
for (i=1; i<=n; i++){
putchar(((a & mask) == 0)? '0' : '1');
a <<= 1;
if (i % CHAR_BIT == 0 && i < n)
putchar(' ');
}
putchar('\n');
}
int pack(char a, char b, char c, char d){
int p=a;
p = (p << CHAR_BIT) | b;
p = (p << CHAR_BIT) | c;
p = (p << CHAR_BIT) | d;
return p;
}
char unpack(int p, int k){ // k=0, 1, 2, or 3
int n = k * CHAR_BIT; // n = 0, 8, 16, 24
unsigned mask = 255; // mask = low-order byte
mask <<= n;
return ((p & mask) >> n);
}
// getbits() extracts n bits from position p(start counting from the right-most bit) in x
unsigned getbits(unsigned x, int p, int n){
unsigned temp = x >> (p+1-n);
unsigned mask = 0;
mask = ~mask;
mask = mask << n;
mask = ~mask;
return temp & mask;
// return (x >> (p+1-n)) & ~(~0<<n);
}
int main(){
int x = 19;
printf("The binary rep. of %d is:\n", x);
bit_print(x);
int p=pack('w', 'x', 'y', 'z');
printf("\n'w', 'x', 'y', and 'z' packed together is equal to %d. Its binary rep. is:\n", p);
bit_print(p);
printf("calling unpack(p, 0) to extract the byte # 0 from the right:\n");
bit_print(unpack(p, 0));
printf("calling unpack(p, 1) to extract the byte # 1 from the right:\n");
bit_print(unpack(p, 1));
printf("calling unpack(p, 2) to extract the byte # 2 from the right:\n");
bit_print(unpack(p, 2));
printf("calling unpack(p, 3) to extract the byte # 3 from the right:\n");
bit_print(unpack(p, 3));
unsigned result = getbits(p, 20, 7);
printf("\ncalling getbits(p, 20, 7) to extract 7 bits from bit # 20 returns %d:\n", result);
bit_print(result);
return 0;
}
Using bitwise AND & , OR |, XOR ^, NOT ~ and a proper bit mask you can manipulate bits inside a variable. You will also need bit shifts >> and <<.
So let us have an example:
Let's take a 8bit var x = 0xff and try to invert its 3'rd bit:
unsigned char x = 0xff; // Our var
unsigned char mask = 1<<3; // Our mask
x = x & ~mask; // Invert mask so its value is b1111_0111
// and make a bitwise AND with x
Every bit in x keeps its value if there is 1 in a mask, and turns into 0 when masks bit value is 0. Now x value is x = 0xf7.
Using other operators you can do whatever you want with bits :)
So for example yours unpack function does:
char unpack(int p, int k){ // k - byte offset
int n = k * CHAR_BIT; // n - bit offset (k * 8)
unsigned mask = 255; // mask with all ones at first byte (0x000f)
mask <<= n; // move mask left n times;
// Now the ones are at the k'th byte
// if k = 2 => mask = 0x0f00
return ((p & mask) >> n); // Mask out k'th byte of p and remove all zeros
// from beginning.
}
When p = 0x3579 and k = 1:
n = k * CHAR_BIT; // n = 8
mask = 255; // mask = 0x000f
mask <<= n; // mask = 0x00f0
p &= mask; // p = 0x0070
p >>= n; // p = 0x0007
I hope it will help you!

Resources