2

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

Evan Teran
  • 87,561
  • 32
  • 179
  • 238
nuriaion
  • 2,621
  • 2
  • 23
  • 18
  • If you want to indicate that is the best solution, you should select that one as the "accepted" solution; that gives a reputation bonus to the user who contributed it, and marks it as the solution that solved your problem. – Brian Campbell Apr 02 '09 at 15:58
  • Should the macro also take the chance to ensure that var = ~var_inverse immediately before doing the assignment? do { assert(var == ~var##_inverse); var = (value); var##_inverse = ~(value); } while (0). If you use this macro everywhere, it is your best chance to check. – Jonathan Leffler Apr 02 '09 at 16:05

6 Answers6

11

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

Community
  • 1
  • 1
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • Is there an article somewhere explaining why you use a macro construction out of a do loop? I'm curious why... – Tom Ritter Apr 02 '09 at 13:34
  • 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 Apr 02 '09 at 13:39
  • 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 Apr 02 '09 at 13:40
  • @Tom, I added a few links that go into detail about why this is good practice for multi-statement macros. – JaredPar Apr 02 '09 at 13:40
  • @dmckee, missed that one (added). – JaredPar Apr 02 '09 at 13:41
  • 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 Apr 02 '09 at 15:34
  • 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 Apr 02 '09 at 23:26
5

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
  • 60,987
  • 18
  • 112
  • 174
4

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

  • 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 Apr 02 '09 at 13:35
  • 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 Apr 02 '09 at 13:41
  • There are beginners also in embedded SW development. – mouviciel Apr 02 '09 at 13:43
  • @nuriaion - in this case you need to make the updates & checks atomic (using a mutex or something) so all hell doesn't break loose if the check happens to occur between setting the value and setting the 'mirror' of the value. – Michael Burr Apr 02 '09 at 21:27
4

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
  • 198,619
  • 38
  • 280
  • 391
  • >> Also, this only evalutes (value) once, which is always nice << - definitely a worthwhile reason to use this method. – Michael Burr Apr 02 '09 at 21:25
  • 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 Apr 02 '09 at 21:34
  • 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 Apr 02 '09 at 22:59
1
#define SetInverse(token, value) { token = value; token##_inverse = ~value; }

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

plinth
  • 48,267
  • 11
  • 78
  • 120
  • 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 Apr 02 '09 at 13:43
  • 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? –  Apr 02 '09 at 13:58
  • Alas, `do{}while(0)` is necessary: this fails if written as `if (1) SetInverse(t, 0); else {printf("unmatched 'else'!\n");}` – ephemient Apr 02 '09 at 19:38
0

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
  • 2,620
  • 1
  • 22
  • 24