I'm having the following problem with a macro for a function. This was working until I added the print_heavyhitters function. I have this in m61.h:
#if !M61_DISABLE
#define malloc(sz) m61_malloc((sz), __FILE__, __LINE__)
#define free(ptr) m61_free((ptr), __FILE__, __LINE__)
#define realloc(ptr, sz) m61_realloc((ptr), (sz), __FILE__, __LINE__)
#define calloc(nmemb, sz) m61_calloc((nmemb), (sz), __FILE__, __LINE__)
#define print_heavyhitters(sz) print_heavyhitters((sz), __FILE__, __LINE__)
#endif
in m61.c, all of these functions are fine except print_heavyhitters(sz). I get " - Macro usage error on the function print_heavyhitters:
- Macro usage error for macro:
print_heavyhitters
- Syntax error
m61.c:
#include "m61.h"
...
void *m61_malloc(size_t sz, const char *file, int line) {...}
void print_heavyhitters(size_t sz, const char *file, int line) {...}
You use the same name for the macro and the function it was intended to expand to.
Using the same name for the macro and for the function name is OK as far as the preprocessor is concerned, since it won't expand it recursively, but it can easily lead to confusing errors such as this. You can do this as long as you're careful to #undef it in the right places, but I'd recommend using a different symbol name to avoid confusion.
I'd do something like this:
// Header file
#if !M61_DISABLE
...
#define print_heavyhitters(sz) m61_print_heavyhitters((sz), __FILE__, __LINE__)
#endif
// Source file
#include "m61.h"
#if !M61_DISABLE
#undef print_heavyhitters
#endif
void print_heavyhitters(size_t sz)
{
// Normal implementation
}
void m61_print_heavyhitters(size_t sz, const char *file, int line)
{
// Debug implementation
}
Related
The Issue
Well, I have this really interesting macro set
#define __macro_3_opt_args(_0, _1, _2, _3, name, ...) name
#define _macro_3_opt_args_(arg0, arg1, arg2, arg3, ...) __macro_3_opt_args(, ##__VA_ARGS__, arg3, arg2, arg1, arg0)(__VA_ARGS__)
#define __padding_id(size, id) uint8_t _padding_##id##_ [size]
#define ____padding_line(size, line) __padding_id(size, ln##line) //adding `ln` prefix
#define ___padding_line(size, line) ____padding_line(size, line) //expanding `__LINE__` macro first
#define __padding_line(size) ___padding_line(size, __LINE__)
#define _padding_(...) _macro_2_opt_args_(, __padding_line, __padding_id, __VA_ARGS__)
#define offset_struct union
#define _offset_zero_member(type, name) type name
#define _offset_member(type, name, offset) struct { __padding_id(offset, to_##name); type name; }
#define offset_member(type, name, ...) _macro_3_opt_args_(, , _offset_zero_member, _offset_member, type, name, ##__VA_ARGS__)
But if I try to use it (like this:)
offset_struct Test {
offset_member (int, header);
offset_member (void*, data, 64);
} test;
//Let's say this two code snippets are in a same file
VS highlights the offset_member macro "calls" as errors (I use Microsoft's C/C++ Extension).
When I lookup VS Code's macro expansion
it shows struct { uint8_t _padding_to__ []; void*, data,64 ; }
instead of struct { uint8_t _padding_to_data_ [64]; void* data; } (what GCC sees)
The Question
How do I make VS ignore the macro expansion?
Can I use some magic #pragma for that?
Or is there a config that does it?
Is there a way to define a macro that voids variable list of arguments?
#define VOID_ARGS(...) ((void)##__VA_ARGS__)
The use case is void arguments to suppress compiler error [-Werror=unused-value] when warnings treated as errors:
#define DEBUG 1
#ifdef DEBUG
#define func(fmt, ...) dbg_func(fmt, ##__VA_ARGS__)
#else
#define func(fmt, ...) VOID_ARGS(fmt, ##__VA_ARGS__)
#endif
Does this give you an idea how to solve that problem?
debug.h:
extern int dbg_func(const char *format, ...);
//Does nothing
extern int ignoreDebug(const char *format, ...);
#define DEBUG 1
#ifdef DEBUG
#define func(fmt, ...) dbg_func(fmt, ##__VA_ARGS__)
#else
#define func(fmt, ...) ignoreDebug(fmt, ##__VA_ARGS__)
#endif
debug.c:
int ignoreDebug(const char *format, ...)
{
(void)format;
return 0;
}
int dbg_func(const char *format, ...)
{
TODO: Some code needs to go here.
return 0;
}
Rather than attempting to put the debug logic in the function declaration, add it to the function body instead:
int dbg_func(const char *format, ...)
{
#ifdef DEBUG
// normal debug logic
#else
(void)format;
return 0;
#endif
}
I found a way only using the processor. The idea came from this answer https://stackoverflow.com/a/11763277/6082851 The idea is to define a bunch of macros that void the arguments, one macro per possible number of arguments. With the use of __VA_ARGS__, the correct macro can be chosen depending on the number of arguments. Sadly, i didn't found a way to make it recursive so that a limited number of macros can be used for an arbitrary number of arguments, the only way i found was to define a macro for each possible number of arguments. But it can be expanded to an arbitrary amount.
#include <stdio.h>
#ifndef DEBUG
#define DEBUG 1
#endif
#if DEBUG
#define DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__)
#else
//GET_MACRO will get the 6. argument
#define GET_MACRO(a,b,c,d,e,f,...) f
//Macros that void a number of arguments
#define SET_VOID0()
#define SET_VOID1(a) (void)a;
#define SET_VOID2(a,b) (void)a;(void)b;
#define SET_VOID3(a,b,c) (void)a;(void)b;(void)c;
#define SET_VOID4(a,b,c,d) (void)a;(void)b;(void)c;(void)d;
#define SET_VOID5(a,b,c,d,e) (void)a;(void)b;(void)c;(void)d;(void)e;
//Void all arguments to avoid compiler warnings.
//SET_VOID5 is used when there are 5 arguments used, SET_VOID4 when 4 are used, ...
#define DEBUG_PRINT(...) GET_MACRO(__VA_ARGS__, SET_VOID5, SET_VOID4, SET_VOID3, SET_VOID2, SET_VOID1, SET_VOID0)(__VA_ARGS__)
#endif
int main(void)
{
int foo=5;
int bar=3;
DEBUG_PRINT("Foo %i Bar %i\n",foo,bar);
return 0;
}
I am trying to define a global logger one time in a header file doing the following:
// log.c
#include <stdio.h>
#include "log.h"
void log_add_file(const char* filename)
{
printf("Adding file %s", filename);
}
void log_log(const char* filename, const char* function, int line, int level, ...)
{
printf("LOG");
}
// logmain.c
#include "log.h"
int main(void)
{
log_add_file("log.txt");
log_info("Hello");
}
#ifndef LOG_H
#define LOG_H
#include <stdio.h>
#define DEFAULT_FORMAT "[%(levelname)] %(time) %(name) - %(filename):%(funcName):%(lineno) - %(msg)"
enum LogLevel {
DEBUG=10,
INFO=20,
WARN=30,
ERROR=40,
};
struct logger {
int level;
const char* format;
FILE** handlers;
int num_handlers;
};
struct logger Logger = {INFO, DEFAULT_FORMAT, NULL, 1};
#define log_debug(...) log_log(__FILE__, __func__, __LINE__, DEBUG, __VA_ARGS__)
#define log_info(...) log_log(__FILE__, __func__, __LINE__, INFO , __VA_ARGS__)
#define log_warn(...) log_log(__FILE__, __func__, __LINE__, WARN , __VA_ARGS__)
#define log_error(...) log_log(__FILE__, __func__, __LINE__, ERROR , __VA_ARGS__)
void log_add_file(const char* filename);
void log_log(const char* filename, const char* function, int line, int level, ...);
#endif
The offending line is:
struct logger Logger = {INFO, DEFAULT_FORMAT, NULL, 1};
And the compiler says:
duplicate symbol _Logger____ in:
/var/folders/b1/mmc6r_jj00ldzr2prvqzy56m0000gp/T/log-9f31fa.o
/var/folders/b1/mmc6r_jj00ldzr2prvqzy56m0000gp/T/logmain-220d4d.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
What is the compiler saying in this case? First, why would a duplicate symbol matter here if logmain.c doesn't call log.c and vice versa? And secondly, what would be a way to resolve this?
Do I just add in the word static and call it a day? Or can that lead to other unintended consequences? Basically, I want all files to have the exact same Logger to use that includes it (a singleton).
I am trying to create a log function which will print file name, function name, line number and error msg.
Is there a way to create macro for a small function which only takes the log type ,msg and macro value will add FILE, func, LINE and call the actual function
it might be something like this:
#define func(int type,const char *msg, ...) \
func(int type,char *__FILE__,char *__func__,char *__LINE__,const *msg,...)
If you want create a macro that during invocation replaces or adds some parameters, you don't have to write it as a prototype, but, because C preprocessor is a simple text replacement processor, you can write it as the invocation itself.
So your macro definition becomes:
#define func(type, msg, ...) \
func(type, __FILE__, __func__, __LINE__, msg, __VA_ARGS__)
The C preprocessor assign to the symbol __VA_ARGS__ the sequence of parameters, included the colon, that starts from elipsis (...) on.
Now using the macro as in the example below:
func(MYTYPE, "Info function called with stack: '%s' size %ld", bIsPrivilegedStack(stack) ? "Privileged" : "User", StackSize);
Will translate in:
func(MYTYPE, __FILE__, __func__, __LINE__, "Infofunction called with stack: '%s' size %ld", bIsPrivilegedStack(stack) ? "Privileged" : "User", StackSize);
The function prototype isn't in the macro and should be write once only, preferably contained in an header file, and appear in the compiling process before any invocation. It will contain all parameters types as in:
void func(int type, char *__FILE__, char *__func__, int _LINE__, const *msg, ...);
Note: the preprocessor symbol __LINE__ is defined as an int, not a char *.
Your file layout will be more or less:
//Prototype
void func(int type, char * file, char *fnc, int line, const *msg, ...);
//Macro definition
#define func(type, msg, ...) \
func(type, __FILE__, __func__, __LINE__, msg, __VA_ARGS__)
//Usage
void foo(void)
{
.....
func(MYTYPE, "Info function called with stack: '%s' size %ld", bIsPrivilegedStack(stack) ? "Privileged" : "User", StackSize);
.....
}
I am trying to fill-in an array with the offset of structure field, I am trying to do the following
#define EXPAND_(X) X
#define TYPE_ARG_N(_0, _1, _2, N, ...) N
#define TYPE_OFFSET_1(S, _0) { sizeof(S), { offsetof(S, _0) } }
#define TYPE_OFFSET_2(S, _0, _1) { sizeof(S), { offsetof(S, _0), offsetof(S, _1) } }
#define TYPE_OFFSET_3(S, _0, _1, _2) { sizeof(S), { offsetof(S, _0), offsetof(S, _1), offsetof(S, _2) } }
#define TYPE_OFFSET_LIST() TYPE_OFFSET_3, TYPE_OFFSET_2, TYPE_OFFSET_1
#define TYPE_OFFSET_N_(...) EXPAND_(TYPE_ARG_N(__VA_ARGS__))
#define TYPE_OFFSET_ARGS(...) EXPAND_(__VA_ARGS__)
#define TYPE_OFFSET_SELECT(...) TYPE_OFFSET_N_(__VA_ARGS__, TYPE_OFFSET_LIST())
#define TYPE_OFFSET(S, ...) TYPE_OFFSET_SELECT(__VA_ARGS__)(S, TYPE_OFFSET_ARGS(__VA_ARGS__))
typedef struct {
size_t size;
size_t* offsets;
} tTable;
tTable t = TYPE_OFFSET(tTable, size, offsets);
MSVC2017 fails with the following:
error C4003: not enough actual parameters for macro 'TYPE_OFFSET_2'
error C2065: 'offsets': undeclared identifier
error C2102: '&' requires l-value
Any idea on how to fix these macros ?
For debugging things like this, try running things through just the preprocessor using the /EP flag. Doing so with your code shows this output:
typedef struct {
size_t size;
size_t* offsets;
} tTable;
tTable t = fxma.h(17) : warning C4003: not enough actual parameters for macro 'TYPE_OFFSET_2'
{ sizeof(tTable), { offsetof(tTable, size, offsets), offsetof(tTable, ) } };
The problem here is that Microsoft's preprocessor has this notion of a single macro argument having commas in it. This happens when the commas are produced by the expansion of another macro.
In particular, TYPE_OFFSET calls TYPE_OFFSET_2 with (tTable, size, offset), but size, offset together (being the expansion of TYPE_OFFSET_ARGS(__VA_ARGS__)) isn't actually two different arguments... it's only 1. TYPE_OFFSET_2 then is getting only two arguments; in other words:
S is tTable1
_0 is size, offset
_1 is missing
(You can see this in the expansion; offsetof(tTable, size, offsets)).
A fix is to add a level of indirection. Replace your version of TYPE_OFFSET with this:
#define TYPE_OFFSET_CALL(X, Y) X Y
#define TYPE_OFFSET(S, ...) TYPE_OFFSET_CALL(TYPE_OFFSET_SELECT(__VA_ARGS__),(S, TYPE_OFFSET_ARGS(__VA_ARGS__)))