Suppressing warnings for a printf-like function in C++ - c++

I have a legacy logging printf-like function in C:
namespace legacy
{
void DoLog(const char* format,...);
}
If is only visible if a corresponding macro is defined (this is legacy too):
#ifdef LOG
# define Log legacy::DoLog
#else
# define Log /* Nothing */
#endif
I have some C++ code, which calls this log like:
Log("Logging started!");
When the LOG macro is not defined, Log("Something"); turns into ("Something"); which is unused code.
I need to suppress these warnings in GCC, and do it only once, of course, so I wrap Log into MyLog as #define MyLog Log and try this:
#define MyLog(...) \
_Pragma("GCC diagnostic push"); \
_Pragma("GCC diagnostic ignored \"-Wunused-value\""); \
Log(__VA_ARGS__); \
_Pragma("GCC diagnostic pop");
But these pragmas for some reason do not have any effecthttps://gcc.gnu.org/onlinedocs/cpp/Pragmas.htmlhttps://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html
I would better use inline C++ wrapper with templates for the perfect wrapping, but I cannot cope with it yet...
Any suggestions how to suppress these warnings?
Thank you in advance!

Use
#define Log(...)
and then Log("Logging started!"); expands to just ; instead of ("Logging started!");

I managed to come to the two following solutions:
C++ style inline function, with suppressed warnings and basic Windows and Linux platform definitions used:
template<typename... Args>
inline void MyLog(const char* format, Args... args)
{
#ifndef LOG
# ifdef _MSC_VER // Windows
# pragma warning(push)
# pragma warning(disable: 4548)
# elif defined(__GNUC__) // Linux
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-value"
# endif
#endif
Log(format, (args,...));
#ifndef LOG
# ifdef _MSC_VER // Windows
# pragma warning(pop)
# elif defined(__GNUC__) // Linux
# pragma GCC diagnostic pop
# endif
#endif
}
C style wrapper macro, even without any warnings suppression needed (thanks to #KamilCuk and #user253751):
#ifndef LOG
# define MyLog(...)
#else
# define MyLog(...) Log(__VA_ARGS__)
#endif

Related

Strange warning when using #define XX __pragma

I'm using the following preprocessor definitions to disable specific warnings for different c++ compilers.
Here's the code
#if defined(_MSC_VER)
#define DISABLE_WARNING_PUSH __pragma(warning(push))
#define DISABLE_WARNING_POP __pragma(warning(pop))
#define DISABLE_WARNING(warningNumber) __pragma(warning(disable : (warningNumber)))
#define DISABLE_WARNING_DEPRECATED_FUNCTION DISABLE_WARNING(4996)
#elif defined(__GNUC__) || defined(__clang__)
#define DO_PRAGMA(X) _Pragma(#X)
#define DISABLE_WARNING_PUSH DO_PRAGMA(GCC diagnostic push)
#define DISABLE_WARNING_POP DO_PRAGMA(GCC diagnostic pop)
#define DISABLE_WARNING(warningName) DO_PRAGMA(GCC diagnostic ignored #warningName)
#define DISABLE_WARNING_DEPRECATED_FUNCTION DISABLE_WARNING(-Wdeprecated-declarations)
#else
#define DISABLE_WARNING_PUSH
#define DISABLE_WARNING_POP
#define DISABLE_WARNING_DEPRECATED_FUNCTION
#endif
These defines works for GCC and CLANG but not for MSVC compiler.
On MSVC compiler I get the following warning:
(23): warning C4081: expected ')'; found '('
You can see it here: https://godbolt.org/z/hTErEbG7W
How can I fix this warning for MSVC compiler?

C++ Debug macro failing compile in release mode

I'm using visual studio (2019) and I have this macro:
#if _DEBUG
#define EngineLog(vars, ...) Log(vars, ##__VA_ARGS__)
#endif
My log function this wraps around is:
template<typename... args>
static void Log(args && ... inputs)
{
std::osyncstream bout(std::cout);
bout << ENGINE_TAG;
([&]() {
bout << inputs;
} (), ...);
bout << "\n";
}
Obviously this works fine when I'm in debug mode, but when I use release mode I get:
Error C3861 'EngineLog': identifier not found
I'm unsure why the compiler takes issue here, I was told it would remove the macro from the code when not defined but it seems not to be doing that.
if _DEBUG is not defined, then EngineLog is an unresolved name. You need to add a definition for the other case.
#if _DEBUG
#define EngineLog(vars, ...) Log(vars, ##__VA_ARGS__)
#else
#define EngineLog(vars, ...) (0 && Log(vars, ##__VA_ARGS__))
#endif
The syntax used here prevents any potential warnings about the variadic arguments being unused while at the same time preventing both the function from being called and its parameters being evaluated.
Looks like you need a #else preprocessor case to define out the macro call with an empty expansion:
#if _DEBUG
#define EngineLog(vars, ...) Log(vars, ##__VA_ARGS__)
#else
#define EngineLog(vars, ...)
#endif

How to avoid warning from nested deprecated function call?

I support a C++ library, and want to declare a number of legacy functions as deprecated. Unfortunately, these functions call one another, and I receive warnings from their compilation. For example:
[[deprecated]] void foo();
[[deprecated]] void bar() { foo(); }
I would like to avoid a warning about calling deprecated function from bar() body compilation, but still has that warning if some outside function (not marked as deprecated) calls foo() or bar(). Is it somehow possible?
While this does not work for OP's circumstance as posted, on account of bar() invoking foo() from within the library's header, there is a straightforward solution that is applicable to anyone facing the same issue without that specific constraint. So it could be useful to other people landing here.
Effectively, you want two different sets of headers. One when users of the library use it, and one when the library itself uses it. We can do this in this case because [[deprecated]] is not supposed to have any influence on the resulting generated code.
You "could" just maintain both of them separately, but that would obviously be very fragile. Thankfully, the language does provide us with a way to have two "versions" of the same header in one single file: The oft-maligned, and to be fair also oft-misused, Macro.
As a bonus, if [[deprecated]] happens to be what forces users to use C++14 or above, you can provide support for older versions of the standard at the same time by checking __cplusplus or the appropriate feature macro.
//mylib.h
#if !defined(MY_LIB_NO_DEPRECATE) && __has_cpp_attribute(deprecated)
#define MY_LIB_DEPRECATED [[deprecated]]
#else
#define MY_LIB_DEPRECATED
#endif
// ...
MY_LIB_DEPRECATED void foo();
MY_LIB_DEPRECATED void bar();
// ...
#undef MY_LIB_DEPRECATED
Compile the library with -DMY_LIB_NO_DEPRECATE, and it's like the deprecation warnings are not there for that specific phase of the process. Users will still get all the deprecation warnings, unless they explicitly opt out of them by also defining MY_LIB_NO_DEPRECATE.
Don't get spooked by the use of macros here. Using them to distinguish between internal/external versions of the same header is a common and well established practice. Windows dlls would be practically impossible to write without it.
In OP's case, if moving bar()'s definition from the header into the library's implementation is a possibility, then they should be good to go as well.
You can ignore the deprecation warnings. It's not technically portable, but it works on all 4 major compilers, at least:
#if defined(__GNUC__)
#define MY_LIB_IGNORE_DEPRECATED_BEGIN \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
#define MY_LIB_IGNORE_DEPRECATED_END \
_Pragma("GCC diagnostic pop")
#elif defined(_MSC_VER)
#define MY_LIB_IGNORE_DEPRECATED_BEGIN \
_Pragma("warning(push)") \
_Pragma("warning(disable : 4996)")
#define MY_LIB_IGNORE_DEPRECATED_END \
_Pragma("warning(pop)")
#else
#define MY_LIB_IGNORE_DEPRECATED_BEGIN
#define MY_LIB_IGNORE_DEPRECATED_END
#endif
You can do it library-wide:
MY_LIB_IGNORE_DEPRECATED_BEGIN
[[deprecated]] void foo();
[[deprecated]] void bar() { foo(); }
MY_LIB_IGNORE_DEPRECATED_END
Or you can guard just the offending calls:
[[deprecated]] void foo();
[[deprecated]] void bar()
{
MY_LIB_IGNORE_DEPRECATED_BEGIN
foo();
MY_LIB_IGNORE_DEPRECATED_END
}

pragma in `#define` macro to disable warnings

I'm trying to do something like this:
#ifdef _MSC_VER
#define DISABLE_WARNINGS() \
#pragma warning( push, 0 )
#elif __GNUC__
#define DISABLE_WARNINGS() \
#define DISABLE_WARNINGS \
#pragma GCC diagnostic push \
#pragma GCC diagnostic ignored "-Wall"
#endif
I would like to define a single macro such as "DISABLE_WARNINGS" in my code before including 3rd party headers that produce enormous amount of warnings on W4, and also ensure the code compiles on any platform.
For example:
DISABLE_WARNINGS
#include <gtkmm/buttonbox.h>
#include <gtkmm/box.h>
#include <gtkmm/window.h>
#include <gtkmm/button.h>
ENABLE_WARNINGS
What would be the best way to achieve this with single macro?
In C99 mode, you can use _Pragma instead of #pragma:
#define DISABLE_WARNINGS \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wall\"")

How can I use the TRACE macro in non-MFC projects?

I want to use the TRACE() macro to get output in the debug window in Visual Studio 2005 in a non-MFC C++ project, but which additional header or library is needed?
Is there a way of putting messages in the debug output window and how can I do that?
Build your own.
trace.cpp:
#ifdef _DEBUG
bool _trace(TCHAR *format, ...)
{
TCHAR buffer[1000];
va_list argptr;
va_start(argptr, format);
wvsprintf(buffer, format, argptr);
va_end(argptr);
OutputDebugString(buffer);
return true;
}
#endif
trace.h:
#include <windows.h>
#ifdef _DEBUG
bool _trace(TCHAR *format, ...);
#define TRACE _trace
#else
#define TRACE false && _trace
#endif
then just #include "trace.h" and you're all set.
Disclaimer: I just copy/pasted this code from a personal project and took out some project specific stuff, but there's no reason it shouldn't work. ;-)
If you use ATL you can try ATLTRACE.
TRACE is defined in afx.h as (at least in vs 2008):
// extern ATL::CTrace TRACE;
#define TRACE ATLTRACE
And ATLTRACE can be found in atltrace.h
You can try the DebugOutputString function. TRACE is only enabled in debug builds.
Thanks to these answers I have fixed my bug :-)
Here I share my TRACE macro in C++ based on ideas from Ferruccio and enthusiasticgeek.
#ifdef ENABLE_TRACE
# ifdef _MSC_VER
# include <windows.h>
# include <sstream>
# define TRACE(x) \
do { std::stringstream s; s << (x); \
OutputDebugString(s.str().c_str()); \
} while(0)
# else
# include <iostream>
# define TRACE(x) std::clog << (x)
# endif // or std::cerr << (x) << std::flush
#else
# define TRACE(x)
#endif
example:
#define ENABLE_TRACE //can depend on _DEBUG or NDEBUG macros
#include "my_above_trace_header.h"
int main (void)
{
int v1 = 123;
double v2 = 456.789;
TRACE ("main() v1="<< v1 <<" v2="<< v2 <<'\n');
}
Any improvements/suggestions/contributions are welcome ;-)
In my understanding wvsprintf has problem with formatting. Use _vsnprintf (or thcar version _vsntprintf ) instead
I've seen the following on the 'net:
#define TRACE printf
Developing this a little bit, came up with the following:
#ifdef _DEBUG
#define TRACE printf
#else
#define TRACE
#endif