Functions parameters using macro - c

I wanted to know if it was contraindicated to define functions parameters using a macro, knowing they could be variable. Does it break a coding convention ?
example:
#ifdef PREVIOUSLY_DEFINED_MACRO
# define PARAMETERS int a, long b
#else
# define PARAMETERS int a
#endif
void my_func(PARAMETERS)
{
...
}
Thanks !

The code is completely valid but, it's not a good coding practice.
Let's assume the following code snippet:
#ifdef PREV_DEFINED
#define ARGS int x, int y
#else
#define ARGS int x
#endif
#include <stdio.h>
// #define PREV_DEFINED
int func(ARGS) {
// In this context, only 'x' is available
// set by the macro
return (x + y); // ERROR, 'y' is undefined
// You need to make a different code, specifically for
// #ifdef PREV_DEFINED and #else
}
To solve this, you need to make two or more different functions within those #ifdef and #endif flags whose usage is controlled by the PREV_DEFINED macro that depends on how many parameters could be variadic. Eventually, this will make the code look worse.

Related

C define macro that expands not the same when not used for the first time

Is it possible to write:
#define FIRST_DEF 1
#define SECOND_DEF 2
#ifndef ALREADY_DEFINED
#define MY_MACRO FIRST_DEF
#define ALREADY_DEFINED
#else
#define MY_MACRO SECOND_DEF
#endif
So that MY_MACRO does not have the same value when not used the first time?
So that writting:
int a = MY_MACRO;
int b = MY_MACRO;
expands to:
int a = 1;
int b = 2;
If not, is there a way to do this?
(I know that this example is silly but it is just to make the question clearer.)
For your example, you can use the pre-defined macro __COUNTER__ which will get incremented everytime it is used. Note that it is a non-standard compiler extension, but both GCC and MSVC support it.
Yes. I think it is OK.
#include "xxx.h"
// FIRST_DEF here
#include "xxx.h"
// SeCOND_DEF here
But you must include the header twice

How do you test if two #defines are the same with the C preprocessor

