bit operations

Discussion in 'C Programming' started by Mark, Nov 16, 2009.

  1. Mark

    Mark Guest

    Hello

    I had to make some mechanism to turn on/off debugging messages at run-time
    in various modules of a project. This is what I've come up with: I defined
    several constants, each with exactly one bit set, and a global variable
    which should be defined in a particular module and assigned with one or a
    few values TAG_1...TAG_4:

    /* debug.h */
    #ifndef DEBUG_H
    #define DEBUG_H

    #include <stdio.h>

    #define TAG_1 0x00000001
    #define TAG_2 0x00000002
    #define TAG_3 0x00000004
    #define TAG_4 0x00000008

    extern unsigned long debug_mask;

    #define DEBUG(tag, fmt, arg) \
    do { \
    if (0 == ((~debug_mask) & (tag))) { \
    printf(fmt, arg); \
    } \
    } while (0)

    #endif /* DEBUG_H */

    /* example of usage*/
    #include "debug.h"

    unsigned long debug_mask;

    int main(void)
    {
    int i=1;
    char p='c';

    debug_mask = TAG_4 | TAG_2;

    DEBUG(TAG_4, "i=%d\n", i);
    DEBUG(TAG_2, "p=%c\n", p);
    return 0;
    }

    Right now I need only one argument passed. It appears the macro works as
    expected, or I have not spotted bugs yet.
    Is there anything wrong with this simple implementation (especially bit
    operations)? Any advices are welcome.

    --
    Mark
    Mark, Nov 16, 2009
    #1
    1. Advertising

  2. Mark

    Seebs Guest

    On 2009-11-16, Mark <> wrote:
    > #define DEBUG(tag, fmt, arg) \
    > do { \
    > if (0 == ((~debug_mask) & (tag))) { \


    Why not
    if (debug_mask & (tag))

    ?

    > Right now I need only one argument passed. It appears the macro works as
    > expected, or I have not spotted bugs yet.
    > Is there anything wrong with this simple implementation (especially bit
    > operations)? Any advices are welcome.


    If you feel safe relying on C99, you can modify the macro to pass a variable
    argument list.

    Me, I generally write this as, roughly:

    int debug(int level, char *fmt, ...) {
    va_list ap;
    int r;
    if (level > debuglevel)
    return 0;
    va_start(ap, fmt);
    r = vfprintf(stderr, fmt, ap);
    va_end(ap);
    return r;
    }

    I know it's probably more expensive to always make the call, but I have
    usually found that I simply don't care much. And yes, tags and bit
    masks are probably better, I hadn't bothered yet.

    -s
    --
    Copyright 2009, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
    Seebs, Nov 16, 2009
    #2
    1. Advertising

  3. Mark

    Mark Guest

    Mark wrote:
    > I had to make some mechanism to turn on/off debugging messages at run-
    > time in various modules of a project. This is what I've come up with:
    > I defined several constants, each with exactly one bit set, and a
    > global variable which should be defined in a particular module and
    > assigned with one or a few values TAG_1...TAG_4:



    Forgot to mention that 'debug_mask' is controlled from a command-line
    interface.

    --
    Mark
    Mark, Nov 16, 2009
    #3
  4. Mark

    Mark Guest

    Seebs wrote:
    > On 2009-11-16, Mark <> wrote:
    >> #define DEBUG(tag, fmt, arg) \
    >> do { \
    >> if (0 == ((~debug_mask) & (tag))) { \

    >
    > Why not
    > if (debug_mask & (tag))
    >


    This is true only when every bit of 'debug_mask' is set, but it is not
    necessary the case. Or I'm missing something ?

    --
    Mark
    Mark, Nov 16, 2009
    #4
  5. Mark

    Seebs Guest

    On 2009-11-16, Mark <> wrote:
    > Seebs wrote:
    >> On 2009-11-16, Mark <> wrote:
    >>> #define DEBUG(tag, fmt, arg) \
    >>> do { \
    >>> if (0 == ((~debug_mask) & (tag))) { \


    >> Why not
    >> if (debug_mask & (tag))


    > This is true only when every bit of 'debug_mask' is set, but it is not
    > necessary the case. Or I'm missing something ?


    Waiiiit. I just realized that what you wrote is... well, it's surprising
    to me. See, I'm used to the "mask" being the set of debug bits we care
    about. So I'd usually do:

    #define BEER 0x1
    #define ANIME 0x2
    #define PIZZA 0x4

    debug(BEER, "we have obtained delicious beer");
    debug(ANIME | PIZZA, "we are going to watch bad dubs and eat pizza");

    The way this would work, then, you'd set debug_mask to, say, "BEER | PIZZA"
    if you were interested only in messages that had to do with pizza and beer.
    Then, the test I use would be:

    debug_mask = BEER | PIZZA; // 0x05
    ...
    if (debug_mask & (ANIME | PIZZA))

    so that'd be 0x5 & 0x6, and since 0x4 is set in both, the result is 0x4,
    so it's non-zero, so we execute the code.

    It looks like your test is:
    if (0 == (~(debug_mask) & (ANIME | PIZZA)))

    assuming a 16-bit int to save typing, that's
    if (0 == (~(0x5) & (0x6)))
    which is
    if (0 == (0xfffa & 0x6))

    .... which means that you match, not on the things that are set, but on the
    things that AREN'T set. So it looks like your intent is that the mask shows
    messages which are being suppressed. So for you, "debug_mask = BEER | PIZZA"
    means "shut up about the beer and pizza, I just wanna watch Ranma", which
    is the opposite of the idiom I'm used to.

    -s
    --
    Copyright 2009, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
    Seebs, Nov 16, 2009
    #5
  6. Mark

    Mark Guest

    Seebs wrote:
    [snip]
    > The way this would work, then, you'd set debug_mask to, say, "BEER |
    > PIZZA" if you were interested only in messages that had to do with
    > pizza and beer. Then, the test I use would be:
    >
    > debug_mask = BEER | PIZZA; // 0x05
    > ...
    > if (debug_mask & (ANIME | PIZZA))
    >
    > so that'd be 0x5 & 0x6, and since 0x4 is set in both, the result is
    > 0x4, so it's non-zero, so we execute the code.


    Yes, you are absolutely right. Thanks a lot.

    --
    Mark
    Mark, Nov 16, 2009
    #6
  7. Mark writes:
    > (...)
    > #define TAG_4 0x00000008


    This has type int. Neither the 0x nor all the zeroes change that.
    Bitmasks should usually have unsigned type, provided you make quite
    sure they match the type you mask against:

    > extern unsigned long debug_mask;


    so make that 0x...zeroes if you feel a need for them...8UL.

    > printf(fmt, arg); \


    Error/debug messages should normally go to go to stderr, not stdout.
    fprintf(stderr, fmt, arg);

    --
    Hallvard
    Hallvard B Furuseth, Nov 16, 2009
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Sanket Suryawanshi

    bit operations in Java

    Sanket Suryawanshi, Jan 23, 2004, in forum: Java
    Replies:
    3
    Views:
    7,073
    Jon A. Cruz
    Jan 23, 2004
  2. Jesus M. Salvo Jr.
    Replies:
    2
    Views:
    4,160
    robert
    Feb 11, 2006
  3. Replies:
    3
    Views:
    1,750
    Timothy Bendfelt
    Jan 19, 2007
  4. Replies:
    9
    Views:
    969
    Juha Nieminen
    Aug 22, 2007
  5. Jeff.M
    Replies:
    6
    Views:
    172
    Lasse Reichstein Nielsen
    May 4, 2009
Loading...

Share This Page