Bad parentheses in macro definition - c

I was reading this tutorial of stanford where they say :
Common coding mistakes:
Bad parentheses in macro definition
#define min(a, b) a<b?a:b // incorrect
#define min(a, b) (((a)<(b))?(a):(b)) // correct
I even ran this in a program, It worked fine.
Can anybody explain what they are trying to say!

The first version fails if you combine it with other operators:
min(a , b) + c
and translates to:
a<b?a:b+c
which is identical to:
a<b?a:(b+c)
which is an unexpected outcome given the starting parenthesis.
The second version isn't much better. It evaluates one of the parameters twice which can cause unexpected behavior if a function or i++ is passed to the macro.
An inline function should be used instead of those macros.

Related

Defining a function as macro

I am trying to understand defining functions as macros and I have the following code, which I am not sure I understand:
#define MAX(i, limit) do \
{ \
if (i < limit) \
{ \
i++; \
} \
} while(1)
void main(void)
{
MAX(0, 3);
}
As I understand it tries to define MAX as an interval between 2 numbers? But what's the point of the infinite loop?
I have tried to store the value of MAX in a variable inside the main function, but it gives me an error saying expected an expression
I am currently in a software developing internship, and trying to learn embedded C since it's a new field for me. This was an exercise asking me what the following code will do. I was confused since I had never seen a function written like this
You are confused because this is a trick question. The posted code makes no sense whatsoever. The MAX macro expands indeed to an infinite loop and since its first argument is a literal value, i++ expands to 0++ which is a syntax error.
The lesson to be learned is: macros are confusing, error prone and should not be used to replace functions.
You have to understand that before your code gets to compiler, first it goes through a preprocessor. And it basically changes your text-written code. The way it changes the code is controlled with preprocessor directives (lines that begin with #, e.g. #include, #define, ...).
In your case, you use a #define directive, and everywhere a preprocessor finds a MAX(i, limit) will be replaced with its definition.
And the output of a preprocessor is also a textual file, but a bit modified. In your case, a preprocessor will replace MAX(0, 3) with
do
{
if (0 < 3)
{
0++;
}
} while(1)
And now the preprocessor output goes to a compiler like that.
So writing a function in a #define is not the same as writing a normal function void max(int i, int limit) { ... }.
Suppose you had a large number of statements of the form
if(a < 10) a++;
if(b < 100) b++;
if(c < 1000) c++;
In a comment, #the busybee refers to this pattern as a "saturating incrementer".
When you see a repeated pattern in code, there's a natural inclination to want to encapsulate the pattern somehow. Sometimes this is a good idea, or sometimes it's fine to just leave the repetition, if the attempt to encapsulate it ends up making things worse.
One way to encapsulate this particular pattern — I'm not going to say whether I think it's a good way or not — would be to define a function-like macro:
#define INCR_MAX(var, max) if(var < max) var++
Then you could say
INCR_MAX(a, 10);
INCR_MAX(b, 100);
INCR_MAX(c, 1000);
One reason to want to make this a function-like macro (as opposed to a true function) is that a macro can "modify its argument" — in this case, whatever variable name you hand to it as var — in a way that a true function couldn't. (That is, if your saturating incrementer were a true function, you would have to call it either as incr_max(&a, 10) or a = incr_max(a, 10), depending on how you chose to set it up.)
However, there's an issue with function-like macros and the semicolon at the end. I'm not going to explain that whole issue here; there's a big long previous SO question about it.
Applying the lesson of that other question, an "improved" INCR_MAX macro would be
#define INCR_MAX(var, max) do { if(var < max) var++; } while(0)
Finally, it appears that somewhere between your exercise and this SO question, the while(0) at the end somehow got changed to while(1). This just about has to have been an unintentional error, since while(1) makes no sense in this context whatsoever.
Yeah, there's a reason you don't understand it - it's garbage.
After preprocessing, the code is
void main(void)
{
do
{
if ( 0 < 3 )
{
0++;
}
} while(1);
}
Yeah, no clue what this thing is supposed to do. The name MAX implies that it should evaluate to the larger of its two arguments, a la
#define MAX(a,b) ((a) < (b) ? (b) : (a))
but that's obviously not what it's doing. It's not defining an interval between two numbers, it's attempting to set the value of the first argument to the second, but in a way that doesn't make a lick of sense.
There are three problems (technically, four):
the compiler will yak on 0++ - a constant cannot be the operand of the ++ or -- operators;
If either i or limit are expressions, such as MAX(i+1, i+5) you're going to have the same problem with the ++ operator and you're going to have precedence issues;
assuming you fix those problems, you still have an infinite loop;
The (technical) fourth problem is ... using a macro as a function. I know, this is embedded world, and embedded world wants to minimize function call overhead. That's what the inline function specifier is supposed to buy you so you don't have to go through this heartburn.
But, okay, maybe the compiler available for the system you're working on doesn't support inline so you have to go through this exercise.
But you're going to have to go to the person who gave you this code and politely and respectfully ask, "what is this crap?"

C Stringize result of equation

I have read lots on stringizing macros, but I obviously don't quite understand. I wish to make a string where the argument to the macro needs to be evaluated first. Can someone please explain where I am going wrong, or perhaps how to do this better?
#define SDDISK 2 // Note defined in a library file elsewhere ie not a constant I know)
#define DRIVE_STR(d) #d ":/"
#define xDRIVE_STR(x) DRIVE_STR(x)
#define FILEPATH(f) xDRIVE_STR(SDDISK + '0') #f
const char file[] = FILEPATH(test.log);
void main(void)
{
DebugPrint(file);
}
The output is: "2 + '0':/test.log",
But I want "2:/test.log"
The C PREprocessor runs before the compiler ever sees the code.
This means that the equation will not be evaluated before it is stringified; instead, the preprocessor will just stringize the whole equation.
In your case just removing the +'0' will solve the problem as the value of SDDISK does not need casting to a char before it is stringified.
However, should you actually need to perform a calculation before stringizing you should either:
Use cpp's constexpr.
Complain to your compiler vendor that a constant expression was not optimized.
Use a preprocessor library to gain the wanted behaviour.

How to force processor to use result of expression before pasting

My code is
#define PASTE__(a, b) a##b
#define PASTE_(a, b) PASTE__(a, b)
#define PASTE(a, b) PASTE_(a, b)
int main()
{
PASTE(1, (1+3)/4);
return 0;
}
I would LIKE to have the result be
int main()
{
11;
return 0;
}
Compilable link: http://coliru.stacked-crooked.com/a/b35ea3e35a1b56ae
I put in two levels of indirection suggested by How can I guarantee full macro expansion of a parameter before paste?.
But still I get a preprocessor error:
main.c:8:11: error: pasting "1" and "(" does not give a valid preprocessing token
PASTE(1, (1+3)/4);
^
main.c:1:23: note: in definition of macro 'PASTE__'
#define PASTE__(a, b) a##b
^
main.c:3:21: note: in expansion of macro 'PASTE_'
#define PASTE(a, b) PASTE_(a, b)
^
main.c:8:5: note: in expansion of macro 'PASTE'
PASTE(1, (1+3)/4);
How do I get the preprocessor to resolve the result of that expression before doing concatenation?
It looks like you're trying to get the preprocessor to evaluate some simple mathematical operations and convert to the result. This is not possible without substantial extra macro infrastructure to perform the necessary math. The easiest way to get the needed infrastructure is probably to use BOOST_PP.
http://www.boost.org/doc/libs/1_59_0/libs/preprocessor/doc/index.html
You would need to modify your code so that macros are used to perform the math rather than operators. The line in question would look like:
PASTE(1, BOOST_PP_DIV(BOOST_PP_ADD(1,3),4));
Now the answer would come out as 11, and I assume that's what you're looking for.
What exactly are you hoping the preprocessor output for the PASTE line will be? 11;? That's impossible. (update: apparently it is possible with clever enough macros. See Charles Ofria's answer).
That double-expansion with multiple macros is only useful for expanding macros and then stringifying the results, IIRC.

