Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use #define mask in "if" comparison

Tags:

c

I've defined in one header file two #define with a mask:

myheader.h

#define MASK_A IPC_CREAT | IPC_EXCL | 0666
#define MASK_B 0666

void myfunction(int mymask);

myfile.c

#include "myheader.h" 

... 

void myfunction(int mymask) {
   if (MASK_A == mymask) {
      printf("My mask is A\n");
      /* Do some things... */   
   } else {
      printf("My mask is B\n");
      /* Do other things...*/   
   } 
}

void main() {   

    myfunction(MASK_A);
    myfunction(MASK_B); 
}

As far as I know, with this simple program should do first MASK_A things defined in myfunctionand after that, MASK_B things, but I don't know why, both times program goes through MASK_A way.

Cast if ((int)MASK_A == mymask) doesn't work.

It looks like #define MASK_A and MASK_B are not being considered as integer, because:

If I redefine function as:

void myfunction(int mymask) {
   int _maskA=MASK_A;
   if (_maskA == mymask) {
      printf("My mask is A\n");
      /* Do some things... */   
   } else {
      printf("My mask is B\n");
      /* Do other things...*/   
   } 
}

It works fine, but it doesn't look very pretty. Anyone knows a better way to manage #define literals and integer comparison, please?

Thanks in advance.

like image 578
Alejandro Galera Avatar asked Mar 06 '23 03:03

Alejandro Galera


2 Answers

It doesn't work because Comparison operator (==) has Higher precedence than Bitwise Or (|). So when you do

 if (MASK_A == mymask) 

it results into,

if (IPC_CREAT | IPC_EXCL | 0666==mymask)

final execution is somewhat like,

if (IPC_CREAT | IPC_EXCL |( 0666==mymask))

Try defining your macro as

#define MASK_A (IPC_CREAT | IPC_EXCL | 0666)
like image 159
Code Name Jack Avatar answered Mar 10 '23 11:03

Code Name Jack


It is advised to always parenthesise your macros

#define MASK_A (IPC_CREAT|IPC_EXCL|0666)

Especially when it comes to & and |, C's precedence rules can be confusing:

#include <stdio.h>
#include <assert.h>
int main()
{
    int mask = 0xAA|0xBB00; assert(mask==0xBBAA);

    printf("%x\n", 0xAA|0xBB00 == mask);
    //prints aa because 0xAA|(0xBB00==mask /*false==0*/)  equals 0xAA
    //IOW, == has a higher precedence than |  
    //ans so 0xAA|0xBB00==mask is equivalent to 0xAA|(0xBB00==mask) 

    printf("%x\n", (0xAA|0xBB00) == mask);
    //prints 1 — parentheses force the intended grouping
}

As Denis Ritchie, the language's author, put it in the first K&R,

"Some of the operators have the wrong precedence; some parts of the syntax could be better."

He explains these precedences for | and & in his article, The Development of the C Language* where he explains that | and & were used in B instead of the short-circuiting, logical || and && (which B didn't have and neither did prehistoric C) and so the precedence rules for | and & were so that:

  if (a==b & c)

would be parsed as

 if ((a==b) & c)

The short-circuting, logical && and || were later added, but the original precedences for | and & were kept.

like image 40
PSkocik Avatar answered Mar 10 '23 10:03

PSkocik