Can`t comprehend the bitwise operations - c

Reading the K&R book I stumbled upon chapter 2.9 which describes bitwise operators in C. Right in the beginning there is this claim:
The bitwise AND operator & is often used to mask off some set of bits, for example
n = n & 0177;
sets to zero all but the low-order 7 bits of n.
I am a bit confused with the true meaning of it. How does hexadecimal (if i got it right) 0177 represent low-order 7 bits? I tried to test it in code and below is what I did:
#include <stdio.h>
int main()
{
int n = 1490;
n = n & 0177;
printf("%i\n", n);
}
The output of the code is 82. Converting 1490 to binary I got 10111010010 and after setting all bits to zero apart from 7 low order bits i ended up with 1010010 which really equals 82 in decimal. Trying to understand the logic under the hood I applied &(AND) operator manually but it resulted in a completely different number. What I am doing wrong?

Please be aware that 0177 is not hexadecimal but the octal form of binary 01111111. Each octal digit represent 3 bits, and the leading 0 tells the compiler to interpret it that way.
So the operation is
decimal 1490 10111010010
octal 0177 00001111111
AND -----------
decimal 82 00001010010

The compiler interprets prefix 0 as base 8.
So 177(8) = 127(10) = 1111111(2).
That's your 7 bits right there.

Related

What is ilogb() in c?

What does ilogb() do? I looked it up on Google but I didn't understand it.
#include <stdio.h>
#include <math.h>
int main()
{
float num;
printf("%f",(float)ilogb(125));
return 0;
}
Output:
6.000000
Process returned 0 (0x0) execution time : 0.764 s
Press any key to continue.
Why does it return 6?
What does ilogb() do?
Why does it return 6?
When FLT_RADIX, defined in <float.h>, has value 2, ilogb() returns the position of the most significant 1 in the binary representation of the argument.
For example: 125 is "0b1111101"; the most significant 1 is at position 6; ilogb(125) returns 6 as your code printed.
Or 0.25 is "0b0.01"; ilogb(0.25) returns -2.
ilogb() is a logarithm base 2 operation, but it's meant to be used specifically on floating point numbers, and returns an integer. To understand what it means to take the exponent part of a floating point number you need to know about floating point numbers.
A floating point number isn't just one number, but a combination of three. Even though you write -333.6, inside the computer it looks more like (-1)*(3.336)*(2^2), a bit like scientific notation but using a 2 instead of a 10. So you have one bit for the sign, a few bits for the exponent, and a few for the actual number (the mantissa). This is what the number 125 looks like as a single-precision floating point which is what c uses:
0 000110 11110100000000000000000//notice the first digit of the mantissa is missing because it's always 1
(sign = 1) (exponent = 110) (mantissa = 1.111101)
In binary, this is (1)*(1.111101)*(10^110), in decimal it is (1)*(1.953125)*(2^6)
Back to ilogb(): What this does is return the exponent part of the number, in this case 110 which is a 6.

left shifting unsigned int to 32 bits, generates warning [duplicate]

I recently picked up a copy of Applied Cryptography by Bruce Schneier and it's been a good read. I now understand how several algorithms outlined in the book work, and I'd like to start implementing a few of them in C.
One thing that many of the algorithms have in common is dividing an x-bit key, into several smaller y-bit keys. For example, Blowfish's key, X, is 64-bits, but you are required to break it up into two 32-bit halves; Xl and Xr.
This is where I'm getting stuck. I'm fairly decent with C, but I'm not the strongest when it comes to bitwise operators and the like.
After some help on IRC, I managed to come up with these two macros:
#define splitup(a, b, c) {b = a >> 32; c = a & 0xffffffff; }
#define combine(a, b, c) {a = (c << 32) | a;}
Where a is 64 bits and b and c are 32 bits. However, the compiler warns me about the fact that I'm shifting a 32 bit variable by 32 bits.
My questions are these:
What's bad about shifting a 32-bit variable 32 bits? I'm guessing it's undefined, but these macros do seem to be working.
Also, would you suggest I go about this another way?
As I said, I'm fairly familiar with C, but bitwise operators and the like still give me a headache.
EDIT
I figured out that my combine macro wasn't actually combining two 32-bit variables, but simply ORing 0 by a, and getting a as a result.
So, on top of my previous questions, I still don't have a method of combining the two 32-bit variables to get a 64-bit one; a suggestion on how to do it would be appreciated.
Yes, it is undefined behaviour.
ISO/IEC 9899:1999 6.5.7 Bitwise shift operators ¶3
The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand. If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.
C11 aka ISO/IEC 9899:2011 says the same.
You should first cast b to the target integer type. Another point is that you should put parentheses around the macro parameters to avoid surprises by operator precedences. Additionally, the comma operator is very useful here, allowing you to avoid the braces, so that the macro can be used as a normal command, closed with a semicolon.
#define splitup(a,b,c) ( (b) = (a) >> 32, (c) = (a) & 0xffffffff )
#define combine(a,b,c) ( (a) = ((unsigned long long)(b) << 32) | (c) )
Additional casts may be necessary for `splitup to silence warnings about precision loss by over-paranoid compilers.
#define splitup(a,b,c) ( (b) = (unsigned long)((a) >> 32), (c) = (unsigned long)((a) & 0xffffffff) )
And please don't even think about using your self-written encryption for production code.
Shifting a 32-bit value by 32 bits or more is undefined in C and C++. One of the reasons it was left undefined is that on some hardware platforms the 32-bit shift instruction only takes into account 5 lowest bits of the supplied shift count. This means that whatever shift count you pass, it will be interpreted modulo 32. Attempting to shift by 32 on such platform will actually shift by 0, i.e. not shift at all.
The language authors did not want to burden the compilers written for such platform with the task of analyzing the shift count before doing the shift. Instead, the language specification says that the behavior is undefined. This means that if you want to get a 0 value from a 32-bit shift by 32 (or more), it is up to you to recognize the situation and process it accordingly.
what's bad about shifting a 32-bit variable 32 bits?
Its better to assign 0 to n-bit integer than to shift it by n-bits.
Example:
0 0 1 0 1 ----- 5 bit Integer
0 1 0 1 0 ----- 1st shift
1 0 1 0 0 ----- 2nd shift
0 1 0 0 0 ----- 3rd shift
1 0 0 0 0 ----- 4th shift
0 0 0 0 0 ----- 5th shift (all the bits are shifted!)
I still don't have a method of combining the two 32-bit variables to get a 64-bit one
Consider: a is 64 bit, b and c are 32 bit
a = b;
a = a << 32; //Note: a is 64 bit
a = a | c;
Unless this is some "reinventing the wheel to understand how it works" project, don't implement your own crypto functions.
Ever.
It's hard enough to use the available algorithms to work (and to choose the right one), don't shoot yourself in the foot by putting in production some home grown cryptor API. Chances are your encryption won't encrypt
What's bad about shifting a 32-bit variable 32 bits?
In addition to what have been already said, the 32nd bit is the sign bit, and you may get sign extension to preserve the sing, thereby losing significant bits.

