Source Insight can't recognize multi-line macro - c

Here is a snippet:
#if defined(a) || \
defined(b)
void test();
#else
void test();
#endif
Source Insight can't recognize multi-line macro.
It treats
#if defined(a) || \
defined(b)
as
#if defined(a)
#if defined(a) || defined(b)
How do I fix this?

Related

Conditional X-MACROs to align ENUMs and String

I have a list of enums:
typedef enum {
ENUM1,
ENUM2,
#if FLAG
ENUM3,
#endif
} enum_var_t;
And a corresponding list of strings to align:
typedef struct { char[50] name; int val; } name_val_map_t
name_val_map_t name_val_map_table[] = {
{.name="string1", .val=ENUM1},
{.name="string2", .val=ENUM2},
#if FLAG
{.name="string3", .val=ENUM3},
#endif
};
FLAG is a build flag, and is either 0, or 1.
I am trying to use X-Macros to align these according to an answer here:
#define IF(cond, foo) IF_IMPL(cond, foo)
#define IF_IMPL(cond, foo) IF_ ## cond (foo)
#define IF_0(foo)
#define IF_1(foo) foo
#define var_list \
X(ENUM1, "string1"), \
X(ENUM2, "string2"), \
IF(FLAG, X(ENUM3, "string3")), \
#define X(ENUMVAL, ...) ENUMVAL
typedef enum {
var_list
}
#undef X
#define X(ENUMVAL, NAME) {.name = NAME, .val = ENUMVAL}
name_val_map_t name_val_map_table = {
var_list
}
This leads to an error which says I'm passing more arguments to the IF macro than declared. I presume it is treating the comma inside the X(ENUM3, "string3") as an argument separator for IF.
I tried encapsulating the X() call with braces and removing the braces from IF_IMPL, but that didn't work either. If I try expand the argument list in IF() using ..., and VA_ARGS, I get expected expression errors. I'm trying to avoid using a def file as this makes my file unreadable. Some solution like I was trying would be perfect to avoid code replication, and for readability. Any pointers would be welcome, thanks!
Using variadic macros.
#define IF(cond, foo) IF_IMPL(cond, foo)
#define IF_IMPL(cond, ...) IF_ ## cond(__VA_ARGS__)
#define IF_0(foo, ...)
#define IF_1(foo, ...) foo, __VA_ARGS__
Test:
//usr/local/bin/tcc -run "$0"; exit $?
#include <stdio.h>
#define FLAG3 1
#define FLAG4 0
#define FLAG5 1
typedef struct { char *name; int val; } name_val_map_t;
#define IF(cond, foo) IF_IMPL(cond, foo)
#define IF_IMPL(cond, ...) IF_ ## cond(__VA_ARGS__)
#define IF_0(foo, ...)
#define IF_1(foo, ...) foo, __VA_ARGS__
#define var_list \
X(ENUM1, "string1") \
X(ENUM2, "string2") \
IF(FLAG3, X(ENUM3, "string3")) \
IF(FLAG4, X(ENUM4, "string4")) \
IF(FLAG5, X(ENUM5, "string5")) \
typedef enum {
#define X(ENUMVAL, str) ENUMVAL,
var_list
#undef X
} enum_var_t;
name_val_map_t name_val_map_table[] = {
#define X(ENUMVAL, NAME) { NAME, ENUMVAL },
var_list
#undef X
{ "sentinel value", 99 }
};
int main(void){
int x =0;
while(name_val_map_table[x].val != 99){
printf("%i, %s\n", name_val_map_table[x].val, name_val_map_table[x].name);
x++;}
return 0;
}
/* output:
0, string1
1, string2
2, string3
3, string5
*/
Another option is to manually create IF_FLAGx( X(bla, bla) ) macros for every case...
See also: macro specialization based on argument in case of MSVC bug.
This seems needlessly complicated. I would simply do this instead:
#if FLAG
#define var_list \
X(ENUM1, "string1") \
X(ENUM2, "string2") \
X(ENUM3, "string3")
#else
#define var_list \
X(ENUM1, "string1") \
X(ENUM2, "string2")
#endif
Full example:
#include <stdio.h>
#define FLAG 1
#if FLAG
#define var_list \
X(ENUM1, "string1") \
X(ENUM2, "string2") \
X(ENUM3, "string3")
#else
#define var_list \
X(ENUM1, "string1") \
X(ENUM2, "string2")
#endif
typedef enum
{
#define X(enum_var, str) enum_var,
var_list
#undef X
ENUM_N
} enum_var_t;
typedef struct
{
char name[50];
int val;
} name_val_map_t;
const name_val_map_t name_val_map_table[] =
{
#define X(enum_var, str) { .name = str, .val = enum_var },
var_list
#undef X
};
int main (void)
{
for(size_t i=0; i<ENUM_N; i++)
{
printf("%d %s\n", name_val_map_table[i].val, name_val_map_table[i].name);
}
}

