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.
Related
I wanted to know if it was contraindicated to define functions parameters using a macro, knowing they could be variable. Does it break a coding convention ?
example:
#ifdef PREVIOUSLY_DEFINED_MACRO
# define PARAMETERS int a, long b
#else
# define PARAMETERS int a
#endif
void my_func(PARAMETERS)
{
...
}
Thanks !
The code is completely valid but, it's not a good coding practice.
Let's assume the following code snippet:
#ifdef PREV_DEFINED
#define ARGS int x, int y
#else
#define ARGS int x
#endif
#include <stdio.h>
// #define PREV_DEFINED
int func(ARGS) {
// In this context, only 'x' is available
// set by the macro
return (x + y); // ERROR, 'y' is undefined
// You need to make a different code, specifically for
// #ifdef PREV_DEFINED and #else
}
To solve this, you need to make two or more different functions within those #ifdef and #endif flags whose usage is controlled by the PREV_DEFINED macro that depends on how many parameters could be variadic. Eventually, this will make the code look worse.
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
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");
}
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.
I'm tidying up some older code that uses 'magic numbers' all over the place to set hardware registers, and I would like to use constants instead of these numbers to make the code somewhat more expressive (in fact they will map to the names/values used to document the registers).
However, I'm concerned that with the volume of changes I might break the magic numbers. Here is a simplified example (the register set is more complex):
const short mode0 = 0;
const short mode1 = 1;
const short mode2 = 2;
const short state0 = 0;
const short state1 = 4;
const short state2 = 8;
so instead of :
set_register(5);
we have:
set_register(state1|mode1);
What I'm looking for is a build time version of:
ASSERT(5==(state1|mode1));
Update
#Christian, thanks for the quick response, I'm interested on a C / non-boost environment answer too because this is driver/kernel code.
NEW ANSWER :
In my original answer (below), I had to have two different macros to support assertions in a function scope and at the global scope. I wondered if it was possible to come up with a single solution that would work in both scopes.
I was able to find a solution that worked for Visual Studio and Comeau compilers using extern character arrays. But I was able to find a more complex solution that works for GCC. But GCC's solution doesn't work for Visual Studio. :( But adding a '#ifdef __ GNUC __', it's easy to choose the right set of macros for a given compiler.
Solution:
#ifdef __GNUC__
#define STATIC_ASSERT_HELPER(expr, msg) \
(!!sizeof \ (struct { unsigned int STATIC_ASSERTION__##msg: (expr) ? 1 : -1; }))
#define STATIC_ASSERT(expr, msg) \
extern int (*assert_function__(void)) [STATIC_ASSERT_HELPER(expr, msg)]
#else
#define STATIC_ASSERT(expr, msg) \
extern char STATIC_ASSERTION__##msg[1]; \
extern char STATIC_ASSERTION__##msg[(expr)?1:2]
#endif /* #ifdef __GNUC__ */
Here are the error messages reported for STATIC_ASSERT(1==1, test_message); at line 22 of test.c:
GCC:
line 22: error: negative width in bit-field `STATIC_ASSERTION__test_message'
Visual Studio:
test.c(22) : error C2369: 'STATIC_ASSERTION__test_message' : redefinition; different subscripts
test.c(22) : see declaration of 'STATIC_ASSERTION__test_message'
Comeau:
line 22: error: declaration is incompatible with
"char STATIC_ASSERTION__test_message[1]" (declared at line 22)
ORIGINAL ANSWER :
I do something very similar to what Checkers does. But I include a message that'll show up in many compilers:
#define STATIC_ASSERT(expr, msg) \
{ \
char STATIC_ASSERTION__##msg[(expr)?1:-1]; \
(void)STATIC_ASSERTION__##msg[0]; \
}
And for doing something at the global scope (outside a function) use this:
#define GLOBAL_STATIC_ASSERT(expr, msg) \
extern char STATIC_ASSERTION__##msg[1]; \
extern char STATIC_ASSERTION__##msg[(expr)?1:2]
There is an article by
Ralf Holly that examines different options for static asserts in C.
He presents three different approaches:
switch case values must be unique
arrays must not have negative dimensions
division by zero for constant expressions
His conclusion for the best implementation is this:
#define assert_static(e) \
do { \
enum { assert_static__ = 1/(e) }; \
} while (0)
Checkout boost's static assert
You can roll your own static assert if you don't have access to a third-party library static assert function (like boost):
#define STATIC_ASSERT(x) \
do { \
const static char dummy[(x)?1:-1] = {0};\
} while(0)
The downside is, of course, that error message is not going to be very helpful, but at least, it will give you the line number.
#define static_assert(expr) \
int __static_assert(int static_assert_failed[(expr)?1:-1])
It can be used anywhere, any times.
I think it is the easiest solution.
Before usage, test it with your compiler carefully.
Any of the techniques listed here should work and when C++0x becomes available you will be able to use the built-in static_assert keyword.
If you have Boost then using BOOST_STATIC_ASSERT is the way to go. If you're using C or don't want to get Boost
here's my c_assert.h file that defines (and explains the workings of) a few macros to handle static assertions.
It's a bit more convoluted that it should be because in ANSI C code you need 2 different macros - one that can work in the area where you have declarations and one that can work in the area where normal statements go. There is a also a bit of work that goes into making the macro work at global scope or in block scope and a bunch of gunk to ensure that there are no name collisions.
STATIC_ASSERT() can be used in the variable declaration block or global scope.
STATIC_ASSERT_EX() can be among regular statements.
For C++ code (or C99 code that allow declarations mixed with statements) STATIC_ASSERT() will work anywhere.
/*
Define macros to allow compile-time assertions.
If the expression is false, an error something like
test.c(9) : error XXXXX: negative subscript
will be issued (the exact error and its format is dependent
on the compiler).
The techique used for C is to declare an extern (which can be used in
file or block scope) array with a size of 1 if the expr is TRUE and
a size of -1 if the expr is false (which will result in a compiler error).
A counter or line number is appended to the name to help make it unique.
Note that this is not a foolproof technique, but compilers are
supposed to accept multiple identical extern declarations anyway.
This technique doesn't work in all cases for C++ because extern declarations
are not permitted inside classes. To get a CPP_ASSERT(), there is an
implementation of something similar to Boost's BOOST_STATIC_ASSERT(). Boost's
approach uses template specialization; when expr evaluates to 1, a typedef
for the type
::interslice::StaticAssert_test< sizeof( ::interslice::StaticAssert_failed<true>) >
which boils down to
::interslice::StaticAssert_test< 1>
which boils down to
struct StaticAssert_test
is declared. If expr is 0, the compiler will be unable to find a specialization for
::interslice::StaticAssert_failed<false>.
STATIC_ASSERT() or C_ASSERT should work in either C or C++ code (and they do the same thing)
CPP_ASSERT is defined only for C++ code.
Since declarations can only occur at file scope or at the start of a block in
standard C, the C_ASSERT() or STATIC_ASSERT() macros will only work there. For situations
where you want to perform compile-time asserts elsewhere, use C_ASSERT_EX() or
STATIC_ASSERT_X() which wrap an enum declaration inside it's own block.
*/
#ifndef C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546
#define C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546
/* first some utility macros to paste a line number or counter to the end of an identifier
* this will let us have some chance of generating names that are unique
* there may be problems if a static assert ends up on the same line number in different headers
* to avoid that problem in C++ use namespaces
*/
#if !defined( PASTE)
#define PASTE2( x, y) x##y
#define PASTE( x, y) PASTE2( x, y)
#endif /* PASTE */
#if !defined( PASTE_LINE)
#define PASTE_LINE( x) PASTE( x, __LINE__)
#endif /* PASTE_LINE */
#if!defined( PASTE_COUNTER)
#if (_MSC_VER >= 1300) /* __COUNTER__ introduced in VS 7 (VS.NET 2002) */
#define PASTE_COUNTER( x) PASTE( x, __COUNTER__) /* __COUNTER__ is a an _MSC_VER >= 1300 non-Ansi extension */
#else
#define PASTE_COUNTER( x) PASTE( x, __LINE__) /* since there's no __COUNTER__ use __LINE__ as a more or less reasonable substitute */
#endif
#endif /* PASTE_COUNTER */
#if __cplusplus
extern "C++" { // required in case we're included inside an extern "C" block
namespace interslice {
template<bool b> struct StaticAssert_failed;
template<> struct StaticAssert_failed<true> { enum {val = 1 }; };
template<int x> struct StaticAssert_test { };
}
}
#define CPP_ASSERT( expr) typedef ::interslice::StaticAssert_test< sizeof( ::interslice::StaticAssert_failed< (bool) (expr) >) > PASTE_COUNTER( IntersliceStaticAssertType_)
#define STATIC_ASSERT( expr) CPP_ASSERT( expr)
#define STATIC_ASSERT_EX( expr) CPP_ASSERT( expr)
#else
#define C_ASSERT_STORAGE_CLASS extern /* change to typedef might be needed for some compilers? */
#define C_ASSERT_GUID 4964f7ac50fa4661a1377e4c17509495 /* used to make sure our extern name doesn't collide with something else */
#define STATIC_ASSERT( expr) C_ASSERT_STORAGE_CLASS char PASTE( PASTE( c_assert_, C_ASSERT_GUID), [(expr) ? 1 : -1])
#define STATIC_ASSERT_EX(expr) do { enum { c_assert__ = 1/((expr) ? 1 : 0) }; } while (0)
#endif /* __cplusplus */
#if !defined( C_ASSERT) /* C_ASSERT() might be defined by winnt.h */
#define C_ASSERT( expr) STATIC_ASSERT( expr)
#endif /* !defined( C_ASSERT) */
#define C_ASSERT_EX( expr) STATIC_ASSERT_EX( expr)
#ifdef TEST_IMPLEMENTATION
C_ASSERT( 1 < 2);
C_ASSERT( 1 < 2);
int main( )
{
C_ASSERT( 1 < 2);
C_ASSERT( 1 < 2);
int x;
x = 1 + 4;
C_ASSERT_EX( 1 < 2);
C_ASSERT_EX( 1 < 2);
return( 0);
}
#endif /* TEST_IMPLEMENTATION */
#endif /* C_ASSERT_H_3803b949_b422_4377_8713_ce606f29d546 */
Try:
#define STATIC_ASSERT(x, error) \
do { \
static const char error[(x)?1:-1];\
} while(0)
Then you can write:
STATIC_ASSERT(a == b, a_not_equal_to_b);
Which may give you a better error message (depending on your compiler).
The common, portable option is
#if 5 != (state1|mode1)
# error "aaugh!"
#endif
but it doesn't work in this case, because they're C constants and not #defines.
You can see the Linux kernel's BUILD_BUG_ON macro for something that handles your case:
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
When condition is true, this becomes ((void)sizeof(char[-1])), which is illegal and should fail at compile time, and otherwise it becomes ((void)sizeof(char[1])), which is just fine.
Ensure you compile with a sufficiently recent compiler (e.g. gcc -std=c11).
Then your statement is simply:
_Static_assert(state1|mode1 == 5, "Unexpected change of bitflags");
#define MODE0 0
#define MODE1 1
#define MODE2 2
#define STATE0 0
#define STATE1 4
#define STATE2 8
set_register(STATE1|STATE1); //set_register(5);
#if (!(5==(STATE1|STATE1))) //MY_ASSERT(5==(state1|mode1)); note the !
#error "error blah blah"
#endif
This is not as elegant as a one line MY_ASSERT(expr) solution. You could use sed, awk, or m4 macro processor before compiling your C code to generate the DEBUG code expansion of MY_ASSERT(expr) to multiple lines or NODEBUG code which removes them for production.