tags:

views:

256

answers:

6
+2  Q: 

Macro questions

On a software project (some old C compiler) we have a lot of variables which have to be saved normal and inverted.

Has somebody a idea how i can make a macro like that?

SET(SomeVariable, 137);

which will execute

SomeVariable = 137;
SomeVariable_inverse = ~137;

Edit:

The best Solution seems to be:

#define SET(var,value) do { var = (value); var##_inverse = ~(value); } while(0)

Thanks for the answers

+11  A: 

Try this

#define SET(var,value) do { var = (value); var##_inverse = ~(value); } while(0)

EDIT

Couple of links to the reason behind adding a do/while into the macro

JaredPar
Is there an article somewhere explaining why you use a macro construction out of a do loop? I'm curious why...
Tom Ritter
In short: the do..while wrapping lets the macro as a whole behave as a statement, which is good. Think if/else, braces, and stuff.
unwind
The general idea is that you want a macro that will work just like a function call, which means you can write things like "SET(a, 1);" or "if (foo) SET(a, 1); else SET(a, 2);". See http://c-faq.com/cpp/multistmt.html for details.
David Thornley
@Tom, I added a few links that go into detail about why this is good practice for multi-statement macros.
JaredPar
http://stackoverflow.com/questions/257418/do-while-0-what-is-it-good-for
dmckee
@dmckee, missed that one (added).
JaredPar
Just one minor thing should be added - using the ## token pasting operator needs to go through some macro indirection hoops to correctly handle cases where one or both operands is a macro itself. See http://stackoverflow.com/questions/216875/-in-macros/217181#217181
Michael Burr
It may be theoretically a good solution but in 18+ yrs I've never seen it being necessary so I'd rather recommend something that makes the macro more readable to take away macros bad rep....
epatel
+2  A: 
#define SetInverse(token, value) { token = value; token##_inverse = ~value; }

Jinx, Jared - like the while (0) in yours

plinth
This becomes a bit silly when used with the normal semicolon, SetInverse(a, 48); ends up creating a null statement in the code, which (to me) is far uglier than the do..while(0) loop.
unwind
I wondered if stringization could be useful, but I've never used it in anger and I couldn't see how it could be used here. The docs say that ## prevents identifier replacement - does it really work in the middle of a contigious string?
Blank Xavier
Alas, `do{}while(0)` is necessary: this fails if written as `if (1) SetInverse(t, 0); else {printf("unmatched 'else'!\n");}`
ephemient
+4  A: 

Why are you storing the inverse when it can be so easily calculated? This seems like a bad idea to me.

anon
This is a security mesure. Every important variable has to be stored normal and inverse. Every second the variables get checked. If they are wrong hell breaks lose.
nuriaion
Might make sense in a environment with strong nuclear radiation. But I'm QUITE scared that a developer for embedded SW in such an environment has to ask that kind of question here.
MSalters
There are beginners also in embedded SW development.
mouviciel
It is a system which will work in a car
nuriaion
Michael Burr
@Michael - Thanks for the tip. Hadn't tough about that...
nuriaion
+5  A: 

One hazard I haven't seen mentioned is that the 'value' macro argument is evaluated twice in most of the solutions. That can cause problems if someone tries something like this:

int x = 10;
SET(myVariable, x++);

After this call, myVariable would be 10 and myVariable_inverse would be ~11. Oops. A minor change to JaredPar's solution solves this:

#define SET(var,value) do { var = (value); var##_inverse = ~(var); } while(0)
Fred Larson
+4  A: 

You can do it in a single statement, which avoids having to use do {} while (0).

#define SetInverse(token, value) (token##_inverse = ~(token = (value)))

Also, this only evalutes (value) once, which is always nice.

ephemient
>> Also, this only evalutes (value) once, which is always nice << - definitely a worthwhile reason to use this method.
Michael Burr
A slight modification makes this macro return the value of (value), just like if it were an assignment (just on the off chance it gets used in a larger expression itself, which is valid if probably unusual): #define SetInverse(token, value) (token = ~(token##_inverse = ~(value)))
Michael Burr
I was tempted to add a `(void)` cast to the define just to make sure it can't be used in a larger expression, but yeah, making it evaluate to `value` is pretty easy.
ephemient
A: 

Just to offer an alternative method:

Store each variable as a structure like this:

typedef struct
{
    u32 u32Normal;
    u32 u32Inverted;
} SafeU32TYPE

Then have a function which takes a pointer to one of these, along with the value to be set, and stores that value with its inverse:

void Set(SafeU32TYPE *pSafeU32, u32Data)
{
    if(pSafeU32 != NULL)
    {
        pSafeU32->u32Normal = u32Data;
        pSageU32->u32Inverted = ~u32Data;
    } /* if */
} /* Set() */

Advantage: if you need the set function to do something more powerful, such as boundary checking, or storing in some more complex way, then it can be easily extended.

Disadvantage: you'll need a different function for each type used, and if processor resource is an issue, this is less efficient than using a macro.

Steve Melnikoff