Preprocessor definitions not working in C

I've been frantically trying to get this following code to work. The preprocessor definitions WIDR and LIDR aren't working and it's giving me the compile error:
projects/elcain.c: In function ‘main’:
projects/elcain.c:17:6: error: ‘WIDR’ undeclared (first use in this function)
if ( WIDR ) {
^
projects/elcain.c:17:6: note: each undeclared identifier is reported only once for each function it appears in
projects/elcain.c:19:13: error: ‘LIDR’ undeclared (first use in this function)
} else if ( LIDR ) {
I don't really have experience with preprocessor macros, or the preprocessor in general, so go easy on me.
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#define WIDR 1
#elif defined _linux_
#define LIDR 1
#endif
int main () {
char* directory = (char*) malloc (1);
if ( WIDR ) {
strcpy(directory, "C:\\TEMP\\");
} else if ( LIDR ) {
strcpy(directory, "~/.temp/");
} else {
*directory = 0x00;
}
printf("%s\n", directory);
return 0;
}
You probably simply want this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main () {
#ifdef _WIN32
char directory[] = "C:\\TEMP\\";
#elif defined _linux_
char directory[] = "~/.temp/";
#else
#error Neither _WIN32 nor _linux_ are defined
#endif
printf("%s\n", directory);
return 0;
}
What you are looking for is something like this:
#include <stdlib.h>
#if defined unix || \
defined __unix || \
defined __unix__ || \
defined __linux__ || \
defined __FreeBSD__ || \
defined __CYGWIN__ || \
(defined __APPLE__ && defined __MACH__)
static const char TMP_DIR[] = "~/.temp/";
#elif defined WIN32 || \
defined _WIN32 || \
defined __WIN32
static const char TMP_DIR[] = "C:\\TEMP\\";
#else
#error "Platform not supported"
#endif
int
main(void)
{
printf("%s\n", TMP_DIR);
return EXIT_SUCCESS;
}
In fact both WIDR and LIDR are conditional compilation directives. In other words they exist at compilation time only.
Change your code like this:
#ifdef WIDR
strcpy(directory, "C:\\TEMP\\");
#elif defined LDIR
strcpy(directory, "~/.temp/");
#else
*directory = 0x00;
#endif
then compilation errors will gone

implicit declaration of function and undefined reference to

About compile suricata.
In Makefile,when CFLAGS wrap "-Werror-implicit-function-declaration"
I got the error:
detect-engine-siggroup.c: In function ‘SigGroupHeadFree’:
detect-engine-siggroup.c:187:9: error: implicit declaration of function ‘_mm_free’ [-Werror=implicit-function-declaration]
SCFreeAligned(sgh->mask_array);
^
detect-engine-siggroup.c: In function ‘SigGroupHeadBuildHeadArray’:
detect-engine-siggroup.c:1715:5: error: implicit declaration of function ‘_mm_malloc’ [-Werror=implicit-function-declaration]
sgh->mask_array = (SignatureMask *)SCMallocAligned((cnt * sizeof(SignatureMask)), 16);
When I delete "-Werror-implicit-function-declaration" in Makefile,I will got the error:
detect-engine-siggroup.o: In function `SigGroupHeadFree':
/root/suricata/suricata-2.0.9/src/detect-engine-siggroup.c:187: undefined reference to `_mm_free'
detect-engine-siggroup.o: In function `SigGroupHeadBuildHeadArray':
/root/suricata/suricata-2.0.9/src/detect-engine-siggroup.c:1715: undefined reference to `_mm_malloc'
Note:_mm_free and _mm_malloc is define in util-mem.h
Yet,I add some code in the other source file,but not in detect-engine-siggroup.c and util-mem.h.
What's wrong?
in detect-engine-siggroup.c(note I have deleted some redundant code here):
void SigGroupHeadFree(SigGroupHead *sgh)
{
if (sgh == NULL)
return;
SCLogDebug("sgh %p", sgh);
PatternMatchDestroyGroup(sgh);
#if defined(__SSE3__) || defined(__tile__)
if (sgh->mask_array != NULL) {
/* mask is aligned */
SCFreeAligned(sgh->mask_array);
sgh->mask_array = NULL;
}
#endif
if (sgh->head_array != NULL) {
SCFree(sgh->head_array);
sgh->head_array = NULL;
}
if (sgh->match_array != NULL) {
detect_siggroup_matcharray_free_cnt++;
detect_siggroup_matcharray_memory -= (sgh->sig_cnt * sizeof(Signature *));
SCFree(sgh->match_array);
sgh->match_array = NULL;
}
sgh->sig_cnt = 0;
if (sgh->init != NULL) {
SigGroupHeadInitDataFree(sgh->init);
sgh->init = NULL;
}
SCFree(sgh);
detect_siggroup_head_free_cnt++;
detect_siggroup_head_memory -= sizeof(SigGroupHead);
return;
}
in util-mem.h(note I have deleted some redundant code here):
#ifndef __UTIL_MEM_H__
#define __UTIL_MEM_H__
#include "util-atomic.h"
#if CPPCHECK==1
#define SCMalloc malloc
#define SCCalloc calloc
#define SCRealloc realloc
#define SCFree free
#define SCStrdup strdup
#define SCMallocAligned _mm_malloc
#define SCFreeAligned _mm_free
#else /* CPPCHECK */
#if defined(_WIN32) || defined(__WIN32)
#include "mm_malloc.h"
#endif
#if defined(__tile__)
/* Need to define __mm_ function alternatives, since these are SSE only.
*/
#include <malloc.h>
#define _mm_malloc(a,b) memalign((b),(a))
#define _mm_free(a) free((a))
#endif /* defined(__tile__) */
SC_ATOMIC_EXTERN(unsigned int, engine_stage);
/* Use this only if you want to debug memory allocation and free()
* It will log a lot of lines more, so think that is a performance killer */
/* Uncomment this if you want to print memory allocations and free's() */
//#define DBG_MEM_ALLOC
#ifdef DBG_MEM_ALLOC
#define SCFree(a) ({ \
extern uint8_t print_mem_flag; \
if (print_mem_flag == 1) { \
SCLogInfo("SCFree at %p", (a)); \
} \
free((a)); \
})
#else /* !DBG_MEM_ALLOC */
#define SCFree(a) ({ \
free(a); \
})
#if defined(__WIN32) || defined(_WIN32)
#define SCFreeAligned(a) ({ \
_mm_free(a); \
})
#else /* !win */
#define SCFreeAligned(a) ({ \
_mm_free((a)); \
})
#endif /* __WIN32 */
#endif /* DBG_MEM_ALLOC */
#endif /* CPPCHECK */
#endif /* __UTIL_MEM_H__ */
#endif /* DBG_MEM_ALLOC */
#endif /* CPPCHECK */
#endif /* __UTIL_MEM_H__ */
/*********************************************************************/
Now solved the problem,reason is forgetting to #include <pmmintrin.h> /* for SSE3 */
/*********************************************************************/
It looks like you have not included util-mem.h properly. SCFreeAligned seem to expand to _mm_free, but _mm_free doesn't seem to expand. Looking at the header file the definition of _mm_free seem to be dependent on __title__ being defined.
Then the compiler just sees a call to _mm_free which is given an implicit prototype as _mm_free doesn't exist. Then of course _mm_free will not be found during linking.