Subtracting 1 from 0 in 8 bit binary

I have 8 bit int zero = 0b00000000; and 8 bit int one = 0b00000001;
according to binary arithmetic rule,
0 - 1 = 1 (borrow 1 from next significant bit).
So if I have:
int s = zero - one;
s = -1;
-1 = 0b1111111;
where all those 1s are coming from? There are nothing to borrow since all bits are 0 in zero variable.
This is a great question and has to do with how computers represent integer values.
If you’re writing out a negative number in base ten, you just write out the regular number and then prefix it with a minus sign. But if you’re working inside a computer where everything needs to either be a zero or a one, you don’t have any minus signs. The question then comes up of how you then choose to represent negative values.
One popular way of doing this is to use signed two’s complement form. The way this works is that you write the number using ones and zeros, except that the meaning of those ones and zeros differs from “standard” binary in how they’re interpreted. Specifically, if you have a signed 8-bit number, the lower seven bits have their standard meaning as 20, 21, 22, etc. However, the meaning of the most significant bit is changed: instead of representing 27, it represents the value -27.
So let’s look at the number 0b11111111. This would be interpreted as
-27 + 26 + 25 + 24 + 23 + 22 + 21 + 20
= -128 + 64 + 32 + 16 + 8 + 4 + 2 + 1
= -1
which is why this collection of bits represents -1.
There’s another way to interpret what’s going on here. Given that our integer only has eight bits to work with, we know that there’s no way to represent all possible integers. If you pick any 257 integer values, given that there are only 256 possible bit patterns, there’s no way to uniquely represent all these numbers.
To address this, we could alternatively say that we’re going to have our integer values represent not the true value of the integer, but the value of that integer modulo 256. All of the values we’ll store will be between 0 and 255, inclusive.
In that case, what is 0 - 1? It’s -1, but if we take that value mod 256 and force it to be nonnegative, then we get back that -1 = 255 (mod 256). And how would you write 255 in binary? It’s 0b11111111.
There’s a ton of other cool stuff to learn here if you’re interested, so I’d recommend reading up on signed and unsigned two’s-complement numbers.
As some exercises: what would -4 look like in this format? How about -9?
These aren't the only ways you can represent numbers in a computer, but they're probably the most popular. Some older computers used the balanced ternary number system (notably the Setun machine). There's also the one's complement format, which isn't super popular these days.
Zero minus one must give some number such that if you add one to it, you get zero. The only number you can add one to and get zero is the one represented in binary as all 1's. So that's what you get.
So long as you use any valid form of arithmetic, you get the same results. If there are eight cars and someone takes away three cars, the value you get for how many case are left should be five, regardless of whether you do the math with binary, decimal, or any other kind of representation.
So any valid system of representation that supports the operations you are using with their normal meanings must produce the same result. When you take the representation for zero and perform the subtraction operation using the representation for one, you must get the representation such that when you add one to it, you get the representation for zero. Otherwise, the result is just wrong based on the definitions of addition, subtraction, zero, one, and so on.

