Kabu
Kabu

Reputation: 569

Sign computation with a macro

What the following expression computes, exactly?

#define SIGN(x) ((x < 0) ? -1 : (x > 0))

what yields if x is zero, less than zero, more than zero? I guess I know the answer, but I'd like to check for clarity...

Thank you

EDIT: added missing parenthesis EDIT: more info here

Upvotes: 0

Views: 825

Answers (4)

Jean-Baptiste Yun&#232;s
Jean-Baptiste Yun&#232;s

Reputation: 36401

If you use it with values only and not expressions that macro will produce -1, 0, 1, otherwise you may have serious problems. The tricky part is (x>0). Lets read the standard:

5.9 Relational operators [expr.rel]

The operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) all yield false or true. The type of the result is bool.

and

3.9.1 Fundamental types [basic.fundamental]

Values of type bool are either true or false. Values of type bool participate in integral promotions (4.5).

Thus x>0 is either true or false.

4.5 Integral promotions [conv.prom]

A prvalue of type bool can be converted to a prvalue of type int, with false becoming zero and true becoming one.

and is promoted to either 1 or 0 (respectively).

Upvotes: 0

CiaPan
CiaPan

Reputation: 9570

First, the macro doesn't compute anything. It is substituted into a source code, expanded, and the resulting text gets compiled. What the resulting text is, depends on the way you use the macro, especially on what parameter you give.

Second, the macro lacks one closing paren, so it probably would not give you a meaningful expression to be compiled.

Third, even when you add the lacking paren:

#define SIGN(x) ((x < 0) ? -1 : (x > 0))

it is possible you get unexpected results if you use the macro in a non-simplest way. For example,

SIGN(a ^ b)

would result in

((a ^ b < 0) ? -1 : (a ^ b > 0))

which is interpreted in C and C++ as

((a ^ (b < 0)) ? -1 : (a ^ (b > 0)))

which certainly is not what we intend.

You should add parentheses to avoid unwanted operators binding – for:

#define SIGN(x) (((x) < 0) ? -1 : ((x) > 0))

the above example will yield a sensible expression

(((a ^ b) < 0) ? -1 : ((a ^ b) > 0))

but that still doesn't protect you against unwanted double increment/decrement in case of plus-plus or minus-minus operators or double execution of a function in case the expression substituted for x contains a function call.

Upvotes: 2

Swift - Friday Pie
Swift - Friday Pie

Reputation: 14614

That macro got a stray parenthesis. It looks like it is meant to be an implementation of signum function, which returns -1, 1 or 0 depending on value of argument.

For sake of being safe and writing C++ code, it is prudent to replace macro by template, similar to

template <class T>
int SIGN( T x )
{
 return (x < T(0)) ? -1 : (x > T(0));
}

First comparision is argument of trenary operator ?:. Ternary would return -1 if expression evaluates to true , i.e. x is less than 0, otherwise it would return result of x > T(0). That expression would evaluated to 0 if x equals to 0, otherwise it would be evaluated to 1.

Note that my implementation is not ideal, you can find better implementation elsewhere on SO. An alternative expression can be:

return (T(0)<x) - (T(0)>x);

Which may be more effective with platforms that implement certain CPU instructions

Upvotes: 1

paxdiablo
paxdiablo

Reputation: 881663

It does exactly what you probably think it does, gives -1 for negative numbers, 0 for zero, and 1 for positive numbers.

However, you should generally avoid function-like macros since they will not do what you expect if, for example, you try to calculate SIGN(value++). Since they're simple text substitutions, that would resolve to:

((value++ < 0) ? -1 : (value++ > 0)

You're far better off just using real functions and letting the compiler inline them if it decides it's worth it. You can also suggest to the compiler that inlining it, with the inline keyword, but keep in mind it is a suggestion.

Upvotes: 2

Related Questions