Boost Preprocessor Recursion

I'm trying to create a 'C' macro (not C++) that will define and initialize static data.
For example:
STATIC_CONST_STRUCT
(
A, a,
MEMBER_DATA(CONST_STR, a, "Hello, a")
MEMBER_DATA(CONST_STR, b, "Hello, b")
MEMBER_STRUCT
(
C, c,
MEMBER_DATA(CONST_STR, d, "Hello, d")
MEMBER_DATA(CONST_INT, e, 1)
)
);
Would cause the 'C' preprocessor to create:
static const struct A
{
CONST_STR a;
CONST_STR b;
struct C
{
CONST_STR d;
CONST_INT e;
} c;
} =
{"Hello, a", "Hello, b", {"Hello, d", 1}};
I've tried to use the Boost Preprocessor
http://www.boost.org/doc/libs/1_54_0/libs/preprocessor/doc/
but I can't quite figure out how to make this work. My macros stop expanding. I suspect the recursive nature of the problem having an arbitrarily deep nesting is why.
The solutions I read regarding getting the preprocessor to recurse either don't work, or the description of how to get recursion to work isn't clear enough to implement a working solution.
Here's what I have so far:
#define MEMBER_DATA_TAG 0
#define MEMBER_STRUCT_TAG 1
#define MEMBER_TAG(MEMBER) BOOST_PP_SEQ_ELEM(0, MEMBER)
#define MEMBER_DATA_TYPE(MEMBER_DATA) BOOST_PP_SEQ_ELEM(1, MEMBER_DATA)
#define MEMBER_DATA_NAME(MEMBER_DATA) BOOST_PP_SEQ_ELEM(2, MEMBER_DATA)
#define MEMBER_DATA_VALUE(MEMBER_DATA) BOOST_PP_SEQ_ELEM(3, MEMBER_DATA)
#define MEMBER_STRUCT_TYPE(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(1, MEMBER_STRUCT)
#define MEMBER_STRUCT_NAME(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(2, MEMBER_STRUCT)
#define MEMBER_STRUCT_MEMBER_SEQ(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(3, MEMBER_STRUCT)
#define MEMBER_DATA(TYPE, NAME, VALUE) ((MEMBER_DATA_TAG)(TYPE)(NAME)(VALUE))
#define MEMBER_STRUCT(TYPE, NAME, MEMBER_SEQ) ((MEMBER_STRUCT_TAG)(TYPE)(NAME)(MEMBER_SEQ))
#define IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM) BOOST_PP_EQUAL(MEMBER_TAG(MEMBER_SEQ_ELEM), MEMBER_STRUCT_TAG)
#define MEMBER_STRUCT_DECLARE(TYPE, NAME, MEMBER_SEQ) \
struct TYPE \
{ \
BOOST_PP_SEQ_FOR_EACH(MEMBER_ELEM_DECLARE, BOOST_PP_EMPTY(), MEMBER_SEQ) \
} NAME
#define MEMBER_ELEM_DECLARE(_r, _data, MEMBER_SEQ_ELEM) \
BOOST_PP_IIF \
( \
IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM), \
MEMBER_STRUCT_DECLARE \
( \
MEMBER_STRUCT_TYPE(MEMBER_SEQ_ELEM), \
MEMBER_STRUCT_NAME(MEMBER_SEQ_ELEM), \
MEMBER_STRUCT_MEMBER_SEQ(MEMBER_SEQ_ELEM) \
), \
MEMBER_DATA_DECLARE \
( \
MEMBER_DATA_TYPE(MEMBER_SEQ_ELEM), \
MEMBER_DATA_NAME(MEMBER_SEQ_ELEM), \
MEMBER_DATA_VALUE(MEMBER_SEQ_ELEM) \
) \
);
#define MEMBER_DATA_DECLARE(TYPE, NAME, VALUE) TYPE NAME
#define MEMBER_VALUE_INIT(MEMBER_SEQ) \
BOOST_PP_SEQ_FOR_EACH_I(MEMBER_VALUE_INIT_DECLARE, BOOST_PP_EMPTY(), MEMBER_SEQ);
#define MEMBER_VALUE_INIT_DECLARE(_r, _data, i, MEMBER_SEQ_ELEM) \
BOOST_PP_COMMA_IF(i) \
BOOST_PP_IIF \
( \
IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM), \
{MEMBER_VALUE_INIT(MEMBER_SEQ_ELEM)}, \
MEMBER_DATA_VALUE(MEMBER_SEQ_ELEM) \
)
#define STATIC_CONST_STRUCT(TYPE, NAME, MEMBER_SEQ) \
static const MEMBER_STRUCT_DECLARE(TYPE, NAME, MEMBER_SEQ) = \
{ \
MEMBER_VALUE_INIT(MEMBER_SEQ) \
}
Thanks.
It can be done without boost-preprocessor.
You don't actually need recursion. Just a loop to iterate over the macro arguments twice.
I took liberty of modifying the syntax a bit, to allow for commas in types and initializers, in case someone decides to use it with C++.
STATIC_CONST_STRUCT
(
A, a,
MEMBER_DATA(a, const char *) "Hello, a"
MEMBER_DATA(b, const char *) "Hello, b"
MEMBER_STRUCT
(
C, c,
MEMBER_DATA(d, const char *) "Hello, d"
MEMBER_DATA(e, int) 42
)
)
This expands to:
static const struct A
{
const char *a;
const char *b;
struct C
{
const char *d;
int e;
} c;
} a =
{
"Hello, a",
"Hello, b",
{
"Hello, d",
42,
},
};
Implementation:
#define STATIC_CONST_STRUCT(type_, name_, ...) \
static const struct type_ { \
END( LOOP_DECL_0 (__VA_ARGS__) ) \
} name_ = { \
END( LOOP_INIT_0 (__VA_ARGS__) ) \
};
#define MEMBER_DATA(name_, ...) )(var,name_,(__VA_ARGS__),
#define MEMBER_STRUCT(type_, name_, ...) )(open,type_ __VA_ARGS__ )(close,name_
#define IDENTITY(...) __VA_ARGS__
#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x##y
#define END(...) END_(__VA_ARGS__)
#define END_(...) __VA_ARGS__##_END
#define LOOP_DECL_0() LOOP_DECL_A
#define LOOP_DECL_A(...) LOOP_DECL_BODY(__VA_ARGS__) LOOP_DECL_B
#define LOOP_DECL_B(...) LOOP_DECL_BODY(__VA_ARGS__) LOOP_DECL_A
#define LOOP_DECL_0_END
#define LOOP_DECL_A_END
#define LOOP_DECL_B_END
#define LOOP_DECL_BODY(action_, ...) CAT(LOOP_DECL_BODY_, action_)(__VA_ARGS__)
#define LOOP_DECL_BODY_var(name_, type_, ...) IDENTITY type_ name_;
#define LOOP_DECL_BODY_open(type_) struct type_ {
#define LOOP_DECL_BODY_close(name_) } name_;
#define LOOP_INIT_0() LOOP_INIT_A
#define LOOP_INIT_A(...) LOOP_INIT_BODY(__VA_ARGS__) LOOP_INIT_B
#define LOOP_INIT_B(...) LOOP_INIT_BODY(__VA_ARGS__) LOOP_INIT_A
#define LOOP_INIT_0_END
#define LOOP_INIT_A_END
#define LOOP_INIT_B_END
#define LOOP_INIT_BODY(action_, ...) CAT(LOOP_INIT_BODY_, action_)(__VA_ARGS__)
#define LOOP_INIT_BODY_var(name_, type_, ...) __VA_ARGS__,
#define LOOP_INIT_BODY_open(type_) {
#define LOOP_INIT_BODY_close(name_) },
If used with C++, IDENTITY type_ should be wrapped in std::type_identity_t<...> to allow using types such as function pointers without typedefing them. void (*)() foo; is illegal, while std::type_identity_t<void (*)()> foo; is ok.