I have a C program which has platform-specific defines for access to low-level hardware. On some platforms, two macros point to the same variable, on others they are different:
//Platform_One.h
#define FOO_PORT (io.portA)
#define BAR_PORT (io.portB)
//Platform_Two.h
#define FOO_PORT (io.portC)
#define BAR_PORT (io.portC) //same
I have some initializer code that is different based on whether the #defines are the same or not. Conceptually, I'd like code like this:
callback_struct_t callbacks[] = {
#if FOO_PORT == BAR_PORT //unfortunately invalid
{&FOO_PORT, handle_foo_bar_func},
#else
{&FOO_PORT, handle_foo_func},
{&BAR_PORT, handle_bar_func},
#endif
{0,0}
};
Is there a reliable way to test at compile time if two arbitrary macros have the same definition?
You cannot compare the preprocessor macros as strings. One possibility would be to put the hardware port address (e.g., via another macro in the platform-specific headers) into the #defines and then compare the addresses.
However, the easiest way might be to do the comparison of addresses in actual code, e.g.:
if (&FOO_PORT == &BAR_PORT) {
// populate callbacks with handle_foo_bar_func
} else {
// populate callbacks with handle_foo_func and handle_bar_func
}
While not done in pre-processor, the compiler may be able to optimise away the unused branch since the hardware addresses are likely compile-time constants.
With the gnu c processor it can be done with stringification: https://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification
You could do something like this:
#include <stdio.h>
#include <string.h>
#define FOO_PORT (io.portA)
#define BAR_PORT (io.portB)
//#define FOO_PORT (io.portC)
//#define BAR_PORT (io.portC)
#define XMACRO_TEST(macro_a, macro_b) MACRO_TEST(macro_a, macro_b)
#define MACRO_TEST(macro_a, macro_b) \
if(strcmp((#macro_a),(#macro_b)) == 0) { \
printf(#macro_a" == "#macro_b"\n"); \
} else { \
printf(#macro_a" != "#macro_b"\n"); \
} \
int main(int argc, char *argv[])
{
XMACRO_TEST(FOO_PORT, BAR_PORT)
return 0;
}
You can compare macros that evaluate to integers.
My understanding is you have three options:
change the macro logic
use numerical values for port number macros (are they physical addresses?)
fill the callback structure with c code as one of the comments suggets.
The last option seems to be the most favourable. With propper use of const, the calculation will be carried at complile time by most compilers, anyway.

Define constant inside #ifdef in C

I want to define a constant depending on the OS in use.
As such:
#include <stdio.h>
#ifdef _Win32 //Used for system("cls") command
#include <process.h>
#define CLEAR "system(\"cls\")"
#endif
#ifdef __APPLE__
#define CLEAR "system(\"clear\")"
#endif
int main()
{
CLEAR;
}
Xcode gives me an error stating that expression result unused at
#define CLEAR "system(\"clear\") and inside the main function.
I am on a Mac.
Use:
#define CLEAR system("clear")
not
#define CLEAR "system(\"clear\")"
You get the error because your macro call is substituted with:
"system(\"clear\")";
which is a useless expression statement (the expression being the string here) like for example:
0; // valid but pointless
try altering your main function as such:
int main()
{
int rc;
rc = CLEAR;
return rc;
}
You need to catch the return value of the system() call and use it
#define CLEAR system("clear")
and not
#define CLEAR "system(\"clear\")"
The compiler will create a new C code (called pre-processor code) in which will replace the macro name by its content.
so if you define macro in this way:
#define CLEAR "system(\"clear\")"
You will get in the new code (pre-processor code) generated by the Compiler:
int main()
{
"system(\"clear\")";
}
You can see the code generated by the compiler (pre-processor code) with gcc -E

Define with only 1 argument

I'm reading external C code, and I found the following line of code:
#define __MAIN_C__
where #define is given only one "argument" (namely __MAIN_C__).
Is this just a placeholder, or can it have a function?
That #define will define __MAIN_C__ to no value (thanks to n.m. and a simple test program). It's a shortcut when you need something #defined when you don't care what it's defined to. In that case, somewhere in your code, you'd probably just see:
#ifdef __MAIN_C__
And that doesn't care what specific value it has, as long as it's defined (and perhaps nonzero).
You'll very often see this for include guards, like so:
#ifndef MYHEADER_H
#define MYHEADER_H
// stuff here
#endif
This is similar to doing this in the compile flags:
gcc -D__MAIN_C__ main.c
If you want to see that it's defined to nothing, try to compile this and watch it fail:
#include <stdio.h>
#define TEST
int main(int argc, char *argv[])
{
printf("%d\n", TEST);
return 0;
}
Yes, this can accomplish something. If you look, there's a pretty decent chance you'll find something like: #ifdef __MAIN_C__ somewhere -- this just checks whether the symbol has been defined, regardless of the value (if any) given.
A define in this case simply sets MAIN_C. No value is assigned, but the preprocessor will interperet MAIN_C as "true". Generally, defines like these are used to include or exclude code before compilation, using something like the following:
#define WIN32
#ifdef WIN32
//some win32-specific code
#else
//some other code
#endif
This definition makes __MAIN_C__ to expand (roughly speaking) to nothing.
A possible use:
#ifdef __MAIN_C__
foo(bar);
#endif
Another one:
#ifdef PLAIN_OLD_OS
#define __MAIN_C__
#else
#define __MAIN_C__ __os_specific_attribute(dllsomething)
#endif
__MAIN_C__ int main (int argc, char* argv[]) {

Variable arguments in a Macro

I have a function which takes variable arguments, something like the following
int log_data (LOG_TYPE eType, ...)
{
/** some logging related stuff here **/
}
In the header file, I use something like
#ifdef LOGGING_ENABLED
int log_data (int nType, ...);
#else
#define log_data(_x_, ...)
#endif
Basically, the idea is to SWITCH debugging ON & OFF ~~~
Problem:
The above logic works perfectly fine in Linux & gcc, but errors outs during compilation in Windows VC++.
Variadic macros are relatively new, for example: this reference says that "Support for variadic macros was introduced in Visual C++ 2005." You might have an older version.
Edit: you are declaring log_data if you want debugging, and not if you don't. This means that you have the definition of the function in an #ifdef as well. As long as you're doing this, a solution would be:
int log_data (int nType, ...)
{
#ifdef LOGGING_ENABLED
/* the code to do logging */
#else
return 0; /* or whatever */
#endif
}
and in your header file, declare the function as usual:
int log_data (int nType, ...);
This has a disadvantage that the function call exists even when you're not logging, but the advantage is that it will work without preprocessor support for varargs.
Older versions of VC++ do not support variable arguments in macros.
You can use this trick to get around it:
#ifdef LOGGING_ENABLED
#define log_data log_data_impl
#else
#define log_data
#endif
// usage:
log_data(level, ...)
UPDATE - Another possible workaround:
#ifdef LOGGING_ENABLED
#define log_data(P) log_data_impl P // no braces around P!
#else
#define log_data(P)
#endif
// usage: we have to use two braces
log_data((level, ...));

Resources