Hoping to get some clarification/explaination on the following piece of code
#define NOOP(x) ((void)(x))
void my_function(int x)
As far as what happens, it's absolutely nothing, and that's the point. Just a reference to the variable, but do absolutely nothing with it. The compiler dutifully processes it, notes that the parameter was used, then throws everything away and does not generate any actual code.
As far as parenthesis go:
It is a good practice to use parenthesis for macros that can potentially be used in an expression, even when it is not needed.
Consider, for example, a simple macro in hypothetical code that draws a window on the screen. The library that does it adds a border around the window that, say, is 6 pixels long. This macro computes the total width of the window. A naive implementation of this macro would read:
#define ACTUAL_WIDTH(w) w+6
Now, let's say your code wants to compute the actual width of two windows. Both windows are 100 pixels wide:
What do you think happens? Recall that a macro substitution is basically just a straightforward text substitution, so this is what actually gets compiled:
Which is utterly wrong. You want to have an extra set of parenthesis in your macro, so that the correct code gets compiled:
And that's why you will often see an extra set of parenthesis in macros that can be used in expressions. Not only that, a macro like that will also have parenthesis around its argument, so it will probably be:
#define ACTUAL_WIDTH(w) ((w)+6)
And that's why you see an extra set of parenthesis in macros. It's easier to acquire a habit of always sticking them into every macro you write and be safe; rather than waste time figuring out, every time, if they are really needed or not.
Using good programming habits will avoid many common bugs.