#define directive in C Giving ambiguous answer [duplicate]

This question already has answers here:
C : #define usage [duplicate]
(3 answers)
Closed 7 years ago.
#include <stdio.h>
#define SQR(x) x*x
int main()
{
printf("%d",225/SQR(15));
return 0;
}
The output to this code is 225. I'm unable to understand as what really is happening here.
If I use #define SQR(x) (x*x) Then it works fine which i get as we are supposed to use parentheses if we have an expression with some operator.
But in the previous case I'm not clear as to what is really happening. Why is the answer 225?
#define macros aren't functions - they are just macros, text replacement. If you take the expression 225/SQR(15) and replace SQR with 15*15, you'll get 225/15*15, and since / and * have the save precedence and are left associative - 255/15*15 = 255.
Macros do substitution only(done before compilation of the code).
Therefore the following line
printf("%d",225/SQR(15));
after substitution will become:
printf("%d",225/15*15);
now this expression evaluates to 225 (basic maths : divide first -> 15*15, then multiply -> 225)
using brackets solves your problem(then it becomes 225/(15*15)).
:)
Notice the steps
1) 225/SQR(15)
2) 225/15*15
Division executed first due to precedence
3) 15*15
4) 225
See #define as a text replacement tool in a text editor; it works the same way (well, almost).
Here are two rules you might want to follow in order to avoid this kind of errors:
When working with macros, always use parentheses for each "variable" given to the macro and for the whole result.
Example:
#define MAX(a, b) ((a) > (b) ? (a) : (b))
When you have an unexpected behavior, use the command line tool cpp (c preprocessor) to see how the macro is actually interpreted.
Example:
$ cpp main.c

