views:

185

answers:

3

I found the following thread:
http://stackoverflow.com/questions/777617/calculate-broadcast-address-from-ip-and-subnet-mask and there the link to http://lpccomp.bc.ca/netmask/netmask.c

Could someone please explain the following line, I don't understand:

for ( maskbits=32 ; (mask & (1L<<(32-maskbits))) == 0 ; maskbits-- )

especially mask & (1L<<(32-maskbits))

+1  A: 

Have a look at bitwise operators, specifically left shift.

http://en.wikipedia.org/wiki/Bitwise_operation#Shifts_in_C.2C_C.2B.2B_and_Java

WOPR
+6  A: 

<< is the bitwise left shift operator; it shifts the bits of a value left by the given amount. Thus 1L<<(32-maskbits) shifts the value 1 to the left 32-maskbits times.

& is the bitwise AND operator.

So the loop expression mask & (1L<<(32-maskbits)) == 0 tests all the bits within the value of mask, from lower to higher. The loop will stop on the first (lowest) nonzero bit of mask, at which point maskbits will contain the number of bits above (and including) that bit.

E.g.

  • if mask == 0xFFFF mask == 0xFFFFFFFF (== binary 11111111111111111111111111111111), the loop will stop on the first iteration, and maskbits will be 32
  • if mask == 0x0001 mask == 0x00000001 (== binary 00000000000000000000000000000001), the loop will again stop on the first iteration, and maskbits will be 32
  • if mask == 0x1000 mask == 0x01000000 (== binary 00000001000000000000000000000000), the loop will stop on the 24th iteration, and maskbits will be 8
Péter Török
question: I get the bitwise AND operation to check when to stop the bits counting, I don't get why using the left shifting with a long int. `1` was not enough?
dierre
thanks for the explanation!
mspoerr
@dierre, to avoid integer overflow. On some platforms an `int` is only 16 bits long, where if you left shift any `int` value by more than 16, the result is undefined (can be 0). Declaring the value as `long` ensures it is at least 32 bits long.
Péter Török
one more question: I am a bit confused about the "1L" statement. What is it exactly?
mspoerr
@mspoerr: it's a long int. Read above Peter's comment.
dierre
Peter are you sure the last example is correct? `0x1000` shouldn't give `maskbits=20`?
dierre
@dierre: ok - thanks.
mspoerr
@dierre, oops, right. The 4-digit hex values represented only 16 bits. Fixed, thanks :-)
Péter Török
@mspoerr: I wrote an example. Maybe it could help you.@Peter Torok: np.
dierre
Shift of signed values is tricky and can lead to undefined behavior. In the example if `long` has width 32, for the value of `maskbits` being 1 the shift reads `1L << 31` which may be UB. So here the`1L` should be replaced at least with a `1UL` to obtain an `unsigned long` value for the mask. Even better would be to use `UINT32_C(1)` for it.
Jens Gustedt
+1  A: 

To see what's happening: run it.

#include <stdio.h> 
#include <iostream>
using namespace std;

char *binary (unsigned int v) {
static char binstr[33] ;
int i ;

binstr[32] = '\0' ;
for (i=0; i<32; i++) {
binstr[31-i] = v & 1 ? '1' : '0' ;
v = v / 2 ;
}

return binstr ;
}

int main(void){  

  unsigned long maskbits,mask;  

mask = 0x01000000;
cout << "MASK IS: " << binary(mask) << "\n";
cout << "32 is: " << binary(32) << "\n\n";
for ( maskbits=32 ; (mask & (1L<<(32-maskbits))) == 0 ; maskbits-- ) {
cout << "maskbits: " << binary(maskbits) << "\n";
cout << "\t(32-maskbits): " << binary((32-maskbits)) << "\n";
cout << "\t1L<<(32-maskbits): " << binary((1L<<(32-maskbits))) << "\n";
cout << "\t(mask & (1L<<(32-maskbits))): " << binary((mask & (1L<<(32-maskbits)))) << "\n\n";

}

cout << "\nFinal maskbits: " << maskbits;

return 0;
}

http://ideone.com/eB8Kp

dierre
thank you for the great example!
mspoerr