C preprocessor - comparing macro arguments - c

wrt:
C preprocessor macro specialisation based on an argument
I am trying to use this technique to compare to 'void', however it also
matches 'void *'.
Has anybody else seen this problem ?
Is there a known solution ?
The source contains thousands of lines with preprocessor macros, so it is not easily readable. However it is like this:
#define GIVE_A_FUNCTION(RetType,Name,ArgType1)\
RetType Name(ArgType1 ArgName1) \
{ \
SWITCH_ON_VOID( \
RetType,\
,\
RetType value =)\
GetValue(); \
PostProcessing(); \
SWITCH_ON_VOID( \
RetType,\
,\
return value;)\
}
This expands to nothing if type is 'void *', hence I do not include the
return statement.
I can solve the problem manually but would prefer not to.
Regards,

Related

Function or macro definition which one to use

I have some macros that I use a lot
So I was thinking in my case would it be better to use a function or use the macro definition?
Example of a macro code that I use:
#define Test(Id, TName, i, FName, var1, var2, var3) do { \
if (GetTable(Id, TName)) { \
while (i < 5) { \
if (GetField(Id, FName)) { \
const char *user = PushName(Id, FName); \
if (!CheckNameisValid(user)) \
continue; \
var1 = GetTimestamp(user); \
var2 = GetSex(user); \
var3 = GetCntLogin(user); \
i++; \
} \
} \
} \
} while (false);
What would be better to use for as per the above code?
Keep using macro definition or migrate to function ?
Given how the macro is written, it would be much better to use a function for this purpose. The macro does not use any construction such as referring to a structure member whose name is passed as an argument to the macro.
The macro has multiple problems:
variable i is assumed to have been declared and initialized appropriately, but it is only incremented if CheckNameisValid(user) is non zero, potentially causing an infinite loop.
the ; should not be part of the macro expansion to allow usage as a single expression statement.
it is unclear if the variables var1, var2, var3 should be updated once or multiple times, and the caller has no way to tell what actually happened as a side effect of this macro.
Defining functions with clear semantics is much preferred. Don't even worry about inline functions, modern compilers can determine which functions are worth inlining even if not defined as such.
would it be better to use a function or use the macro definition?
A function.
What would be better to use for as per the above code?
A function.
Keep using macro definition or migrate to function ?
Migrate to function.

c _Generic and macro funtion