How to fix `left hand operand has no effect` warning with variadic macro in C

I'm using the variadic macro to simulate a default argument. I compile with -Wunused-value. Thus, I get the following warning:
warning: left-hand operand of comma expression has no effect
Is there a way to somehow fix this warning without having to remove -Wunused-value? or do I have to end up using #pragma GCC diagnostic ignored "-Wunused-value"?
#include <stdio.h>
#define SUM(a,...) sum( a, (5, ##__VA_ARGS__) )
int sum (int a, int b)
{
return a + b;
}
int main()
{
printf("%d\n", SUM( 3, 7 ) );
printf("%d\n", SUM( 3 ) );
}
The ## construct that you are using is a gcc speciality and not portable. Don't use it, there are other ways.
The following should do what you expect
#define SUM2(A, B, ...) sum((A), (B))
#define SUM1(...) SUM2(__VA_ARGS__)
#define SUM(...) SUM1(__VA_ARGS__, 5, 0)
Such games with macro default arguments are frowned upon by many, because they may make the code more difficult to read.
For the moment I'd suggest that you don't use such constructs in your programs. You should perhaps learn more of the basics before you go into such esoteric stuff.
Also your idea to want to silence the compiler is really a bad one. The compiler is there to help you, listen to him. In the contrary, raise the warning level to a maximum and improve your code until it compiles without any warning.
Jens Gustedt proposed a very good problem-specific portable solution. I didn't know, ,##__VA_ARGS__ is a GCC extension (maybe Clang too?). There are however GCC-specific solutions for the authors initial intension.
As a problem-specific and very GCC-specific solution, you can use _Pragma("GCC diagnostic ignored \"-Wunused-value\"") and delimit it around the macro expansion. This will keep the comfort of readability. This does not work everywhere. It mainly fails within static initializer lists placed outside of functions where those pragmas can't be applied. I really was looking for a solution within such initializer lists because I couldn't find any which hides the warning pragmas from the reader. Other than that, for a function call like sum() for example - which I suppose to be only valid in a function body itself -, you can use it:
#define SUM(a,...) ({\
_Pragma("GCC diagnostic push")\
_Pragma("GCC diagnostic ignored \"-Wunused-value\"")\
sum( a, (5, ##__VA_ARGS__) );\
_Pragma("GCC diagnostic pop")\
})
Remember, you can only use it in function bodies and where an expression is expected. The warning will remain turned on after the macro expansion.
But I found a general solution! Conditional-macro-expansion is possible with the ,##__VA_ARGS__ feature. It gives you the power of conditional expansion based on blankness of the argument.
This feature does not necessarily add substitution power to the preprocessor. If you use arguments which include commas like (<...>) for false or 0 and (<...>,<...>) for true or 1, you can achieve the same. But only the conditional comma allows you the comfort of expanding conditionally based on the blankness of an argument.
See: you might be able to write your code like SUM(A) expanding to sum((A),5) without ##__VA_ARGS__ but you might not be able to write SUM(,B) expanding to sum((somevalue),B) . But you can do that with ##__VA_ARGS__ .
Example:
#define _VADIC(...) , ##__VA_ARGS__
//expands to A if A is not blank else to __VA_ARGS__ as fallback value
#define TRY(A,B) _TRY0(_VADIC(A), B)
#define _TRY0(...) _TRY1(__VA_ARGS__) /*expand before call*/
#define _TRY1(A, B, ...) B
//expands to THEN if A is blank otherwise expands to blank
#define IF(A,THEN) _IF0(_VADIC(A),THEN)
#define _IF0(...) _IF1(__VA_ARGS__) /*expand before call*/
#define _IF1(A,B,...) __VA_ARGS__
//expands to ELSE if A is not blank otherwise expands to blank
#define IFNOT(A,ELSE) _IFNOT0(_VADIC(A),,ELSE)
#define _IFNOT0(...) _IFNOT1(__VA_ARGS__) /*expand before call*/
#define _IFNOT1(A,B,C,...) C
#define IF_ELSE(A, THEN, ELSE) IF(A,THEN)IFNOT(A,ELSE)
Without the conditional comma, you only can expand conditionally on the number of arguments or on predefined concatenations but this way, you can use ANY single undefined symbol as condition.
PS: What about loops? Macros in C are designed to be finite for faster compilation. You won't get infinite loops since the limit of loop cycles depends on the source code size. Limited loops is the only thing which hinders you from turing-completeness, but practical real-world computer science problems (different from embedded or operating systems) don't need infinite loops for calculations. They are all limited depending with the problem size. The turing machine also uses a finite alphabet of symbols. You could know the limit of loop cycles which are needed in the worst case and it is possible to create a functional loop (a "reduce" or "filter" macro) running on variable-length macro argument lists which can reformat the macro argument list and do magic. The only requirement is the comma. You can't iterate over elements without a comma in between.

Resources