Suppressing Error Highlighting of Macros in VS Code - c

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?

Related

#ifdef inside a #define?

I'm initializing an array of structures with the help of a define like this:
#define FLAGCODE(name) { #name, MNT_ ## name }
struct {
const char *name;
uint64_t flag;
} flagcodes[] = {
FLAGCODE(ACLS),
FLAGCODE(ASYNC),
...
This works nicely, and now I'd like to add a check, whether each flag (such as MNT_ACLS) is defined without inserting an #ifdef and #endif for each symbol by hand?
That is, I want the macro FLAGCODE(name) to expand into (an equivalent of):
#ifdef MNT_ ##name
{ # name, MNT_ ##name },
#endif
Exempli gratia, if name is NOATIME, the code shall become:
#ifdef MNT_NOATIME
{ "NOATIME", MNT_NOATIME },
#endif
Yes, I realize, that this would mean double pass through preprocessor, and so is unlikely to be possible -- without a custom code-generator... But still...
There is a solution but highly not recommended! You could do funny things with C-preprocessor (cf. Macro to replace nested for loops and links in the question). But I repeat it: Don't do it. It is a cpp abuse.
In two words, you have to create your own #ifdef with macro. In the code below, ISDEF is an "operator" to check if the flag is defined and #if has been redefined: IIF (To understand, all explanations are here: https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#define COMMA ,
#define IIF(c) PRIMITIVE_CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t
#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define PROBE(x) x, 1,
#define ISDEF(x) CHECK(PRIMITIVE_CAT(ISDEF_, x))
#define ISDEF_ PROBE(~)
#define FLAGCODE(name) IIF(ISDEF(name))({ #name COMMA MNT_ ## name }COMMA)
#define ACLS
#define FLAGDEFINED
int main()
{
struct {
const char *name;
uint64_t flag;
} flagcodes[] = {
FLAGCODE(ACLS)
FLAGCODE(ASYNC)
FLAGCODE(FLAGDEFINED)
FLAGCODE(FLAGNOTDEFINED)
...
You could also do a list with your flags (cf. MAP part in http://jhnet.co.uk/articles/cpp_magic).
Enjoy but do not go overboard with preprocessor.
Following the very good comment of Chris Dodd,
1 : This tricks works if the flag is define as empty (#define FLAGDEFINED). It does not work with, for example, #define FLAGDEFINED 1 or #define FLAGDEFINED xxx.
2 : CPP_ prefix has been added and name is changed by CPP_FLAG
#define CPP_PRIMITIVE_CAT(CPP_a, ...) CPP_a ## __VA_ARGS__
#define CPP_COMMA ,
#define CPP_IIF(CPP_c) CPP_PRIMITIVE_CAT(CPP_IIF_, CPP_c)
#define CPP_IIF_0(CPP_t, ...) __VA_ARGS__
#define CPP_IIF_1(CPP_t, ...) CPP_t
#define CPP_CHECK_N(CPP_x, CPP_n, ...) CPP_n
#define CPP_CHECK(...) CPP_CHECK_N(__VA_ARGS__, 0,)
#define CPP_PROBE(CPP_x) CPP_x, 1,
#define CPP_ISDEF(CPP_x) CPP_CHECK(CPP_PRIMITIVE_CAT(CPP_ISDEF_, CPP_x))
#define CPP_ISDEF_ CPP_PROBE(~)
#define CPP_FLAGCODE(CPP_FLAG) CPP_IIF(CPP_ISDEF(CPP_FLAG))({ #CPP_FLAG CPP_COMMA MNT_ ## CPP_FLAG }CPP_COMMA)
#define ACLS
#define FLAGDEFINED

Is it possible to define _Generic's association-list dynamically?

I have a template like this:
template.h
----------
// Declare a function "func_type()"
void JOIN(func_, T)(T t) { return; }
#undef T
which I use like this in order to generate the same function for different types:
example.c
---------
#define T int
#include "template.h"
#define T float
#include "template.h"
I would like to have a single func that I can use instead of funct_int, func_float, etc. My problem with _Generic is that it doesn't seem possible to define the association-list dynamically. In practical terms I'd like to have something like this:
#define func(TYPE) _Generic((TYPE), AUTO_GENERATED_LIST)
instead of manually defining every new type like this:
#define func(TYPE) _Generic((TYPE), int: func_int..., float: func_float...)
Here's an example of code that is not working: https://ideone.com/HN7sst
I think what you want to do can be achieved with the dreaded "X macros". Create a list such as
#define SUPPORTED_TYPES(X) \
X(int, "%d") \
X(float, "%f") \
where int is the type and in this case I used printf format specifier as another item. These can be anything that counts as valid pre-processor tokens.
Then you can generate all functions through an evil macro like this:
#define DEFINE_F(type, fmt) \
void f_##type (type param) \
{ printf(fmt "\n", param); }
SUPPORTED_TYPES(DEFINE_F)
This creates functions such as void f_int (int param) { printf("%d\n", param); }. That is, very similar to C++ templates - functions doing the same thing but with different types.
You can then write your _Generic macro like this:
void dummy (void* param){}
#define GENERIC_LIST(type, fmt) type: f_##type,
#define func(x) _Generic((x), SUPPORTED_TYPES(GENERIC_LIST) default: dummy)(x)
Here you define the generic asoc. list with GENERIC_LIST, using the type item but ignoring everything else. So it expands to for example int: f_int,.
A problem with this is the old "trailing comma" problem, we can't write _Generic like _Generic((x), int: f_int,)(x) the comma after f_int would mess up the syntax. I solved this with a default clause calling a dummy function, not ideal... might want to stick an assert inside that function.
Full example:
#include <stdio.h>
#define SUPPORTED_TYPES(X) \
X(int, "%d") \
X(float, "%f") \
#define DEFINE_F(type, fmt) \
void f_##type (type param) \
{ printf(fmt "\n", param); }
SUPPORTED_TYPES(DEFINE_F)
void dummy (void* param){}
#define GENERIC_LIST(type, fmt) type: f_##type,
#define func(x) _Generic((x), SUPPORTED_TYPES(GENERIC_LIST) default: dummy)(x)
int main (void)
{
int a = 1;
float b = 2.0f;
func(a);
func(b);
}
Output:
1
2.000000
This is 100% ISO C, no extensions.

MSVC: Error mapping a structure to an array of offsetof

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__)))

Using a macro for a function

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
}

Define array and symbolic indices at same time

I'm trying to think of a clever way (in C) to create an array of strings, along with symbolic names (enum or #define) for the array indices, in one construct for easy maintenance. Something like:
const char *strings[] = {
M(STR_YES, "yes"),
M(STR_NO, "no"),
M(STR_MAYBE, "maybe")
};
where the result would be equivalent to:
const char *strings[] = {"yes", "no", "maybe"};
enum indices {STR_YES, STR_NO, STR_MAYBE};
(or #define STR_YES 0, etc)
but I'm drawing a blank for how to construct the M macro in this case.
Any clever ideas?
A technique used in the clang compiler source is to create .def files that contains a list like this, which is designed like a C file and can easily be maintained without touching other code files that use it. For example:
#ifndef KEYWORD
#define KEYWORD(X)
#endif
#ifndef LAST_KEYWORD
#define LAST_KEYWORD(X) KEYWORD(X)
#endif
KEYWORD(return)
KEYWORD(switch)
KEYWORD(while)
....
LAST_KEYWORD(if)
#undef KEYWORD
#undef LAST_KEYWORD
Now, what it does is including the file like this:
/* some code */
#define KEYWORD(X) #X,
#define LAST_KEYWORD(X) #X
const char *strings[] = {
#include "keywords.def"
};
#define KEYWORD(X) kw_##X,
#define LAST_KEYWORD(X) kw_##X
enum {
#include "keywords.def"
};
In your case, you could do similar. If you can live with STR_yes, STR_no, ... as enumerator names you could use the same approach like above. Otherwise, just pass the macro two things. One lowercase name and one uppercase name. Then you could stringize the one you want like above.
This is a good place to use code generation. Use a language like perl, php or whatever to generate your .h file.
It is not required to put this into specific .def files; using only the preprocessor is perfectly possible. I usually define a list named ...LIST where each element is contained within ...LIST_ELEMENT. Depending on what I will use the list for I will either just separate with a comma for all but the last entry (simplest), or in the general case make it possible to select the separator individually on each usage. Example:
#include <string.h>
#define DIRECTION_LIST \
DIRECTION_LIST_ELEMENT( up, DIRECTION_LIST_SEPARATOR ) \
DIRECTION_LIST_ELEMENT( down, DIRECTION_LIST_SEPARATOR ) \
DIRECTION_LIST_ELEMENT( right, DIRECTION_LIST_SEPARATOR ) \
DIRECTION_LIST_ELEMENT( left, NO_COMMA )
#define COMMA ,
#define NO_COMMA /**/
#define DIRECTION_LIST_ELEMENT(elem, sep) elem sep
#define DIRECTION_LIST_SEPARATOR COMMA
typedef enum {
DIRECTION_LIST
} direction_t;
#undef DIRECTION_LIST_ELEMENT
#undef DIRECTION_LIST_SEPARATOR
#define DIRECTION_LIST_ELEMENT(elem, sep) void (*move_ ## elem)(struct object_s * object);
#define DIRECTION_LIST_SEPARATOR NO_COMMA
typedef struct object_s {
char *name;
// ...
DIRECTION_LIST
} object_t;
#undef DIRECTION_LIST_ELEMENT
#undef DIRECTION_LIST_SEPARATOR
static void move(object_t *object_p, const char * direction_string)
{
if (0) {
}
#define DIRECTION_LIST_SEPARATOR NO_COMMA
#define DIRECTION_LIST_ELEMENT(elem, sep) \
else if (strcmp(direction_string, #elem) == 0) { \
object_p->move_ ## elem(object_p); \
}
DIRECTION_LIST
#undef DIRECTION_LIST_ELEMENT
#undef DIRECTION_LIST_SEPARATOR
}

Resources