I would like to turn on -Wdouble-promotion flag on my embedded project to avoid any accidental use of doubles. It was very useful however I can't fix my logger component because it uses __VA_ARGS__:
void log( const LogLevel _level, const char* const _file, const int _line, const char* const _format, ... )
{
va_list args;
va_start( args, _format );
Com< ILogger >()->Log( _level, _file, _line, _format, args );
va_end(args);
}
#define LOG_CRITICAL(...) log(LogLevel_Critical, __FILE__, __LINE__, __VA_ARGS__)
When I use stdarg.h or __VA_ARGS__ my floats are promoted into doubles (it is the standard behavior)...
base/logger.h, line 35, column 76: warning: implicit conversion from ‘float’ to ‘double’ when passing argument to function [-Wdouble-promotion]
#define LOG_WARN(...) log(LogLevel_Warning, __FILE__, __LINE__, __VA_ARGS__)
^
base/ntp.cpp, line 91, column 6: note: in expansion of macro ‘LOG_WARN’
LOG_WARN("System time is stepped by NTP daemon! (%f sec)", offset);
^~~~~~~~
It is an unfortunate situation, however it would be a really hard work to modify my logger component not to use printf in the background so I decided to suppress this error in this header:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdouble-promotion"
//(...) my logger component
#pragma GCC diagnostic pop
But it was unsuccessful because the warning is triggered when the compiler elaborates the #define LOG_CRITICAL(...) log(LogLevel_Critical, __FILE__, __LINE__, __VA_ARGS__) macro in the caller file.
How can I suppress the double-promotion warning of the variadic macro? GCC specific solutions are OK too.
Update 1:
I have checked alk's solution:
#define LOG_CRITICAL(...) \
_Pragma( "GCC diagnostic push" ) \
_Pragma( "GCC diagnostic ignored \"-Wdouble-promotion\"" ) \
log(LogLevel_Critical, __FILE__, __LINE__, __VA_ARGS__) \
_Pragma( "GCC diagnostic pop" )
After the modification there are many errors:
core/app_health.cpp, line 118, column 1: error: ‘#pragma’ is not allowed here
LOG_ERROR("[Main]");
I think this kind of pragma isn't allowed inside functions...
Related
When compiling I am getting the same warning on 3 different lines of code in a .h file such as this:
warning gnu_printf is an unrecognized format function type
My flags look like this:
CFLAGS += -Wall -Wextra -Wformat -Wno-ignored-qualifiers -Wformat-security -Wno-unused-parameter \
Examples of the three lines of code producing this error below:
int ATTR_WARN_PRINTF(1,2) OutputDebugStringF(const char* pszFormat, ...);
std::string ATTR_WARN_PRINTF(1,3) real_strprintf(const char *format, int dummy, ...);
bool ATTR_WARN_PRINTF(1,2) error(const char *format, ...);
I have many other uses of printf() in this file that are not producing any errors. I am a bit confused on the error in the formatting.
Apparently the failing code is:
#ifdef __GNUC__
#define ATTR_WARN_PRINTF(X,Y) __attribute__((format(gnu_printf,X,Y)))
#else
#define ATTR_WARN_PRINTF(X,Y)
#endif
int ATTR_WARN_PRINTF(1,2) OutputDebugStringF(const char* pszFormat, ...);
std::string ATTR_WARN_PRINTF(1,3) real_strprintf(const char *format, int dummy, ...);
bool ATTR_WARN_PRINTF(1,2) error(const char *format, ...);
It seems that this works on any gcc between versions 4.4.7 and gcc trunk (9.0.0).
GCC 4.1.2 fails with:
<source>:7: warning: 'gnu_printf' is an unrecognized format function type
Also, clang always fails on this:
<source>:7:5: warning: 'format' attribute argument not supported: gnu_printf [-Wignored-attributes]
But from the original question it seems that the issue with a GCC which is too old. To fix this, check GCC version number:
#if defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__>= 4) || __GNUC__ > 4)
# define ATTR_WARN_PRINTF(X,Y) __attribute__((format(gnu_printf,X,Y)))
#elif defined(__GNUC__)
# define ATTR_WARN_PRINTF(X,Y) __attribute__((format(printf,X,Y)))
#else
# define ATTR_WARN_PRINTF(X,Y)
#endif
Maybe even it is better to restrict the format to printf instead of gnu_printf, and so the above condition can be simplified.
EDIT: As can be found on GCC history, the gnu_printf format was added in gcc-4.4.0
commit r133365. From what I understand, it is merely an alias to printf, and the gnu prefix was added to allow differentiation between printf of different compilers, such as possibly ms_printf.
I have a warning in my code that is driving me crazy:
int vasprintf_wrapper(char** bufptr, const char* fmt, va_list ap)
{
// Do stuff...
// ...
return vasprintf(bufptr, fmt, ap);
}
Clang (3.6.0), complains with "format string is not a string literal", referring to the fmt argument that is being forwarded.
Naively, I tried to:
return vasprintf(bufptr, reinterpret_cast<const char[]>(fmt), ap);
Which of course doesn't compile.
What do I do? Disabling the warning altogether is not an option. I want to have the warning. But in this case, I would like to tell the compiler that I know what I'm doing ("famous last words" jokes aside...)
Indicate a parameter is a printf-style format using the __attribute__ flag. For example:
__attribute__((__format__ (__printf__, 2, 0)))
int vasprintf_wrapper(char** bufptr, const char* fmt, va_list ap)
{
...
}
The last parameter (0) disables checking for va_list.
From the documentation:
format (archetype, string-index, first-to-check)
The format attribute specifies that a function takes printf-, scanf-, strftime-, or strfmon-style arguments that should be type-checked against a format string.
The parameter archetype determines how the format string is interpreted.
The parameter string-index specifies which argument is the format string argument (starting from 1).
The parameter first-to-check is the number of the first argument to check against the format string. For functions where the arguments are not available to be checked (such as vprintf), specify the third parameter as zero.
See also:
http://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
http://clang.llvm.org/docs/AttributeReference.html#format
The warning flag that enables this type of warning is -Wformat-nonliteral. Since you don't want to turn that warning off completely, you can locally disable this warning using the following code:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-nonliteral"
...
#pragma clang diagnostic pop
So your function would look like this:
int vasprintf_wrapper(char** bufptr, const char* fmt, va_list ap)
{
// Do stuff...
// ...
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-nonliteral"
return vasprintf(bufptr, fmt, ap);
#pragma clang diagnostic pop
}
I'm trying to build the following code in Eclipse CDT on Linux with GNU:
log_defs.h
#pragma once
#define dbg_log(fmt, ...) debug_logger::debug(__FILE__, __FUNCTION__, __LINE__, fmt, __VA_ARGS__, 0)
ErrorMessage.cpp
ErrorMessage::ErrorMessage( void ){ dbg_log( L"ErrorMessage::ErrorMessage _in" ); }
ErrorMessage::~ErrorMessage( void ){ dbg_log( L"ErrorMessage::~ErrorMessage _in" ); }
I'm getting the following errors:
../sources/ErrorMessage.cpp: In constructor ‘ErrorMessage::ErrorMessage()’:
/include/log_defs.h:27:97: error: expected primary-expression before ‘,’ token
#define dbg_log(fmt, ...) debug_logger::debug(__FILE__, __FUNCTION__, __LINE__, fmt, __VA_ARGS__, 0)
^
../sources/ErrorMessage.cpp:150:37: note: in expansion of macro ‘dbg_log’
ErrorMessage::ErrorMessage( void ){ dbg_log( L"ErrorMessage::ErrorMessage _in" ); }
^
../sources/ErrorMessage.cpp: In destructor ‘ErrorMessage::~ErrorMessage()’:
/include/log_defs.h:27:97: error: expected primary-expression before ‘,’ token
#define dbg_log(fmt, ...) debug_logger::debug(__FILE__, __FUNCTION__, __LINE__, fmt, __VA_ARGS__, 0)
^
../sources/ErrorMessage.cpp:152:38: note: in expansion of macro ‘dbg_log’
ErrorMessage::~ErrorMessage( void ){ dbg_log( L"ErrorMessage::~ErrorMessage _in" ); }
The reason is that when you don't pass any additional arguments to the macro, __VA_ARGS__ expands to nothing. You therefore end up with the following code like this after macro expansion:
debug_logger::debug("SomeFile", "SomeFunction", 42, L"TheFormatString", , 0)
If the code you've posted faithfully captures your real scenario, the way out is easy: subsume fmt into the variadic part:
#define dbg_log(...) debug_logger::debug(__FILE__, __FUNCTION__, __LINE__, __VA_ARGS__, 0)
That way, you'll always pass at least one argument (the fmt string) to the macro, and the commas will work out nicely.
I have the following function that I shouldn't change to not break dependencies
void Trace(
__in DbgInfo dbgInfo,
__in_z _Printf_format_string_ const WCHAR* pwszMsgFormat,
...) {
// some code I need
};
I need it to call a function that also has ... args:
#define TRACE_LINE( format, ... ) _TRACE( LogLevelInfo ,format, __VA_ARGS__ )
#define _TRACE( mask, format, ... ) \
((mask) & g_LogLevel) \
? TraceGlobal::TraceLine( mask, L"[" __FILEW__ L":" _BLOB_WIDE(_BLOB_STRINGIZE(__LINE__)) L"] " L"MyService!" __FUNCTIONW__ L": " format , __VA_ARGS__ ) \
: (void)0
void
ServiceTracing::TraceGlobal::TraceLine(
_In_ LogLevel level,
_In_z_ PCWSTR format,
_In_ ...)
/**
Routine Description:
Trace a formatted line with Level tracing
Arguments:
level: enum level of trace line
format: the string format
...: the variable arguments to be formatted
Return value:
None
**/
{
ASSERT(format);
va_list args;
va_start(args, format);
// code does tracing
va_end(args);
}
how can I do that?
Inside the main Trace function above I tried this:
TRACE_LINE( pwszMsgFormat, __VA_ARGS__ );
this didn't work however and I got error:
syntax error : missing ')' before identifier 'pwszMsgFormat'
error C2059: syntax error : ')'
I am assuming because it is macro the __VA_ARGS__ it gives this error.
On the other hand I tried calling the TraceGlobal directly
va_list args;
va_start(args, pwszMsgFormat);
TraceGlobal::TraceLine(LogLevelInfo, pwszMsgFormat , args );
va_end(args);
this builds fine but I get Segmentation Fault / Access Violation in the tracing function because I also initialize va_list and use va_start in TraceLine
Is there a simple way I can just pass along the variable arguments from function to another. I don't want to change Trace function to Macro.
GCC version ntoarm-gcc (GCC) 4.4.2
I've added 'printf' format attributes to all my functions that wrap printf() and co. They work perfectly fine except when calling the functions using a variadic macro.
class Log { [...]
void log_fmt(LogLevel level, const std::string& funcName, const char_t * const logFormatStr, ...) __attribute__ ((format (printf, 4, 5)));
[...] };
An incorrect direct call like
log.log_fmt(Info, "test", "wrong %u", "type");
yields warning:
format '%u' expects type 'unsigned int', but argument 5 has type 'const char*'
The same incorrect call using a macro yields no warning, however:
#define LOGI(MSG, ...) log.log_fmt(Info, __func__, (MSG), __VA_ARGS__)
LOGI("wrong %u", "type");
Can I get the warnings to show up in this case too? Have I made a mistake or is this intended behaviour?
This:
#include <iostream>
#include <cstdio>
struct log {
static void logf(std::string, std::string, const char*, ...) __attribute__((format (printf, 3, 4))) {}
};
#define L(m, ...) log::logf("no", __func__, (m), __VA_ARGS__)
int main() {
//log::logf("hi", "hi", "test %u", "hi");
L("test %u", "hi");
}
works perfectly, in the sense that it gives the correct warning, like below:
main.cpp: In function 'int main()':
main.cpp:8:61: warning: format '%u' expects argument of type 'unsigned int', but argument 4 has type 'const char*' [-Wformat=]
#define L(m, ...) log::logf("no", __func__, (m), __VA_ARGS__)
^
main.cpp:12:5: note: in expansion of macro 'L'
L("test %u", "hi");
^
At global scope:
cc1plus: warning: unrecognized command line option "-Wno-undefined-internal" [enabled by default]
So, I would guess that the problem is on the position parameters (you have put 4, 5 on your format attribute, when it seems that you should have put 3, 4)....