Calling function with macro in C - c

I have function in C with 3 params. I want to call that function with pre-defined values. Is there any solution?
My idea which does not work.
#define PRE_DEFINED_MACRO (10, 15 , true)
void myFunc(uint8_t temp, uint32_t value, bool valid)
{
....
}
....
//call the function like that
myFunc(PRE_DEFINED_MACRO);

Your macro already includes parentheses, so when this ...
myFunc(PRE_DEFINED_MACRO);
... is expanded, the result is:
myFunc((10, 15 , true));
You could do this instead:
myFunc PRE_DEFINED_MACRO;
I find that pretty confusing, however. Personally, I would prefer to remove the parentheses from the macro's replacement text:
#define MYFUNC_ARGS 10, 15 , true
// ...
myFunc(MYFUNC_ARGS);
That makes it much clearer that the call to myFunc() is, in fact, a function call. The choice of macro name also makes the intended purpose of the macro much clearer.

To just replace 3 arguments with a macro:
#define PRE_DEFINED_MACRO 10, 15, true
The reason why you can't use a parenthesis is because it would expand as myFunc((10, 15, true)); and the compiler reads that as "the first parameter is obtained from a chained series of comma operators and the rest of the parameters are missing". What does the comma operator , do?
As for always giving a certain function the same default arguments and optionally omit some arguments (like in C++), it's a bit more intricate. See C default arguments, including this late answer that I posted there recently myself.

Another, not uncommon solution would be to use a function-like macro right away, e.g.
#define MY_FUNC_DEFAULTS() myFunc(10, 15, true)
This looks also fairly clean, retains the function syntax etc. Note that the macro expansion does not end with a semicolon so that it can (and must) be provided at the call site in the natural fashion: if(cond) MY_FUNC_DEFAULTS(); else g(); works as expected.
Because you originally asked about C++: I find some of the OCD types here a bit annoying. All preprocessor solutions provided in the answers here work equally well in both languages. Nonetheless, the preprocessor is text replacement and as such inherently unsafe. Therefore, C++ provides means to avoid using it. In this case one could provide default arguments in the function declaration:
void myFunc(uint8_t temp = 10, uint32_t value = 15, bool valid = true);
This essentially overloads the function: It defines a set of four distinct functions that take 3, 2, 1 or 0 arguments, respectively. All of the calls
myFunc();
myFunc(1);
myFunc(1,2);
myFunc(1,2,false);
are now possible.
Such declarations could be present in different translation units with different default values. The default values are defined at the caller side and are not part of the function signature. (Whether that would be recommended is debatable though.)

Related

Why are statements with no effect considered legal in C?