Variable arguements in macro using ellipsis

I want to define a macro accepting either 1 or 2 parameters. Both the parameters should be different type. How to use ellipsis and read the arguments passed?
Below is the sample:
void test(char *var2)
{
printf("%s\n",var2);
}
#define PRINT_STRING(...) ( if (!var1) test(var2) )
int main(int argc, _TCHAR argv[]) {
PRINT_STRING(TRUE);
PRINT_STRING(FALSE,"Hello, World!");
return 0;
}
This is known as a Variadic macro.
If your compiler supports __VA_ARGS__, you can do it like this:
#include <stdio.h>
#define NUM_ARGS__(X, \
N64,N63,N62,N61,N60, \
N59,N58,N57,N56,N55,N54,N53,N52,N51,N50, \
N49,N48,N47,N46,N45,N44,N43,N42,N41,N40, \
N39,N38,N37,N36,N35,N34,N33,N32,N31,N30, \
N29,N28,N27,N26,N25,N24,N23,N22,N21,N20, \
N19,N18,N17,N16,N15,N14,N13,N12,N11,N10, \
N09,N08,N07,N06,N05,N04,N03,N02,N01, N, ...) N
#define NUM_ARGS(...) \
NUM_ARGS__(0, __VA_ARGS__, \
64,63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define PRINT_STRING_1(var) \
{ if (!(var)) {} }
#define PRINT_STRING_2(var, ...) \
{ if (!(var)) test(__VA_ARGS__); }
#define PRINT_STRINGN__(N, ...) \
PRINT_STRING_##N(__VA_ARGS__)
#define PRINT_STRINGN(N, ...) \
PRINT_STRINGN__(N, __VA_ARGS__)
#define PRINT_STRING(...) \
PRINT_STRINGN(NUM_ARGS(__VA_ARGS__), __VA_ARGS__)
void test(char* var2)
{
printf("%s\n", var2);
}
int main(void)
{
PRINT_STRING(1);
PRINT_STRING(0, "Hello, World!");
PRINT_STRING(1, "You can't see me!");
return 0;
}
Output:
Hello, World!
To do something like that you'd have to implement a series of macros, something like this
#include <stdbool.h>
#define PRINT_STRING0(X, Y) do { if (X && Y) test(Y); } while(false)
#define PRINT_STRING1(X, Y, ...) PRINT_STRING0(X, Y)
#define PRINT_STRING(...) PRINT_STRING1(__VA_ARGS__, 0, 0)
The last of them (user interface) adds a second or third argument of 0. PRINT_STRING1 then ignores all arguments that are more than 2. And PRINT_STRING0 then does the work.
Some more remarks:
be careful that a macro like you want to program it here can be place syntactically just as any other statement. In the example here the do { } while(false) does that trick
since C99 has Boolean type and constants, these are _Bool or bool and false and true
Don't use a macro to do that, use a variadic function!
void print_string( bool should_print, ... )
{
if( should_print )
{
va_list argp;
va_start( argp, should_print);
char *string = va_arg(argp, char *);
if( string) printf("%s", string );
va_end( argp );
}
}
But be very careful when using these sorts of things, because va_arg doesn't check if you really have a 2nd argument.
Also, to use a macro that accepts one or 2 arguments, use the GCC trick (at the very bottom of this page):
#define PRINT_STRING( should , args... ) print_string( should , ##args )
(note the spaces between the commas)

Resources