Conditional Compilation #ifdef - c

I am trying to understand the #ifdef macros. Sample code below.
getval(int val)
{
if(val==0) {
#ifndef PKT
#define PKT
#endif
}
}
main() {
getval(0);
#ifdef PKT
printf("Packet\n");
#endif
}
I get output Packet even when I pass 1 to getval. Why am I getting output when PKT is not defined when val=1 ? Thanks.

The # directives are compile time and not run time. So it doesn't matter what you pass. If the macro PKT is defined then "Packet" is printed, else not.
If you are running gcc you can do gcc -E myfile.c and check the result after preprocessing.
If you remove the bunch of preprocessor directives from your getval function, then the "Packet" will not be printed, because in that case PKT is not defined, and therefore the #ifdef PKT is false and the printf does not reach the compiler.

That part where you #define PKT is evaluated by the preprocessor before the actual compilation, not during programm execution. Therefore, it is not subject to the condition if(val==0).

#define and #ifdef are evaluated at compile time (actually even before compilation). They are evaluated on a text file, independently of the C code which is below. Therefore in
if(val==0) {
#ifndef PKT
#define PKT
#endif
}
The #define is always done. Otherwise said, your code is equivalent to the same code where the define are outside a function. See https://en.wikipedia.org/wiki/C_preprocessor

This code could be used instead:
#define val 0
#if val==0
#ifndef PKT
#define PKT
#endif
#endif //val == 0
int main()
{
#ifdef PKT
printf("Packet\n");
#endif
}
However, note that you've to define val before compilation.
Or, you could use enum:
typedef enum {PKT, NO_PKT} Packet;
Packet p;
getval(int val)
{
if (val == 0)
p = PKT;
else
p = NO_PKT;
}
int main()
{
getval(1);
if (p == PKT)
printf("Packet\n");
}

Related

Warning: "extra ; ignored" by using C macros with ARMCC

My compiler raises the warning #381-D: extra ";" ignored in such a situation:
I have a struct defined, like the following
struct example_s
{
u8_t foo;
SOME_MACRO(bar);
};
The macro SOME_MACRO(x) does the following:
#if defined(SYSTEM_A)
#define SOME_MACRO(x) u16_t x##something
#else
#define SOME_MACRO(x) /* nothing */
#endif
Of course, the warning is correct, when SYSTEM_A is not defined. Simply because I have now a ; within the struct. But does someone know a way to avoid it correctly? I don't want to break the typical C-style by moving the ; into the macro.
One way that is a bit of a kludge but it seems to work with gcc:
#if defined(SYSTEM_A)
#define SOME_MACRO(x) u16_t x##something
#else
#define SOME_MACRO(x) int x[0] /* nothing */
#endif
With this method you end up with a struct like this:
struct example_s
{
u8_t foo;
int bar[0];
};
which has the correct size (i.e. as size as if bar had not been defined at all).
You can add an unnamed 0-width bitfield instead:
#if defined(SYSTEM_A)
#define SOME_MACRO(x) u16_t x##something
#else
#define SOME_MACRO(x) unsigned :0
#endif
you can also insert an empty anonymous struct :
#if defined(SYSTEM_A)
#define SOME_MACRO(x) u16_t x##something
#else
#define SOME_MACRO(x) struct {}
#endif

Unused var in non-debug configuration

I often write code like this:
int result = someMethod(arg1,arg2,...);
assert(result==0)
Let's say assert() is defined something like this:
#ifdef DEBUG
#define assert(e) if(!e) printf("something's wrong");
#else
#define assert(...)
#endif
The first piece of code would give a warning about 'result' being an unused var.
I could do something like:
#ifdef DEBUG
int result = someMethod(arg1,arg2,...);
#else
someMethod(arg1,arg2,...);
#endif
assert(result==0)
But that seems quite non-dry to me ...
What else could I do?
int result = someMethod(arg1,arg2,...);
assert(result==0);
(void)result;
A macro like assertion_code to enable certain code pieces only in debug configuration.
#if defined(NDEBUG)
#define assertion_code(v)
#else
#define assertion_code(v) v
#endif
Now you can write
assertion_code(int result =) expr();
assert(result == 0);
Whitespace and line breaks are irrelevant to the compiler, so...
#ifdef DEBUG
int result =
#endif
someMethod(arg1,arg2,...);
assert(result==0)
There is the explicit way:
static inline void debug(const char *msg)
{
#ifdef DEBUG
printf("%s\n", msg);
#else
(void)msg;
#endif
}
Then:
if (someMethod(arg1,arg2,...) != 0) {
debug(message);
}
As there is a fair chance you won't want to continue as normal when something is wrong, the explicit conditional clause is perhaps going to be useful anyway. Or were you planning to ignore errors when DEBUG is turned off?

Wunused-but-set-variable warning treatment