Pardon if this question is naive. Consider the following program:
#include <stdio.h>
int main() {
int i = 1;
i = i + 2;
5;
i;
printf("i: %d\n", i);
}
In the above example, the statements 5; and i; seem totally superfluous, yet the code compiles without warnings or errors by default (however, gcc does throw a warning: statement with no effect [-Wunused-value] warning when ran with -Wall). They have no effect on the rest of the program, so why are they considered valid statements in the first place? Does the compiler simply ignore them? Are there any benefits to allowing such statements?
One benefit to allowing such statements is from code that's created by macros or other programs, rather than being written by humans.
As an example, imagine a function int do_stuff(void) that is supposed to return 0 on success or -1 on failure. It could be that support for "stuff" is optional, and so you could have a header file that does
#if STUFF_SUPPORTED
#define do_stuff() really_do_stuff()
#else
#define do_stuff() (-1)
#endif
Now imagine some code that wants to do stuff if possible, but may or may not really care whether it succeeds or fails:
void func1(void) {
if (do_stuff() == -1) {
printf("stuff did not work\n");
}
}
void func2(void) {
do_stuff(); // don't care if it works or not
more_stuff();
}
When STUFF_SUPPORTED is 0, the preprocessor will expand the call in func2 to a statement that just reads
(-1);
and so the compiler pass will see just the sort of "superfluous" statement that seems to bother you. Yet what else can one do? If you #define do_stuff() // nothing, then the code in func1 will break. (And you'll still have an empty statement in func2 that just reads ;, which is perhaps even more superfluous.) On the other hand, if you have to actually define a do_stuff() function that returns -1, you may incur the cost of a function call for no good reason.
Simple Statements in C are terminated by semicolon.
Simple Statements in C are expressions. An expression is a combination of variables, constants and operators. Every expression results in some value of a certain type that can be assigned to a variable.
Having said that some "smart compilers" might discard 5; and i; statements.
Statements with no effect are permitted because it would be more difficult to ban them than to permit them. This was more relevant when C was first designed and compilers were smaller and simpler.
An expression statement consists of an expression followed by a semicolon. Its behavior is to evaluate the expression and discard the result (if any). Normally the purpose is that the evaluation of the expression has side effects, but it's not always easy or even possible to determine whether a given expression has side effects.
For example, a function call is an expression, so a function call followed by a semicolon is a statement. Does this statement have any side effects?
some_function();
It's impossible to tell without seeing the implementation of some_function.
How about this?
obj;
Probably not -- but if obj is defined as volatile, then it does.
Permitting any expression to be made into an expression-statement by adding a semicolon makes the language definition simpler. Requiring the expression to have side effects would add complexity to the language definition and to the compiler. C is built on a consistent set of rules (function calls are expressions, assignments are expressions, an expression followed by a semicolon is a statement) and lets programmers do what they want without preventing them from doing things that may or may not make sense.
The statements you listed with no effect are examples of an expression statement, whose syntax is given in section 6.8.3p1 of the C standard as follows:
expression-statement:
expressionopt ;
All of section 6.5 is dedicated to the definition of an expression, but loosely speaking an expression consists of constants and identifiers linked with operators. Notably, an expression may or may not contain an assignment operator and it may or may not contain a function call.
So any expression followed by a semicolon qualifies as an expression statement. In fact, each of these lines from your code is an example of an expression statement:
i = i + 2;
5;
i;
printf("i: %d\n", i);
Some operators contain side effects such as the set of assignment operators and the pre/post increment/decrement operators, and the function call operator () may have a side effect depending on what the function in question does. There is no requirement however that one of the operators must have a side effect.
Here's another example:
atoi("1");
This is calling a function and discarding the result, just like the call printf in your example but the unlike printf the function call itself does not have a side effect.
Sometimes such a statements are very handy:
int foo(int x, int y, int z)
{
(void)y; //prevents warning
(void)z;
return x*x;
}
Or when reference manual tells us to just read the registers to archive something - for example to clear or set some flag (very common situation in the uC world)
#define SREG ((volatile uint32_t *)0x4000000)
#define DREG ((volatile uint32_t *)0x4004000)
void readSREG(void)
{
*SREG; //we read it here
*DREG; // and here
}
https://godbolt.org/z/6wjh_5

Parenthesis do in C/Embedded C #define statements

I saw the following in a .h-file for the cc2640 mcu:
#define ADC_STATUS_SUCCESS (0)
From my C knowledge, the compiler is told to put the value of ADC_STATUS_SUCCESS everywhere it occurs, that is (0). But what is the difference in putting just 0?
what is the difference in putting just 0?
None, if you don't write crazy code. It is common to use parentheses for macros that contain expressions to avoid unexpected errors related to operator precedence and similar stuff when using them. In this case though, defining something as 0 or as (0) is the same if it's used in expressions.
What do I mean by "crazy code"? Well, the only difference between the two can be seen in something like the following:
void func(int x) { /* ... */ };
#define ADC_STATUS_SUCCESS 0
func ADC_STATUS_SUCCESS; // INVALID
#define ADC_STATUS_SUCCESS (0)
func ADC_STATUS_SUCCESS; // VALID (for the love of God NEVER do this)
I highly doubt this is the case though, nobody in their right mind would write such an abomination. That define is most likely out of habit.

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.

