I am using log4cplus, and my misra-checks for something as innocent-looking as
LOG4CPLUS_INFO(
logger,
std::string("ABC") + std::string("DEF"));
yield (among others) The underlying type of `0L` is implicitly reduced from `8-bit signed char` to {code{bool}}.. This happens also when I put the respective literals rather than wrapping them inside string. I wonder how to fix this. Or, more generally put, how would you concatenate several log messages and yet keep MISRA-checks happy?
I had a look at LOG4CPLUS_INFO and that is a macro defined as:
#if !defined(LOG4CPLUS_DISABLE_INFO)
#define LOG4CPLUS_INFO(logger, logEvent) \
LOG4CPLUS_MACRO_BODY (logger, logEvent, INFO_LOG_LEVEL)
and LOG4CPLUS_MACRO_BODY is defined as:
#define LOG4CPLUS_MACRO_BODY(logger, logEvent, logLevel) \
LOG4CPLUS_SUPPRESS_DOWHILE_WARNING() \
do { \
log4cplus::Logger const & _l \
= log4cplus::detail::macros_get_logger (logger); \
if (LOG4CPLUS_MACRO_LOGLEVEL_PRED ( \
_l.isEnabledFor (log4cplus::logLevel), logLevel)) { \
LOG4CPLUS_MACRO_INSTANTIATE_OSTRINGSTREAM (_log4cplus_buf); \
_log4cplus_buf << logEvent; \
log4cplus::detail::macro_forced_log (_l, \
log4cplus::logLevel, _log4cplus_buf.str(), \
__FILE__, __LINE__, LOG4CPLUS_MACRO_FUNCTION ()); \
} \
} while (0) \
LOG4CPLUS_RESTORE_DOWHILE_WARNING()
and so your MISRA checker will be checking the invocation of the macro. And MISRA likes if statements to be defined explicitly in terms of bool e.g. rather than if(node) it likes if(node!=nullptr) and I think it may have an issue with the last line:
} while (0) \
As 0 is being implicitly cast to bool. You should see if you get the same warning by adding a simple do{}while(0); loop to your code and run your checker again.
And if you want a MISRA safe way of logging, I would avoid the use of macros. You can make a simple logging class with a std::ofstream and a std::mutex and keep it in namespace scope defined as an extern in your header file.
I am getting a weird error for one of my macros. The names are changed, but besides that the code is exactly the same as the one in my project. Its purpose is automatic a process I write many times troughout my code.
#ifdef add
#undef add
#endif
#define add(name, temp) \
struct name<temp> \
{ \
static constexpr r = true; \
}
Here is the error:
Function definition for 'add' not found.
explicit type is missing ('int' assumed)
It's expanding the code properly and showing me that too, but it seems either it is very confused about what's going on or I do not understand the error.
I am using Visual Studio 2019, so the VC++19 compiler.
I think you've forgotten bool keyword as compiler message suggested but as int
#ifdef add
#undef add
#endif
#define add(name, temp) \
struct name<temp> \
{ \
static constexpr bool r = true; \
}
What's the way to implement a standard-compliant assert macro with an optional formatted message?
What I have works in clang, but (correctly) triggers the -Wgnu-zero-variadic-macro-arguments warning if it is turned on (e.g. via -Wpedantic) when the macro is used without the optional message. Wandbox
#define MyAssert(expression, ...) \
do { \
if(!(expression)) \
{ \
printf("Assertion error: " #expression " | " __VA_ARGS__); \
abort(); \
} \
} while(0)
One needs to really use the preprocessor to the max in order to differentiate no additional arguments from the case where they are present. But with Boost.PP one can do this:
#include <boost/preprocessor/variadic/size.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/logical/bool.hpp>
#include <boost/preprocessor/cat.hpp>
#define MyAssert(...) BOOST_PP_CAT(MY_ASSERT,BOOST_PP_BOOL(BOOST_PP_SUB(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), 1)))(__VA_ARGS__)
#define MY_ASSERT0(expr) MY_ASSERT1(expr,)
#define MY_ASSERT1(expression, ...) \
do { \
if(!(expression)) \
{ \
std::printf("Assertion error: " #expression " | " __VA_ARGS__); \
std::abort(); \
} \
} while(0)
MyAssert must accept at least one argument (standard). Then we count the arguments, subtract one, and turn to a boolean (0 or 1). This 0 or 1 is concatenated to the token MY_ASSERT to form a macro name, to which we proceed to forward the arguments.
MY_ASSERT1 (with args), is your original macro. MY_ASSERT0 substitutes itself with MY_ASSERT1(expr,), the trailing comma means we pass another argument (thus fulfilling the requirement for the one extra argument), but it is an empty token sequence, so it does nothing.
You can see it live.
Since we already went down this rabbit hole, if one doesn't want to pull in Boost.PP the above can be accomplished with the usual argument counting trick, slightly adapted. First, we must decide on a maximum limit for the arguments we allow. I chose 20, you can choose more. We'll need the typical CONCAT macro, and this macro here:
#define HAS_ARGS(...) HAS_ARGS_(__VA_ARGS__,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,)
#define HAS_ARGS_(a1,a2,a3,a4,a5,b1,b2,b3,b4,b5,c1,c2,c3,c4,c5,d1,d2,d3,d4,d5,e, N, ...) N
It's argument counting, but with a twist. When __VA_ARGS__ is a single argument (no extra ones), the N resolved as 0. Otherwise, it is resolved as 1. There can be up to 20 extra arguments after the expression, any number of which will resolve to the same 1. Now we just plug it into the same place we used boost before:
#define MyAssert(...) CONCAT(MY_ASSERT, HAS_ARGS(__VA_ARGS__))(__VA_ARGS__)
You can tinker with it here
I have a solution which I'm not particularly proud of..
We can obtain the first argument in plain form and as a string using:
#define VA_ARGS_HEAD(N, ...) N
#define VA_ARGS_HEAD_STR(N, ...) #N
Note that in usage, in order to not get warnings, you should do VA_ARGS_HEAD(__VA_ARGS__, ) (with the extra ,) so that VA_ARGS_HEAD is never used with a single parameter (trick taken from StoryTeller's answer).
We define the following helper function:
#include <stdarg.h>
#include <stdio.h>
inline int assertionMessage(bool, const char *fmt, ...)
{
int r;
va_list ap;
va_start(ap, fmt);
r = vprintf(fmt, ap);
va_end(ap);
return r;
}
When the assertion has a format string, the function would work with __VA_ARGS__ as is, however when the bool is the only argument, we're missing a format string. That's why we'll add another empty string after __VA_ARGS__ when invoking it:
#define MyAssert(...) \
do { \
if(!(VA_ARGS_HEAD(__VA_ARGS__, ))) \
{ \
printf("Assertion error: %s | ", VA_ARGS_HEAD_STR(__VA_ARGS__, )); \
assertionMessage(__VA_ARGS__, ""); \
abort(); \
} \
} while(0)
Note that assertionMessage doesn't have printf in its name. This is deliberate and intended to avoid the compiler giving format-string related warnings for its invocations with the extra "" argument. The down-side for this is that we don't get the format-string related warnings when they are helpful.
The basic solution is to use << on cerr:
#define MyAssert(expression, msg) \
do { \
if(!(expression)) \
{ \
std::cerr << msg; \
abort(); \
} \
} while(0)
This solution uses C++ streams, so you can format the output as you see fit. Actually this is a simplification of a C++17 solution that I'm using to avoid temporaries (people tend to use + instead of << with this solution, triggering some efficiency warnings).
Use it then like this:
MyAssert(true, "message " << variable << " units");
I think the optionality is bogus here, as you are outputting "Assertion error:" meaning that you expect a message.
I'm using the macros from this post looping through my arguments. Everything works great! However, is there a way to combine these two CCB_CREATE and CCB_CREATE_MORE?
I need to extract the first argument object_type to write additional code. The additional object_types will be using the FOR_EACH loop to insert into the map.
The compiler complaints when I only have one argument when using CCB_CREATE_MORE(Type1). To fix that I made another macro to handle that CCB_CREATE(Type1). Hoping to find a clever solution to combine these two into one elegant macro. Any ideas?
#define INSERT_LOADER_MAP(object_type) loader_map.insert(make_pair(#object_type, object_type##Loader::loader()))
#define CCB_CREATE_MORE(object_type,...) \
static CCNode * create##object_type##Node() { \
std::map<std::string, CCNodeLoader*> loader_map; \
std::string classname = #object_type; \
FOR_EACH(INSERT_LOADER_MAP,object_type,__VA_ARGS__); \
return loadCCBFile((classname + ".ccbi").c_str(), loader_map); \
}
#define CCB_CREATE(object_type) \
static CCNode * create##object_type##Node() { \
std::map<std::string, CCNodeLoader*> loader_map; \
std::string classname = #object_type; \
INSERT_LOADER_MAP(object_type); \
return loadCCBFile((classname + ".ccbi").c_str(), loader_map); \
}
The compiler is likely complaining about the trailing comma when the variadic arguments list is empty. GCC and Visual Studio compilers support the non-standard extension ##__VA_ARGS__ to suppress the trailing comma:
#define FOO(fmt, ...) printf(fmt, ##__VA_ARGS__)
The Visual Studio compilers will also suppress the trailing comma even without the ## extension.
See GCC documentation here, and Visual Studio documentation here.
If you need a standards-compliant solution, there is one detailed in an answer to this question.
So if you are using either gcc or Visual Studio, you should be able to use your original macro with this simple change:
#define CCB_CREATE(object_type,...) \
static CCNode * create##object_type##Node() { \
std::map<std::string, CCNodeLoader*> loader_map; \
std::string classname = #object_type; \
FOR_EACH(INSERT_LOADER_MAP,object_type,##__VA_ARGS__); \
return loadCCBFile((classname + ".ccbi").c_str(), loader_map); \
}
Edit:
You would need to use the ##__VA_ARGS__ extension in the FOR_EACH() macro as well, or the more elegant modification suggested by ugoren.
#define FOR_EACH(what, x, ...) FOR_EACH_(FOR_EACH_NARG(x, ##__VA_ARGS__), what, x, __VA_ARGS__)
In addition to Chris Olsen's suggestion, a slight change to the FOR_EACH macro is needed:
#define FOR_EACH(what, ...) FOR_EACH_(FOR_EACH_NARG(__VA_ARGS__), what, __VA_ARGS__)
As a result, FOR_EACH(X, a) will become X(a) (instead of X(a); X();). This eliminates an empty INSERT_LOADER_MAP invocation.
Is there any idiom that forces a semicolon after a cpp macro outside of a function?
The known solution for macros used inside functions is:
#define MACRO(x) \
do {
x * 2;
} while(0)
However, say I have a macro that looks like the following:
#define DETAIL(warning) _Pragma(#warning)
#define WARNING_DISABLE(warning) DETAIL(GCC diagnostic ignore warning)
What can I put in the macro that would force a semi-colon after that statement. The statement could be used in or outside of a function:
WARNING_DISABLE("-Wunused-local-typedefs")
#include "boost/filesystem.hpp"
void foo(const int x) {
WARNING_DISABLE("-Wsome-warning")
...
}
Is there any C/C++ syntax that will force a semi-colon in the parser at any point in a file that doesn't have side effects?
Edit: A possible use case:
#define MY_CPPUNIT_TEST_SUITE(test_suite_class) \
WARNING_PUSH \
/* the declaration of the copy assignment operator has been suppressed */ \
INTEL_WARNING_DISABLE(2268) \
/* the declaration of the copy assignment operator has been suppressed */ \
INTEL_WARNING_DISABLE(2270) \
/* the declaration of the copy constructor operator has been suppressed */ \
INTEL_WARNING_DISABLE(2273) \
CPPUNIT_TEST_SUITE(test_suite_class); \
WARNING_POP \
/* force a semi-colon */ \
UDP_KEYSTONE_DLL_LOCAL struct __udp_keystone_cppunit_test_suite ## __LINE__ {}
You don't need LINE trick - it is enough to forward-declare some structure, which is allowed multiple times and there is no need for actual definition. Also collision with actual struct should not be a problem.
#define DETAIL(warning) _Pragma(#warning) struct dummy
#define DETAIL(warning) _Pragma(#warning) struct X ## __LINE__ {}
The easiest is an extern function declaration
#define MACRO_END_(LINE) extern void some_inprobable_long_function_name ## LINE(void)
#define MACRO_END MACRO_END_(__LINE__)
the line trick is only there because some compilers with excessive warnings give you warnings on duplicate declarations.
This macro works in any context where a declaration is allowed, so with C99 almost everywhere:
#define DETAIL(warning) _Pragma(#warning) MACRO_END