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.
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.
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 have some code that needs Unicode strings for the most part, but I want to make it conditional (ie, TEXT("string") expanding to L"string" or "string", depending on settings). For these, I use the macro:
#ifdef _UNICODE
# define VSTR(str) L##str
#else
# define VSTR(str) str
#endif
The main complication with this is printf format strings, which use %s and %S for same-encoding and other-encoding strings, respectively. Some strings come from similarly conditional APIs (TCHAR and similar), while some come from set APIs (mostly C-string only). When using _tprintf and family, the function used can vary making %s and %S conditional as well, and they may need to be flipped around. To handle this, I defined macros to the appropriate format elements:
#ifdef _UNICODE
# define VPFCSTR(str) "%S"
# define VPFWSTR(str) "%s"
# define VPFTSTR(str) VPFWSTR(str)
#else
# define VPFCSTR(str) "%s"
# define VPFWSTR(str) "%S"
# define VPFTSTR(str) VPFCSTR(str)
#else
Now, this all works fine, but forces the syntax:
VSTR("Beginning of a format string, with a string '") VPFTSTR VSTR("' included.")
I would like to be able to use a syntax like:
VSTR("Beginning of a format string, with a string '", VPFTSTR, "' included.")
For Unicode, this needs to expand to:
L"Beginning of a format string, with a string '" L"%s" L"' included."
The only complication is the variable number of arguments, all of which need to be transformed in the same manner (one by one, if necessary).
My first idea was to use __VA_ARGS__ to handle this, using empty arguments, like:
VASTR(str, ...) VSTR(str) VASTR(__VA_ARGS__)
Unfortunately, as macros can't be used in their own definition, this fails. I then attempted a proxy:
VASTR2(...) VASTR(__VA_ARGS__)
VASTR(str, ...) VSTR(str) VASTR2(__VA_ARGS__)
The proxy method doesn't appear to work either.
Is there a way to handle running the same macro on each argument of a(nother) macro, which takes a variable number of arguments? Or, if not, is there an equivalent? If compiler-specific, MSVC10 is preferred, but anything is of interest.
Recursive macro expansion is not possible in C/C++.
Not sure, but C++0x allows you to omit encoding prefix for string literal concatenation. Thus you can try design your macro to prepend L only to the first string literal and use it as follows:
VSTR("Beginning of a format string, with a string '" VPFTSTR "' included.")
Please, correct me, if I'm wrong.
UPD.
A similar Unicode-related question: What happens with adjacent string literal concatenation when there is a modifier(L, u8, etc.)
Using the Boost.Preprocessor library, and these additional macros, you can apply your VSTR macro to each argument:
//Your VSTR macro for one argument
#define VSTR_EACH(str) ...
/**
* PP_NARGS returns the number of args in __VA_ARGS__
*/
#define PP_NARGS(...) \
PP_DETAIL_NARG((__VA_ARGS__,PP_DETAIL_RSEQ_N()))
#define PP_DETAIL_NARG(args) \
PP_DETAIL_ARG_N args
#define PP_DETAIL_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,N,...) N
#define PP_DETAIL_RSEQ_N() \
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
//Convert agruments list to a BOOST_PP_SEQ so we can iterate over it
//This is two macros in order to avoid the bug in MSVC compilers
#define DETAIL_PP_ARGS_TO_SEQ(size, tuple) BOOST_PP_TUPLE_TO_SEQ(size, tuple)
#define PP_ARGS_TO_SEQ(...) DETAIL_PP_ARGS_TO_SEQ(PP_NARGS(__VA_ARGS__), (__VA_ARGS__))
//The macro used inside of BOOST_PP_SEQ_FOR_EACH
#define VSTR_SEQ_EACH(t, data, x) VSTR_EACH(x)
#define VSTR(...) BOOST_PP_SEQ_FOR_EACH(VSTR_SEQ_EACH, ~, PP_ARGS_TO_SEQ(__VA_ARGS__))