views:

973

answers:

6

I want to make a simple macro with #define for returning the smaller of two numbers.

How can i do this in C ? Suggest some ideas, and see if you can make it more obfuscated too.

+6  A: 

Typically:

#define min(a, b) (((a) < (b)) ? (a) : (b))

Be warned this evaluates the minimum twice, which was the reason for disaster in a recent question.

But why would you want to obfuscate it?


This one stores the result in a variable, and only evaluates each argument once. It's basically a poor-mans inline function + declaration:

#define min(t, x, a, b) \
            t x; \
            { \
                t _this_is_a_unique_name_dont_use_it_plz_0_ = a; \
                t _this_is_a_unique_name_dont_use_it_plz_1_ = b; \
                x = _this_is_a_unique_name_dont_use_it_plz_0_ < \  
                    _this_is_a_unique_name_dont_use_it_plz_1_ ? \
                    _this_is_a_unique_name_dont_use_it_plz_0_ : \  
                    _this_is_a_unique_name_dont_use_it_plz_1_ ; \
            }

Use it like:

min(int, x, 3, 4)
/* x is an int, equal to 3
  Just like doing:

  int x = min(3, 4);

  Without double evaluation.
*/
GMan
It should be a little obfuscated - it's intended for another person who thinks he's programming-mastermind, that's why. Anyway, tnx.
VaioIsBorn
A mastermind in which language? If we go to C++, I'm sure I can try to give him something to fry his expert noodle. But okay, what kind of assumptions can we make? Are these integers we're finding the minimum of? Then again, perhaps that's just a back-story to trick me into answering. :)
GMan
"I can give him something to fry his expert noodle" - glad to hear this, waiting further answers xD . BTW, the question was because in class we needed a simple minimum function, so i decided to go with macro so it'll look more c-ish.
VaioIsBorn
I'd add another pair of parenthesis for even more safety:#define min(a, b) ( ((a) < (b)) ? (a) : (b))You could make a code block, evaluate the values to some variables and return the variables, so you just evaluate once. Bad code, anyway.
Spidey
@Spidey: Agreed, added those parenthesis. I'll add your idea as well since this answer feels so empty.
GMan
Macro arguments should pretty much always be parenthesized in the macro. `min(int, x, 2; int c = 3, 4);` compiles as it's currently defined. OK, so what on earth is in the user's mind writing that? (Answer: the `=` sign in an object definition "binds" weaker than any operator, so it's the best example I could think of). But parenthesize `a`, and it doesn't parse, which is better. `t` is a notable exception - you can't parenthesize the type in an object definition since that turns it into a cast of an undefined object.
Steve Jessop
It worth to mention that GCC has `typeof` extension (http://gcc.gnu.org/onlinedocs/gcc/Typeof.html) that allows you avoid mentioning type name as macro param.
qrdl
Woe if `a` or `b` happen to be named `r0` or `r1` though.
jamesdlin
@jamesdlin: Yeah. There, that should do it. :P
GMan
@GMan - More useful (and (re)usable) would be to `#define _JOIN(x, y) x##y` / `#define JOIN(x, y) _JOIN(x, y)` / `#define UNIQ(x) JOIN(x, __LINE__)` and then use `UNIQ(x_)` and `UNIQ(y_)` to get uniquely named `x` and `y` variables.
Chris Lutz
+2  A: 

Sure, you can use a #define for this, but why would you want to? The problem with using #define, even with parentheses, is that you get unexpected results with code like this (okay, you wouldn't actually do this, but it illustrates the problem).

int result = min(a++, b++);

If you're using C++ not C, surely better to use an inline function, which (i) avoids evaluating the parameters more than once, and (ii) is type safe (you can even provide versions taking other types of value, like unsigned, double or string).

inline int min(int a, int b) { return (a < b) ? a : b; }
Huw Walters
In C++, it should be a template function, for *any* type. And of course no need to rewrite it; there's already one in `<algorithm>`.
GMan
You can write an inline function in C99, too, or with compiler extensions (`__inline` in MSVC, `__inline__` in GNU C89).
Steve Jessop
+2  A: 

For slightly obfuscated, try this:

#define MIN(a,b)  ((((a)-(b))&0x80000000) >> 31)? (a) : (b)

Basically, it subtracts them, and looks at the sign-bit as a 1-or-0. If the subtraction results in a negative number, the first parameter is smaller.

abelenky
Assuming the type is 32-bits.
GMan
Thank you - this was what i was looking for.
VaioIsBorn
Sadly, this doesn't actually work even for 32 bit integers, unless you believe that 2147483647 is smaller than -1.
Stephen Canon
@Stephen: What do you mean? In 2's compliment, it is smaller. (-1 has maximum value unsigned)
GMan
@GMan: -1 is unquestionably smaller than 2147483647, both as integers, and when compared in any signed type wide enough to represent both of them (32 bit twos complement integers, for example). Unsigned comparisons have nothing to do with the issue.
Stephen Canon
+1  A: 

And, just for the hell of it, a GNU C example:

#define MAX(a,b) ({ \
    typeof(a) _a_temp_; \
    typeof(b) _b_temp_; \
    _a_temp_ = (a); \
    _b_temp_ = (b); \
    _a_temp_ = _a_temp_ < _b_temp_ ? _b_temp_ : _a_temp_; \
    })

It's not obfuscated, but I think this works for any type, in any context, on any arguments, etc; please correct if you can think of any counterexamples.

David X
It's unlikely to happen, but this will be broken if `a` or `b` happen to themselves be variables named `_a_temp_` and `_b_temp_`.
jamesdlin
Yeah, I thought on glueing on `__LINE__`, but it didnt seem worth the effort; if only there was a `__UNIQUE__` macro...
David X
+2  A: 

I think this method is rather cute:

#define min(a, b) (((a) + (b) - fabs((a) - (b))) * 0.5)

doynax
A: 

If I were just trying to lightly obfuscate this I would probably go with something like:

#define min(a,b) ((a) + ((b) < (a) ? (b) - (a) : 0))

I think Doynax's solution is pretty cute, too. Usual reservations for both about macro arguments being evaluated more than once.

Stephen Canon