Why one needs two brackets to use macros in C?

KdPrint(("Enter HelloWDMAddDevice\n"));
What's the reason for doing that?
That is so you can pass an entire argument list to the macro and have it pass it on to a function that takes a variable number of arguments.
I would bet anything that the definition of that macro is:
#if DEBUG /* or something like it */
#define KdPrint(args) (printf args)
#else
#define KdPrint(args) /* empty */
#endif
Or similar to some other function that works just like printf.
If it were defined as printf(args), then you could only pass the single string argument, because an argument to a macro can't contain a comma that isn't inside a nested parenthesis.
It causes everything inside the parens to be treated as a single parameter to the macro. In the example shown, it can allow for varargs types of parameters:
KdPrint(( "My info is %s\n", "my name" ));
As well as
KdPrint(( "fn %s ln %s\n", "my", "name" ));
If the macro in question was not well written using parentheses, it might be necessary because of operator precedence. Take this macro for example:
#define MY_MACRO(a) a * 11
Well, if you did this:
int b = MY_MACRO(1 + 2);
b, instead of being 33 like it should, would actually be replaced with int b = 1 + 2 * 11 which is 23 and not 33. If your macro isn't written like that, though (without parenthesis around the a) then it's unnecessary.
If this is the KdPrint() that you are talking about, then this is because you can use KdPrint() macro with format arguments, and it is not a variable length macro.
For example, you can do:
KdPrint(("The answer is %d\n", 42));
and so on.
For your specific example, I cannot tell you, because I don't know what is XdPrint.
But in a more general case, it is because a macro I just like a search and replace. Suppose you have:
#define MULT(a,b) (a*b)
If you call MULT(1+1, 2+2), it would become 1+1*2+2, and result as 5 instead of 8 as you would expect. Doing MULT((1+1), (2+2)) would gives you the expected result. That is why you need to double the brackets.

Compound literals and function-like macros: bug in gcc or the C standard?

In C99, we have compound literals, and they can be passed to functions as in:
f((int[2]){ 1, 2 });
However, if f is not a function but rather a function-like macro, gcc barfs on this due to the preprocessor parsing it not as one argument but as two arguments, "(int[2]){ 1" and "2 }".
Is this a bug in gcc or in the C standard? If it's the latter, that pretty much rules out all transparent use of function-like macros, which seems like a huge defect...
Edit: As an example, one would expect the following to be a conforming program fragment:
fgetc((FILE *[2]){ f1, f2 }[i]);
But since fgetc could be implemented as a macro (albeit being required to protect its argument and not evaluate it more than once), this code would actually be incorrect. That seems surprising to me.
This "bug" has existed in the standard since C89:
#include <stdio.h>
void function(int a) {
printf("%d\n", a);
}
#define macro(a) do { printf("%d\n", a); } while (0)
int main() {
function(1 ? 1, 2: 3); /* comma operator */
macro(1 ? 1, 2: 3); /* macro argument separator - invalid code */
return 0;
}
I haven't actually looked through the standard to check this parse, I've taken gcc's word for it, but informally the need for a matching : to each ? trumps both operator precedence and argument list syntax to make the first statement work. No such luck with the second.
This is per the C Standard, similar to how in C++, the following is a problem:
f(ClassTemplate<X, Y>) // f gets two arguments: 'ClassTemplate<X' and 'Y>'
If it is legal to add some extra parentheses there in C99, you can use:
f(((int[2]){ 1, 2 }));
^ ^
The rule specifying this behavior, from C99 ยง6.10.3/11, is as follows:
The sequence of preprocessing tokens bounded by the outside-most matching parentheses
forms the list of arguments for the function-like macro.
The individual arguments within the list are separated by comma preprocessing tokens, but comma preprocessing tokens between matching inner parentheses do not separate arguments.
To the extent that it's a bug at all, it's with the standard, not gcc (i.e., in this respect I believe gcc is doing what the standard requires).

Resources