I'm trying to make a macro with the following formula: (a^2/(a+b))*b
, and I want to make sure that the there will be no dividing by zero.
#define SUM_A( x, y ) if( x == 0 || y == 0) { 0 } else { ( ( ( x * x ) / ( ( x ) + ( y ) ) ) * ( y ) )}
and then I call the macro inside main:
float a = 40, b = 10, result;
result = SUM_A(a, b);
printf("%f", result);
I've tried using brackets around the if function but I keep getting syntax errors before the if statement. I've also tried using return, but I read somewhere that you're not supposed to use that in define.
You can not use if statement, because #define
is interpret by the preprocessor, and the output would be
result=if( x == 0 || y == 0) { 0 } else { ( ( ( x * x ) / ( ( x ) + ( y ) ) ) * ( y ) )}
which is wrong syntax.
But an alternative is to use ternary operator. Change your define to
#define SUM_A( x, y ) ((x) == 0 || (y) == 0 ? 0 : ( ( ( (x) * (x) ) / ( ( x ) + ( y ) ) ) * ( y ) ))
Remember to always put your define between parentheses, to avoid syntax error when replacing.
As far as I know, what you're trying to do (use if
statement and then return a value from a macro) isn't possible in ISO C... but it is somewhat possible with statement expressions (GNU extension).
Since #define
s are essentially just fancy text find-and-replace, you have to be really careful about how they're expanded. I've found that this works on gcc
and clang
by default:
#define SUM_A(x, y) \
({ \
float answer; \
if ((x) == 0 || (y) == 0) { \
answer = 0; \
} else { \
answer = ((float)((x)*(x)) / ((x)+(y))) * (y); \
} \
answer; \
})
// Typecasting to float necessary, since int/int == int in C
Brief explanation of the things in this macro:
\
at the end of each line is to signal line continuation (ie to tell the compiler "this macro continues on the next line")({
is a statement expression (GNU extension; not part of standard C). x
was 2+1
, then (x)*(x)
would expand to (2+1)*(2+1)
, which is 9 (what we wanted), but x*x
would expand to 2+1*2+1
, which is 5 (not what we wanted)return
value (hence the answer;
at the end) This should give you the result you're looking for, and there's no reason it can't be extended to include multiple else if
s as well (though as other answers have pointed out, it's probably better to use the ternary operator if you can).
if
introduces a statement, not an expression. Use the "ternary" (conditional) operator:
#define SUM_A(x, y) (((x) == 0 || (y) == 0)? 0: ((((x) * (x)) / ((x) + (y))) * (y)))
Alternatively, make this an inline
function:
inline float sum_a(float x, float y)
{
if (x == 0 || y == 0)
return 0;
else
return ((x * x) / (x + y)) * y;
}
This avoids the problem of multiple evaluation of x
and/or y
and is much more readable, but it does fix the types of x
and y
. You can also drop the inline
and let the compiler decide whether inlining this function is worthwhile ( inline
is not a guarantee that it will perform inlining).
There are multiple problems with your macro:
it expands to a statement, so you cannot use it as an expression
the arguments are not properly parenthesized in the expansion: invoking this macro with anything but variable names or constants will produce problems.
the arguments are evaluated multiple times: if you invoke the macro with arguments that have side effects, such as SUM_A(a(), b())
or SUM_A(*p++, 2)
, the side effect will occur multiple times.
To avoid all these problems, use a function, possibly defined as static inline
to help the compiler optimize more (this is optional and modern compilers do this automatically):
static inline int SUM_A(float x, float y) {
if (x == 0 || y == 0)
return 0;
else
return x * x / (x + y) * y;
}
Notes:
The problem is that an if
statement is not an expression, and doesn't return a value. Besides, there is no good reason to use a macro in this case. In fact, it could cause very serious performance problems (depending on what you pass as macro arguments). You should use a function instead.
YES you can have an if statement in a macro. You need to format it correctly. Here is an example:
#define MY_FUNCTION( x ) if( x ) { PRINT("TRUE"); } else { PRINT("FALSE"); }
I use macros with conditions quite a bit and they do have a legit use.
I have a few structures that are essentially blobs and everything is just a uint8_t stream.
To make internal structures more readable I have conditional macros.
Example...
#define MAX_NODES 10
#define _CVAL16(x)(((x) <= 127) ? (x) : ((((x) & 127) | 0x80) ), ((x) >> 7)) // 1 or 2 bytes emitted <= 127 = 1 otherwise 2
Now to use the macro inside an array...
uint8_t arr_cvals[] = { _CVAL16(MAX_NODES), _CVAL16(345) };
Three bytes are emitted in the array, 1st macro emits 1 and the second 2 bytes. This is evaluated at compile time and just makes the code more readable.
I also have... for example...
#define _VAL16(x) ((x) & 255), (((x) >> 8) & 255)
For the original problem... maybe the person wants to use the results with constants, but once again really comes down to where and how it's to be used.
#define SUM_A(x, y) (!(x) || !(y)) ? 0 : ((x) * (x) / ((x) + (y)) * (y))
float arr_f[] = { SUM_A(0.5f, 0.55f), SUM_A(0.0f, -1.0f), SUM_A(1.0f, 0.0f) };
At runtime can have...
float x;
float y;
float res = SUM_A(x,y); // note ; on the end
I have a program that creates fonts that are included as code inside C programs and most values are wrapped around macros that split 32 bit values into 4 bytes, float into 4 bytes, etc.
You can convert the conditional statement into a simple expression. Conditions evaluate to 0
or 1
// pseudo-code
// if (<something>) { 0; } else { 42; }
// if (!<something>) { 42; } else { 0; }
// !<something> * 42;
In your specific case
// if ((x == 0) || (y == 0)) { 0; } else { (x)(y)expression; }
// if ((x != 0) && (y != 0)) { (x)(y)expression; }
// ((x != 0) && (y != 0)) * ( (x)(y)expression );
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.