Related
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.
For example, I saw source code like the following. Can we use #define in a function? How does it work? (more information: this code is what I copied from openvswitch source code):
void *
ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf)
{
switch (code) {
case OFPUTIL_ACTION_INVALID:
#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
#include "ofp-util.def"
OVS_NOT_REACHED();
#define OFPAT10_ACTION(ENUM, STRUCT, NAME) \
case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
#include "ofp-util.def"
}
OVS_NOT_REACHED();
}
#define OFPAT10_ACTION(ENUM, STRUCT, NAME) \
void \
ofputil_init_##ENUM(struct STRUCT *s) \
{ \
memset(s, 0, sizeof *s); \
s->type = htons(ENUM); \
s->len = htons(sizeof *s); \
} \
\
struct STRUCT * \
ofputil_put_##ENUM(struct ofpbuf *buf) \
{ \
struct STRUCT *s = ofpbuf_put_uninit(buf, sizeof *s); \
ofputil_init_##ENUM(s); \
return s; \
}
#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
OFPAT10_ACTION(ENUM, STRUCT, NAME)
#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
OFPAT10_ACTION(ENUM, STRUCT, NAME)
#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) \
void \
ofputil_init_##ENUM(struct STRUCT *s) \
{ \
memset(s, 0, sizeof *s); \
s->type = htons(OFPAT10_VENDOR); \
s->len = htons(sizeof *s); \
s->vendor = htonl(NX_VENDOR_ID); \
s->subtype = htons(ENUM); \
} \
\
struct STRUCT * \
ofputil_put_##ENUM(struct ofpbuf *buf) \
{ \
struct STRUCT *s = ofpbuf_put_uninit(buf, sizeof *s); \
ofputil_init_##ENUM(s); \
return s; \
}
#include "ofp-util.def"
#define is a preprocessor directive: it is used to generate the eventual C++ code before it is handled to the compiler that will generate an executable. Therefore code like:
for(int i = 0; i < 54; i++) {
#define BUFFER_SIZE 1024
}
is not executed 54 times (at the preprocessor level): the preprocessor simply runs over the for loop (not knowing what a for loop is), sees a define statement, associates 1024 with BUFFER_SIZE and continues. Until it reaches the bottom of the file.
You can write #define everywhere since the preprocessor is not really aware of the program itself.
Sure this is possible. The #define is processed by the preprocessor before the compiler does anything. It is a simple text replacement. The preprocessor doesn't even know if the line of code is inside or outside a function, class or whatever.
By the way, it is generally considered bad style to define preprocessor macros in C++. Most of the things they are used for can be better achieved with templates.
You can use it inside a function, but it is not scoped to the function. So, in your example, the second definitions of a macro will be a redefinition and generate an error. You need to use #undef to clear them first.
You can use #define anywhere you want. It has no knowledge of functions and is not bound by their scope. As the preprocessor scans the file from top-to-bottom it processes #defines as it sees them. Do not be misled (by silly code like this!) into thinking that the #define is somehow processed only when the function is called; it's not.
How does it work? All C/C++ files are first processed by... the preprocessor.
It doesn't know anything about C nor C++ syntax. It simply replaces THIS_THING with ANOTHER THING. That's why you can place a #define in functions as well.
Sure. #define is handled by the preprocessor which occurs well before the compiler has any sense of lines of code being inside functions, inside parameters lists, inside data structures, etc.
Since the preprocessor has no concept of C++ functions, it also means that there is no natural scope to macro definitions. So if you want to reuse a macro name, you have to #undef NAME to avoid warnings.
I am adding compile-time checks to my company's C++ projects to make sure the third-party libraries on all development machines and build servers are up-to-date. Most libraries define something like the following for e.g. version 3.1.4:
#define VERSION_MAJOR 3
#define VERSION_MINOR 1
#define VERSION_BUILD 4
This is nice and easy to check using static_assert or preprocessor directives.
Now I am looking at a third-party library that defines a single macro instead:
#define VERSION 3.1.4
How can I verify the value of such a macro at compile time?
With C++11, I could use a constexpr string comparison function, and stringify the macro to check it:
constexpr bool static_equal(const char * a, const char * b)
{
return (*a == *b) && (*a == '\0' || static_equal(a + 1, b + 1));
}
// stringification functions
#define str(x) #x
#define xstr(x) str(x)
static_assert(static_equal(xstr(VERSION), "3.1.4"), "incorrect version of libwhatever");
But we are using Visual Studio 2013 on the Windows machines, so I can only use the subset of C++11 that it supports. Unfortunately constexpr is not supported.
Here is what I am doing now:
#define str(x) #x
#define xstr(x) str(x)
#include xstr(libwhatever.version.is.VERSION.should.be.3.1.4)
Along with this, I add an empty file named libwhatever.version.is.3.1.4.should.be.3.1.4 to the project. So if the version is correct, the preprocessor will successfully include this file. Otherwise, it will fail with "Cannot open 'libwhatever.version.is.2.7.2.should.be.3.1.4', no such file or directory". And failing the build with a somewhat meaningful message is what counts in the end.
Of course this approach is not very flexible; for instance I cannot check for a minimal version, or a range of versions. But for me it is sufficient to be able to check the exact value.
This seems to work with Visual C++ as well as g++. I am not sure whether the behavior is entirely well-defined according to the standard, though.
You can't in the preprocessor, but you can abuse type traits!
VS 2013 seems to support variadic templates. Try using the macro CSTRING at https://stackoverflow.com/a/15912824/2097780 (you should be able to replace constexpr with const and have the code still work) and doing something like:
#define STRT(x) decltype(CSTRING(x))
static_assert(std::is_same<STRT(VERSION), STRT("3.1.4")>::value, "incorrect version of libwhatever");
EDIT: That doesn't work. However, if your compiler compiles this without errors:
extern const char data[] = "abc";
template <char C> struct x {
static const char c = C;
};
char buf[(int)x<"ABC123"[0]>::c];
int main() { return (int)buf; }
Then you can try this:
#include <type_traits>
#define VERSION 1.2.3
#define STR2(x) #x
#define STR(x) STR2(x)
template <char...> struct ststring;
// https://stackoverflow.com/a/15860416/2097780
#define MACRO_GET_1(str, i) \
(sizeof(str) > (i) ? str[(i)] : 0)
#define MACRO_GET_4(str, i) \
MACRO_GET_1(str, i+0), \
MACRO_GET_1(str, i+1), \
MACRO_GET_1(str, i+2), \
MACRO_GET_1(str, i+3)
#define MACRO_GET_16(str, i) \
MACRO_GET_4(str, i+0), \
MACRO_GET_4(str, i+4), \
MACRO_GET_4(str, i+8), \
MACRO_GET_4(str, i+12)
#define MACRO_GET_64(str, i) \
MACRO_GET_16(str, i+0), \
MACRO_GET_16(str, i+16), \
MACRO_GET_16(str, i+32), \
MACRO_GET_16(str, i+48)
#define MACRO_GET_STR(str) MACRO_GET_64(str, 0), 0
static_assert(std::is_same<ststring<MACRO_GET_STR(STR(VERSION))>,
ststring<MACRO_GET_STR("1.2.3")>>::value,
"invalid library version");
If you right click on your project->Properties->Build Events->Pre Build Event
You'll see an option that says "Command Line". You can put a call to another program here.
You could write another program in C++ or any language you prefer that checks your file (or any number of files you want) for "#define VERSION 3.1.4". You can abort your build and put any warnings you want in that program.
here is a tutorial: https://dillieodigital.wordpress.com/2012/11/27/quick-tip-aborting-builds-in-visual-studio-based-on-file-contents/
related reading: https://msdn.microsoft.com/en-us/library/e85wte0k.aspx
I tried messing with the preprocessor commands for a long time, and I couldn't find a way to do it using only preprocessor commands.
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.
I'm often use do-while(0) construct in my #defines, for the reasons described in this answer. Also I'm trying to use as high as possible warning level from compiler to catch more potential problem and make my code more robust and cross-platform. So I'm typically using -Wall with gcc and /Wall with MSVC.
Unfortunately MSVC complain about do-while(0) construct:
foo.c(36) : warning C4127: conditional expression is constant
What should I do about this warning?
Just disable it globally for all files? It does not seems to be good idea for me.
Summary: This warning (C4127) in this particular case is a subtle compiler bug. Feel free to disable it.
In depth:
It was meant to catch situations when logical expression evaluates to a constant in non-obvious situations (such as, if(a==a && a!=a), and somehow, it turned while(true) and other useful constructs into invalid.
Microsoft recommends using for(;;) for infinite loop if you want to have this warning on, and there is no solution for your case. This is one of very few Level-4 warnings my company's development conventions allow to disable.
Perhaps your code needs more owls:
do { stuff(); } while (0,0)
Or the less photogenic but also less warning producing:
do { stuff(); } while ((void)0,0)
As Michael Burr noted in Carl Smotricz' answer, for Visual Studio 2008+ you can use __pragma:
#define MYMACRO(f,g) \
__pragma(warning(push)) \
__pragma(warning(disable:4127)) \
do { f; g; } while (0) \
__pragma(warning(pop))
You can put it on one line (without the \s) if you prefer macros to be unreadable.
I have a pattern that I based off an answer here & it works on clang, gcc & MSVC. I'm posting it here in the hopes that it'll be useful for others & because the answers here helped me formulate it.
#ifdef WIN32
# define ONCE __pragma( warning(push) ) \
__pragma( warning(disable:4127) ) \
while( 0 ) \
__pragma( warning(pop) )
#else
# define ONCE while( 0 )
#endif
And I use it like this:
do {
// Some stuff
} ONCE;
You can use this in macros too:
void SomeLogImpl( const char* filename, int line, ... );
#ifdef NDEBUG
# define LOG( ... )
#else
# define LOG( ... ) do { \
SomeLogImpl( __FILE__, __LINE__, __VA_ARGS__ ); \
} ONCE
#endif
This also works for the case pointed out above, if F uses 'ONCE' in a function:
#define F( x ) do { f(x); } ONCE
...
if (a==b) F(bar); else someFunc();
Edit: Years later, I realize I forgot to add the pattern I actually wrote this macro for - the "switch-like-a-goto" pattern:
do {
begin_some_operation();
if( something_is_wrong ) {
break;
}
continue_big_operation();
if( another_failure_cond ) {
break;
}
finish_big_operation();
return SUCCESS;
} ONCE;
cleanup_the_mess();
return FAILURE;
This gives you a try/finally-ish construct that's more structured than a crufty goto to your cleanup & return code. Using this ONCE macro instead of while(0) shuts VS up.
Using newer versions of the MS compiler, you can use warning suppression:
#define MY_MACRO(stuff) \
do { \
stuff \
__pragma(warning(suppress:4127)) \
} while(0)
You can also push/disable/pop, but suppress is a much more convenient mechanism.
This compiler bug was fixed in Visual Studio 2015 Update 1, even if the releases notes don't mention it.
The bug was explained in one of the previous answers though:
Summary: This warning (C4127) in this particular case is a subtle compiler bug. Feel free to disable it.
It was meant to catch situations when logical expression evaluates to a constant in non-obvious situations (such as, if(a==a && a!=a), and somehow, it turned while(true) and other useful constructs into invalid.
Here's another possible approach, which avoids C4127, C4548 and C6319 (VS2013 code analysis warning), and doesn't require macros or pragmas:
static const struct {
inline operator bool() const { return false; }
} false_value;
do {
// ...
} while (false_value);
This optimises away, and compiles without warnings in GCC 4.9.2 and VS2013. In practice it could go in a namespace.
The warning is due to the while(false). This site gives an example of how to workaround this problem. Example from site (you'll have to re-work it for your code):
#define MULTI_LINE_MACRO_BEGIN do {
#define MULTI_LINE_MACRO_END \
__pragma(warning(push)) \
__pragma(warning(disable:4127)) \
} while(0) \
__pragma(warning(pop))
#define MULTI_LINE_MACRO \
MULTI_LINE_MACRO_BEGIN \
std::printf("Hello "); \
std::printf("world!\n"); \
MULTI_LINE_MACRO_END
Just insert your code between the BEGIN and END.
You can use
do {
// Anything you like
} WHILE_FALSE;
And earlier define WHILE_FALSE macro as follows:
#define WHILE_FALSE \
__pragma(warning(push)) \
__pragma(warning(disable:4127)) \
while(false) \
__pragma(warning(pop))
Verified on MSVC++2013.
This "while(0)" stuff is a hack and has just turned around to bite you.
Does your compiler offer #pragmas for selectively and locally turning off specific error messages? If so, that might be a sensible alternative.
#define STUFF for (bool b = true; b;) do {f(); g(); b = false;} while (b)?
#define STUFF for (;;) {f(); g(); break;}?
You can use comma operator instead of do-while(0) construct for multi-statement macro to be used in expressions. So instead of:
#define FOO(...) do { Statement1; Statement2; Statement3; } while(0)
Use:
#define FOO(...) (Statement1, Statement2, Statement3)
This works independently from the platform and allows to avoid compiler warning (even if highest warning level is selected).
Note that in comma containing macro (second FOO) the result of the last statement (Statement3) would be the result of entire macro.
I found this to be the shortest version
do {
// ...
}
while (([]() { return 0; })()) /* workaround for MSVC warning C4172 : conditional expression is constant */
Haven't checked to see if it is optimized away by the compiler, but I would guess it is.
You could use for loop as:
for (;;) {
// code
break;
}
Macro:
#define BEGIN \
for (;;) {
#define END \
break; }
I must say, I've never bothered with the do..while construct in macros. All code in my macros is itself included in braces, but without the do-..while. For example:
#define F(x) \
{ \
x++; \
} \
int main() {
int a = 1;
F(a);
printf( "%d\n", a );
}
Also, my own coding standard (and informal practice for years) has been to make all blocks, wherever they occur be enclosed in braces, which also more or less removes the problem.
There is a solution but it will add more cycles to your code. Don't use explicit value in the while condition.
You can make it like this:
file1.h
extern const int I_am_a_zero;
#define MY_MACRO(foo,bar) \
do \
{ \
} \
while(I_am_a_zero);
the variable I_am_a_zero should be defined in some .c file.
Anyway this warning doesn't show up in GCC :)
See this related question.
You can use #pragma warning to:
save the state
disable the warning
write the offending code
return the warning to their previous state
(you need a # before the pragmas, but SO is having a hard time dealing with them and formatting at the same time)
#pragma warning( push )
#pragma warning( disable: 4127 )
// Your code
#pragma warning( pop )
You want to push/pop the warnings rather then disable/enable because you do not want to interfere with the command line arguments that might be chosen to turn warnings on/off (someone may use the command line to turn off the warning, you do not want to force it back on... the code above deals with that).
This is better than turning the warning off globally since you can control it just for the part you want. Also you can make it part of the macro.
Well, for me, the following works without the C4127 warning:
#define ALWAYS_TRUE(zzsome) ((##zzsome)==(##zzsome))
void foo()
{
int a = 0;
while( ALWAYS_TRUE(a) )
{
}
}
Ofcourse, compilers are smart and zzsome should not be a constant
This will disable the warning and compiler will still be able to optimize the code:
static inline bool to_bool(const bool v) { return v; }
if (to_bool(0)) { // no warning here
dead_code(); // will be compiled out (by most compilers)
}
do { something(); } while(to_bool(0)); // no extra code generated
I'd use
for(int i = 0; i < 1; ++i) //do once
{
}
This is equivalent to
do
{
}while(0);
and yields no warnings.
Please use compiler switch /wd"4127" to disable this warning in your project.