wwe has asked for the wisdom of the Perl Monks concerning the following question:

Hi everybody, I have program which takes some value from a database (active directory, attribute UserAccountControl more info: http://msdn.microsoft.com/en-us/library/ms680832(v=vs.85).aspx) which contains many different things coded as a bitmask. Most common values are 512 for a 'normal' user and 514 for 'disabled' user. I need to know if this user account is active or disabled. I know this value is corresponds to a bit number two e.g. if the value matches 00000010 this account is disabled and in case it matches 00000000 this account is enabled. I followed some discussions here but still not sure how to do this kind of calculation in right way :-((

I managed to get right output using the & operator $bitmask_value & 2, see example code:

use strict; use warnings; my @bitmask_value = ( 512, 514, 210, 328, 2, 1, 65535 ); foreach my $bitmask_value ( @bitmask_value ) { print 'bit 2 is ', $bitmask_value & 2 ? 'set' : 'not set', " for v +alue [$bitmask]\n"; }
could you please tell me if there is some major problem or if I can trust this code? thank yo in advance

Replies are listed 'Best First'.
Re: bitmask check
by Eliya (Vicar) on Mar 29, 2011 at 17:10 UTC

    I can't see any major problem — only a minor one, which is that [$bitmask] should most likely have been [$bitmask_value] :)

    In other words, & is the correct operator to test if certain bits are set.

    In case you want to test if more than one bit is set, you should check if the masked value equals the mask, not only if it's true, i.e.

    if (($value & $mask) == $mask) ...

    Example:

    my $mask = 0b00001110; # test if bits 2,3,4 are set check($_, $mask) for 0b01101110, 0b01100110; sub check { my ($value, $mask) = @_; printf " val %08b\n", $value; printf "mask %08b\n", $mask; print " & --------\n"; printf " %08b ", $value & $mask; if ( ($value & $mask) == $mask ) { # equals mask? print "=> all tested bits set"; } elsif ( $value & $mask ) { # just true? print "=> some tested bits set"; } print "\n\n"; } __END__ val 01101110 mask 00001110 & -------- 00001110 => all tested bits set val 01100110 mask 00001110 & -------- 00000110 => some tested bits set
Re: bitmask check
by ikegami (Patriarch) on Mar 29, 2011 at 17:30 UTC

    Gotta watch out for precedence when dealing with the bitwise ops, but there's no precedence issue in the code you posted.

    a & b == c # XXX, means a & (b == c) (a & b) == c # ok

    Just trying to guess at your problem since the code you posted does not exhibit the problem you describe. (It exhibits a strict error.)

Re: bitmask check
by lostjimmy (Chaplain) on Mar 29, 2011 at 18:51 UTC
    As others have said, there isn't anything wrong with your code; I just wanted to add another common method for doing bit tests in to the mix. This sub will test for a single bit being set.
    sub bit_test { my ($value, $bit) = shift; return $value & (1 << $bit); }

      I know this is 2 years old but I stumbled on this and it might similarly confuse someone else.

      THIS is the corrected bit_test subroutine

      sub bit_test { my ($value, $bit) = @_; return $value & (1 << $bit); }

      Original code would only test the first bit position (1 << 0).