Bit arithmetic in C

Say we have 11101111 stored in the address address, how would I add the first 4 bits to the last 4 bits?
My prof showed us we can do this (*address)/16 + (*address)%16 but I don't understand why it works. Can someone explain where the division and modulo with 16 come from?
#VanGo, See to perform operation on bits, you have to learn bitwise operator first.
I am explaining your problem here.
11101111 (is in binary form) and is equivalent to 239 (in decimal).
Now you have to add 1110 in 1111. In order to get these two pair of 4 bits from 11101111, you have to perform bitwise operation on 11101111.
To get higher 4 bits, shift 11101111 four times from left to right.
*address >> 4 :- is equal to *address/16
internally compiler convert *address>>4 into (*address)/(2 pow 4).
To get lower 4 bits, either perform (*address)&0x0f or (*address)%16. Both operation will clear all bits except lower 4 bits.
printf(".....%d\n",(((*address)>>4) + ((*address)&0x0f)));
hope it helps you.

Integer representation as float, clarification needed

Take
int x = 5;
float y = x;
//"I know it's a float .. you know it's a float .. but take it's address
// and pretend you're looking at an integer and then dereference it"
printf("%d\n", *(int*)&y); //1084227584
Why am i seeing this number?
5 in binary is 0101
5 can be thought of as (1.25 * 2^2), which means that
Can be represented as:
[sign bit] - 0
[8 bits worth of exp] - 129 (129-127=2) - 1000|0001
[23 bits of .xxxxxxx] - 25 - 1100|1
Put together, i have
[sign bit][8 bits worth of exp][23 bits worth of .xxx]
0 10000001 11001000000000 //2126336
What am i missing please?
Others have pointed out it's not portable... but you know this already, and you've specified 64-bit OS X. Basically, you have the mantissa wrong. 1.25 is represented with an implicit leading bit for 1.0. The first explicit bit of the mantissa represents 0.5 and the second bit 0.25. So the mantissa is actually: 01000000000000000000000.
The sign bit 0, and biased exponent 10000001, followed by the mantissa gives:
0x40a00000 which is 1084227584 decimal.
Why am i seeing this number? Because you are printing a float as an int.
I know, I know, you clearly already know this, but the bottom line is the behaviour is undefined. On your system are ints and floats the same size? Have you looked up the standards your compiler uses to store floating points?

Resources