I'm writing DEBUG_MSG for print debug messages
#define DEBUG_MSG(msg_str) _DEBUG_MSG_GENERIC(msg_str)
The _DEBUG_MSG_GENERIC is because I'd like to:
Show int message when a input parameter is int
Show char* message when a input parameter is char*
and its implement:
#define _DEBUG_MSG_GENERIC(strs) \
_Generic( (strs), \
int: _DEBUG_MSG_INT, \
default: _DEBUG_MSG_STR \
)(strs)
Now I'd like to implement _DEBUG_MSG_INT and _DEBUG_MSG_STR with Macro function and printf :
#define _DEBUG_MSG_INT(val) printf("%d\n", val);
#define _DEBUG_MSG_STR(str) printf("%s\n", str);
But I got error message is:
main.c:14:30: error: ‘_DEBUG_MSG_INT’ undeclared (first use in this function); did you mean ‘DEBUG_MSG’?
14 | int: _DEBUG_MSG_INT, \
| ^~~~~~~~~~~~~~
How do I solve it?
Does _generic only support function(pointer to function) and not support macro function?
Full Code
#include <stdio.h>
#define DEBUG_MSG(msg_str) _DEBUG_MSG_GENERIC(msg_str)
#define _DEBUG_MSG_GENERIC(strs) \
_Generic( (strs), \
int: _DEBUG_MSG_INT, \
default: _DEBUG_MSG_STR \
)(strs)
#define _DEBUG_MSG_INT(val) printf("%d\n", val)
#define _DEBUG_MSG_STR(str) printf("%s\n", str)
int main()
{
DEBUG_MSG("str");
DEBUG_MSG(5);
}
The problem is that both _DEBUG_MSG_INT and _DEBUG_MSG_STR are function-like macros thus they are only expanded if they are followed by ().
Note that macro expansion takes place before actual C compilation thus _Generic is nothing more than a common identifier at preprocessor stage.
I suggest using _Generic not for selection of the function pointer but rather for a formatting specifier to be used in printf(). Try:
#define _DEBUG_MSG_GENERIC(arg) printf( _DEBUG_MSG_FMTSPEC(arg), arg)
#define _DEBUG_MSG_FMTSPEC(arg) \
_Generic( (arg), int: "%d\n", default: "%s\n")
I believe your issue is because the preprocessor only makes one pass of the source code, so the printf's don't get substituted.
A quick solution would be to define _DEBUG_MSG_INT(val) and _DEBUG_MSG_STR(str) as real functions like so:
void _DEBUG_MSG_INT(int val) {
printf("%d\n", val);
}
void _DEBUG_MSG_STR(char * str) {
printf("%s\n", str);
}
The compiler will optimise out the extra function call overhead and will behave as if you called printf directly.
_Generic is not a preprocessor operation and cannot be used to select preprocessor macro functions. The code after a : in its cases must be a C expression (specifically an assignment-expression).
The code you have in those positions is _DEBUG_MSG_INT and _DEBUG_MSG_STR. Those are preprocessor macro names.
Those preprocessor macros are function-like macros. They are macro-replaced only when they are followed by a (. In your code, there is no ( after them, so they are not replaced.
That means the code after reprocessing looks like int : _DEBUG_MSG_INT,. So the compiler attempts to interpret _DEBUG_MSG_INT as an expression. Since _DEBUG_MSG_INT is not a declared identifier, the compiler reports an error that it is undeclared.
In summary, your code _Generic( (strs), int: _DEBUG_MSG_INT, default: _DEBUG_MSG_STR )(strs) attempts to use an after-preprocessing _Generic selection to select a preprocessing-time macro (either _DEBUG_MSG_INT or _DEBUG_MSG_STR) and then to have that macro treated as a function-like macros with the (strs) that appears after the _Generic. That simply cannot work; an after-preprocessing _Generic cannot select preprocessing macro names.

Can't understand statement (void)(x == y) and 1; in linux typecheck macro

In linux 5.4.21 source code include/linux/irqflags.h,
#define raw_local_save_flags(flags) \
do { \
typecheck(unsigned long, flags); \
flags = arch_local_save_flags(); \
} while (0)
and in include/linux/typecheck.h
#define typecheck(type,x) \
({ type __dummy; \
typeof(x) __dummy2; \
(void)(&__dummy == &__dummy2); \
1; \
})
I can't understand how the typecheck macro works. So the typecheck macro makes a variable __dummy having type type, and another variable __dummy2 with the same type with x. It then compares the address of those two variables. I guess putting (void) makes the comparison statement not make error.. but what does this comparison do? How can two variables have same address? and what is the last state 1; ? And what effect does this macro have in the raw_local_save_flags macro? (related to how it is called..) Can somebody explain it to me please? Thanks!
The comparison &__dummy == &__dummy2 is only permitted if the objects are of the same type, so a compiler will complain if they are not.
See this post about Compound Statements.
You can supply a brace-surrounded block (a compound statement) as a valid expression whose value is the last expression in the block.
So in ({ int x = c; x; }) the value of the expression is evaluated as x;

Macro ternary comma expression causes warning when used as a statement

I have defined a macro to log NULL pointers. Because I have NULL checks in my code, the macro is a ternary that always returns the argument and calls a function if it is NULL.
This however causes a compile warning (gcc: right-hand operand of comma expression has no effect) if the macro is used outside of an if statement.
Curiously, clang doesn't produce a warning, even with -Weverything.
The solution I have come up so far is defining another macro that wraps the expression in an if without a body.
#define NULLPRINT(X) \
((X) ? (X) \
: (fprintf(stderr, \
"%s:%u: %s: %s is NULL.\n", \
__FILE__, \
__LINE__, \
__func__, \
#X), \
stacktrace(), \
(X)))
#define IF_NULLPRINT(X) do {if(NULLPRINT(X)){}} while(0)
Is there a way to do this without macro duplication and avoiding the compiler warning?
Obviously without turning off the warning.
Try casting it to void:
(void) NULLPRINT(...);
This generally suppresses warnings about unused values of expressions.
You could define another macro that hides this.

C macro get typeof argument

I am trying to write a macro to assist with object oriented programming in C. As I store the class information in a constant struct, I need to create a macro that does the following:
Take the type of the object (typeof the derefenced pointer)
Append _info to get the name of the desired classInfo struct
Take the address of that symbol so it can be passed to the function
Call the destroyObject function with a pointer to the class struct and the object itself
An example:
queue_t* p = NULL;
delete(p);
delete should expand to:
destroyObject(&(queue_t_info), p);
I tried using this macro, but I can't get to to work:
#define delete(X) (destroyObject(&(typeof(*X)##_info), X))
I'm having trouble with the typeof part to work correctly.
typeof isn't macro, it is language construction and it is expanded by compiler, not preprocessor. Since preprocessing goes before compilation, macro can't access typeof result.
Your delete(p) is expanded to: (destroyObject(&(typeof(*p)_info), p)). (You can see it by -E gcc flag)
I realized that what I was attempting to do was impossible - the C preprocessor doesn't parse and symbolize the code so it doesn't know which type a variable is.
To solve this, I require the type to be passed into the delete function as well. This isn't ideal as it introduces a frequent source of bugs due to mismatched types. If a programmer passes a pointer to object A but specifies object B in the delete function, the wrong destructor would be called. To solve this, I added a typecheck to the macro so that a compiler warning would be generated for any mismatched types.
#define typecheck(type,x) \
({ type __dummy; \
typeof(x) __dummy2; \
(void)(&__dummy == &__dummy2); \
})
#define delete(P, X) (destroyObject(&(X##_info), P), typecheck(X, *P))
#define new(X, ...) (createObject(&(X##_info), ##__VA_ARGS__))
Normal usage of the macro:
queue_t* p = new(queue_t);
delete(p, queue_t);
However using the wrong type:
queue_t* p = new(queue_t);
delete(p, int);
causes a compiler warning:
Comparison of distinct pointer types ('int *' and 'typeof (*p) *' (aka 'queue_t *'))

Resources