I have the following code, and while compiling it with gcc-4.6 I get warning:
warning: variable ‘status’ set but not used [-Wunused-but-set-variable]
#if defined (_DEBUG_)
#define ASSERT assert
#else /* _DEBUG_ */
#define ASSERT( __exp__ )
#endif
static inline void cl_plock(cl_plock_t * const p_lock)
{
status_t status;
ASSERT(p_lock);
ASSERT(p_lock->state == INITIALIZED);
status = pthread_rwlock_unlock(&p_lock->lock);
ASSERT(status == 0);
}
When _DEBUG_
flag isn't set I get the warning.
Any ideas how can I workaround this warning?
You can change your ASSERT macro to:
#if defined (_DEBUG_)
#define ASSERT assert
#else /* _DEBUG_ */
#define ASSERT( exp ) ((void)(exp))
#endif
If the expression has no sideeffects, then it should still be optimised out, but it should also suppress the warning (if the expression does have side-effects, then you would get different results in debug and non-debug builds, which you don't want either!).
The compiler option to turn off unused variable warnings is -Wno-unused.
To get the same effect on a more granular level you can use diagnostic pragmas like this:
int main()
{
#pragma GCC diagnostic ignored "-Wunused-variable"
int a;
#pragma GCC diagnostic pop
// -Wunused-variable is on again
return 0;
}
This is, of course, not portable but you can use something similar for VS.
You could surround the variable declaration of status with a #ifdef clause.
#ifdef _DEBUG_
status_t status
#endif
EDIT: You have to surround the call also:
#ifdef _DEBUG_
status = pthread_rwlock_unlock(&p_lock->lock);
#else
pthread_rwlock_unlock(&p_lock->lock);
#endif
or you can switch off the error message.

has no member compilation error

I have the following code and when I'm trying to compile it, I get an error:
error: ‘list_item_t’ has no member named ‘state’
Any creative ideas how to make this piece of code compile without warnings and erros?
#if defined (_DEBUG_)
#define ASSERT assert
#else /* _DEBUG_ */
#define ASSERT( exp ) ((void)(exp))
#endif`
typedef struct list_item {
struct list_item *p_next;
struct list_item *p_prev;
#ifdef _DEBUG_
int state;
#endif
} list_item_t;
main(int argc, char *argv)
{
list_item_t p_list_item;
ASSERT(p_list_item.state == 0);
}
Just #define ASSERT as
#if defined (_DEBUG_)
#define ASSERT assert
#else
#define ASSERT( exp ) (void)0
#endif
Note that this may change the behaviour of other code spots because ASSERT no longer evaluates its argument, but that's how people expect it to behave anyway.
Or perform a _DEBUG_ build, but this doesn't resolve the problem, it just avoids it.
Your class has the mentioned member if and only if _DEBUG_ is defined, and it apparently isn't.
#define _DEBUG_
in the beginning of your TU or change project settings to define it in some other way
This is due to
#define ASSERT( exp ) ((void)(exp))
which evaluates p_list_item.state == 0 and thus needs state to exist even when _DEBUG_ is not #define'd.

How to use #if inside #define in the C preprocessor?

I want to write a macro that spits out code based on the boolean value of its parameter. So say DEF_CONST(true) should be expanded into const, and DEF_CONST(false) should be expanded into nothing.
Clearly the following doesn't work because we can't use another preprocessor inside #defines:
#define DEF_CONST(b_const) \
#if (b_const) \
const \
#endif
You can simulate conditionals using macro token concatenation as follows:
#define DEF_CONST(b_const) DEF_CONST_##b_const
#define DEF_CONST_true const
#define DEF_CONST_false
Then,
/* OK */
DEF_CONST(true) int x; /* expands to const int x */
DEF_CONST(false) int y; /* expands to int y */
/* NOT OK */
bool bSomeBool = true; // technically not C :)
DEF_CONST(bSomeBool) int z; /* error: preprocessor does not know the value
of bSomeBool */
Also, allowing for passing macro parameters to DEF_CONST itself (as correctly pointed out by GMan and others):
#define DEF_CONST2(b_const) DEF_CONST_##b_const
#define DEF_CONST(b_const) DEF_CONST2(b_const)
#define DEF_CONST_true const
#define DEF_CONST_false
#define b true
#define c false
/* OK */
DEF_CONST(b) int x; /* expands to const int x */
DEF_CONST(c) int y; /* expands to int y */
DEF_CONST(true) int z; /* expands to const int z */
You may also consider the much simpler (though potentially less flexible):
#if b_const
# define DEF_CONST const
#else /*b_const*/
# define DEF_CONST
#endif /*b_const*/
Doing it as a paramterised macro is a bit odd.
Why not just do something like this:
#ifdef USE_CONST
#define MYCONST const
#else
#define MYCONST
#endif
Then you can write code like this:
MYCONST int x = 1;
MYCONST char* foo = "bar";
and if you compile with USE_CONST defined (e.g. typically something -DUSE_CONST in the makefile or compiler options) then it will use the consts, otherwise it won't.
Edit: Actually I see Vlad covered that option at the end of his answer, so +1 for him :)

Resources