Issue with nested #define for defining a function with variadic arguments - c++

How can I define a nested #define into a macro with variadic arguments
#ifndef MY_PRINTF
#define MY_PRINTF(f_, ...) { \
#ifdef USE_WRITE_DEBUG_INFO \
char buff[200]; \
sprintf(buff, (f_), __VA_ARGS__); \
WriteDebugInfo(buff); \
#else \
printf((f_), __VA_ARGS__); \
#endif \
}
#endif
Visual studio complains about missing directives. I'd appreciate for any hint.

You can't use preprocessor directives while defining a #define. This means that your #ifdef USE_WRITE_DEBUG_INFO won't work.
For this case, use a function rather than a macro:
#include <cstdarg>
void my_printf(const char* format, ...) {
#ifdef USE_WRITE_DEBUG_INFO
char buff[200];
va_list args;
va_start(args, format);
// Note: uses the snprintf variant rather than sprintf variant,
// avoiding buffer overlows.
vsnprintf(buff, 200, format, args);
va_end(args);
WriteDebugInfo(buff);
#else
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
#endif
}
In general, you'd have to bring the preprocessor directives outside of the #define:
#ifndef MY_PRINTF
#ifdef USE_WRITE_DEBUG_INFO
// do { ... } while (false) makes the macro behave mostly like a regular function call.
#define MY_PRINTF(f_, ...) do { \
char buff[200]; \
sprintf(buff, (f_), __VA_ARGS__); \
WriteDebugInfo(buff); \
} while (false)
#else
#define MY_PRINTF(f_, ...) printf((f_), __VA_ARGS__)
#endif
#endif

Related

Replacing __LINE__ and __FUNCSIG__ with the new std::source_location in a macro

C++20 added std::source_location as a replacement for the debugging macros __LINE__, __FILE__, etc.
This is great. I have a macro that builds up a variable declaration in order to log and profile a block of code using said macros:
#define TOKEN_PASTE_SIMPLE(x, y) x##y
#define TOKEN_PASTE(x, y) TOKEN_PASTE_SIMPLE(x, y)
#define TOKEN_STRINGIZE_SIMPLE(x) #x
#define TOKEN_STRINGIZE(x) TOKEN_STRINGIZE_SIMPLE(x)
//...
#if defined PROFILE_LOG_SCOPE || defined PROFILE_LOG_SCOPE_FUNCTION
#undef PROFILE_LOG_SCOPE
#undef PROFILE_LOG_SCOPE_FUNCTION
#endif
#ifdef PROFILE_BUILD
#define PROFILE_LOG_SCOPE(tag_str) ProfileLogScope TOKEN_PASTE(plscope_, __LINE__)(tag_str)
#define PROFILE_LOG_SCOPE_FUNCTION() PROFILE_LOG_SCOPE(__FUNCSIG__)
#else
#define PROFILE_LOG_SCOPE(tag_str)
#define PROFILE_LOG_SCOPE_FUNCTION()
#endif
However, replacing the macros with the source_location version breaks because the function calls are not evaluated before the macro expansion.
#define TOKEN_PASTE_SIMPLE(x, y) x##y
#define TOKEN_PASTE(x, y) TOKEN_PASTE_SIMPLE(x, y)
#define TOKEN_STRINGIZE_SIMPLE(x) #x
#define TOKEN_STRINGIZE(x) TOKEN_STRINGIZE_SIMPLE(x)
//...
//TODO: Replace __LINE__ with std::source_location::line
//TODO: Replace __FUNCSIG__ with std::source_location::function_name
#if defined PROFILE_LOG_SCOPE || defined PROFILE_LOG_SCOPE_FUNCTION
#undef PROFILE_LOG_SCOPE
#undef PROFILE_LOG_SCOPE_FUNCTION
#endif
#ifdef PROFILE_BUILD
#define PROFILE_LOG_SCOPE(tag_str) ProfileLogScope TOKEN_PASTE(plscope_, std::source_location::current().line())(tag_str)
#define PROFILE_LOG_SCOPE_FUNCTION() PROFILE_LOG_SCOPE(std::source_location::current().function_name())
#else
#define PROFILE_LOG_SCOPE(tag_str)
#define PROFILE_LOG_SCOPE_FUNCTION()
#endif
QUESTION
How would I get the above to work?
I ultimately went with a hybrid approach. That is, Use __LINE__ to generate the variable name and pass in std::source_location::current() as a default parameter:
//...
class ProfileLogScope {
public:
explicit ProfileLogScope(const char* scopeName = nullptr, std::source_location location = std::source_location::current()) noexcept;
//...
};
ProfileLogScope::ProfileLogScope(const char* scopeName, std::source_location location) noexcept
: m_scope_name(scopeName)
, m_time_at_creation(TimeUtils::Now())
, m_location(location)
{
/* DO NOTHING */
}
ProfileLogScope::~ProfileLogScope() noexcept {
const auto now = TimeUtils::Now();
TimeUtils::FPMilliseconds elapsedTime = (now - m_time_at_creation);
DebuggerPrintf(std::format("ProfileLogScope {} in file {} on line {} took {:.2f} milliseconds.\n", m_scope_name != nullptr ? m_scope_name : m_location.function_name(), m_location.file_name(), m_location.line(), elapsedTime.count()));
}
//...
#define TOKEN_PASTE_SIMPLE(x, y) x##y
#define TOKEN_PASTE(x, y) TOKEN_PASTE_SIMPLE(x, y)
#define TOKEN_STRINGIZE_SIMPLE(x) #x
#define TOKEN_STRINGIZE(x) TOKEN_STRINGIZE_SIMPLE(x)
//...
#if defined PROFILE_LOG_SCOPE || defined PROFILE_LOG_SCOPE_FUNCTION
#undef PROFILE_LOG_SCOPE
#undef PROFILE_LOG_SCOPE_FUNCTION
#endif
#ifdef PROFILE_BUILD
#define PROFILE_LOG_SCOPE(tag_str) auto TOKEN_PASTE(plscope_, __LINE__) = ProfileLogScope{tag_str}
#define PROFILE_LOG_SCOPE_FUNCTION() auto TOKEN_PASTE(plscope_, __LINE__) = ProfileLogScope{nullptr}
#else
#define PROFILE_LOG_SCOPE(tag_str)
#define PROFILE_LOG_SCOPE_FUNCTION()
#endif

How can I compose translation units in C? [duplicate]

I was wondering if it's possible to use C constructors in VC just as it is possible to use them in GCC.
The gcc way is quite straight using the __attribute__ keyword, unfortunately VC doesn't seem to even know this keyword, as I'm not a Win32 programmer I wonder if there's some sort of equivalent keyword for such things.
Just to note - this is a C program, not a C++ or C# even, (as 'twas quite easy to do that in those languages)
Below C code demonstrates how to define a void(void) function to be called at program/library load time, before main executes.
For MSVC, this places a pointer to the function in the user initializer section (.CRT$XCU), basically the same thing the compiler does for the constructor calls for static C++ objects. For GCC, uses a constructor attribute.
// Initializer/finalizer sample for MSVC and GCC/Clang.
// 2010-2016 Joe Lowe. Released into the public domain.
#include <stdio.h>
#include <stdlib.h>
#ifdef __cplusplus
#define INITIALIZER(f) \
static void f(void); \
struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \
static void f(void)
#elif defined(_MSC_VER)
#pragma section(".CRT$XCU",read)
#define INITIALIZER2_(f,p) \
static void f(void); \
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
__pragma(comment(linker,"/include:" p #f "_")) \
static void f(void)
#ifdef _WIN64
#define INITIALIZER(f) INITIALIZER2_(f,"")
#else
#define INITIALIZER(f) INITIALIZER2_(f,"_")
#endif
#else
#define INITIALIZER(f) \
static void f(void) __attribute__((constructor)); \
static void f(void)
#endif
static void finalize(void)
{
printf( "finalize\n");
}
INITIALIZER( initialize)
{
printf( "initialize\n");
atexit( finalize);
}
int main( int argc, char** argv)
{
printf( "main\n");
return 0;
}
You are probably interested in DllMain.
I don't think there's a way to avoid using C++ features with MSVC. (MSVC's C support sucks anyways.)
Untested, but this should at least allow the same code to work in both MSVC and GCC.
#if defined(_MSC_VER)
struct construct { construct(void (*f)(void)) { f(); } };
#define constructor(fn) \
void fn(void); static constructor constructor_##fn(fn)
#elif defined(__GNUC__)
#define constructor(fn)
void fn(void) __attribute__((constructor))
#endif
static constructor(foo);
void foo() {
...
}
I tried the last answer in MSVC like
#ifdef _MSC_VER
#pragma section(".CRT$XCU",read)
#define INITIALIZER2_(f,p) \
static void f(void); \
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
__pragma(comment(linker,"/include:" p #f "_")) \
static void f(void)
#ifdef _WIN64
#define INITIALIZER(f) INITIALIZER2_(f,"")
#else
#define INITIALIZER(f) INITIALIZER2_(f,"_")
#endif
#else
#define INITIALIZER(f) \
static void f(void) __attribute__((constructor)); \
static void f(void)
#endif
but INITIALIZER(f) can't appear in 2 different files with the same function name passed to INITIALIZER, the following definition will allow that
#ifdef _MSC_VER
#define INITIALIZER(f) \
static void f();\
static int __f1(){f();return 0;}\
__pragma(data_seg(".CRT$XIU"))\
static int(*__f2) () = __f1;\
__pragma(data_seg())\
static void f()
#else
#define INITIALIZER(f) \
__attribute__((constructor)) static void f()
#endif

MSVC equivalent for: void __attribute__((constructor)) [duplicate]

I was wondering if it's possible to use C constructors in VC just as it is possible to use them in GCC.
The gcc way is quite straight using the __attribute__ keyword, unfortunately VC doesn't seem to even know this keyword, as I'm not a Win32 programmer I wonder if there's some sort of equivalent keyword for such things.
Just to note - this is a C program, not a C++ or C# even, (as 'twas quite easy to do that in those languages)
Below C code demonstrates how to define a void(void) function to be called at program/library load time, before main executes.
For MSVC, this places a pointer to the function in the user initializer section (.CRT$XCU), basically the same thing the compiler does for the constructor calls for static C++ objects. For GCC, uses a constructor attribute.
// Initializer/finalizer sample for MSVC and GCC/Clang.
// 2010-2016 Joe Lowe. Released into the public domain.
#include <stdio.h>
#include <stdlib.h>
#ifdef __cplusplus
#define INITIALIZER(f) \
static void f(void); \
struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \
static void f(void)
#elif defined(_MSC_VER)
#pragma section(".CRT$XCU",read)
#define INITIALIZER2_(f,p) \
static void f(void); \
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
__pragma(comment(linker,"/include:" p #f "_")) \
static void f(void)
#ifdef _WIN64
#define INITIALIZER(f) INITIALIZER2_(f,"")
#else
#define INITIALIZER(f) INITIALIZER2_(f,"_")
#endif
#else
#define INITIALIZER(f) \
static void f(void) __attribute__((constructor)); \
static void f(void)
#endif
static void finalize(void)
{
printf( "finalize\n");
}
INITIALIZER( initialize)
{
printf( "initialize\n");
atexit( finalize);
}
int main( int argc, char** argv)
{
printf( "main\n");
return 0;
}
You are probably interested in DllMain.
I don't think there's a way to avoid using C++ features with MSVC. (MSVC's C support sucks anyways.)
Untested, but this should at least allow the same code to work in both MSVC and GCC.
#if defined(_MSC_VER)
struct construct { construct(void (*f)(void)) { f(); } };
#define constructor(fn) \
void fn(void); static constructor constructor_##fn(fn)
#elif defined(__GNUC__)
#define constructor(fn)
void fn(void) __attribute__((constructor))
#endif
static constructor(foo);
void foo() {
...
}
I tried the last answer in MSVC like
#ifdef _MSC_VER
#pragma section(".CRT$XCU",read)
#define INITIALIZER2_(f,p) \
static void f(void); \
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
__pragma(comment(linker,"/include:" p #f "_")) \
static void f(void)
#ifdef _WIN64
#define INITIALIZER(f) INITIALIZER2_(f,"")
#else
#define INITIALIZER(f) INITIALIZER2_(f,"_")
#endif
#else
#define INITIALIZER(f) \
static void f(void) __attribute__((constructor)); \
static void f(void)
#endif
but INITIALIZER(f) can't appear in 2 different files with the same function name passed to INITIALIZER, the following definition will allow that
#ifdef _MSC_VER
#define INITIALIZER(f) \
static void f();\
static int __f1(){f();return 0;}\
__pragma(data_seg(".CRT$XIU"))\
static int(*__f2) () = __f1;\
__pragma(data_seg())\
static void f()
#else
#define INITIALIZER(f) \
__attribute__((constructor)) static void f()
#endif

C++ Pass Boost::log severity level as argument to function

I want to have only one function to write logs which would parse ellipsis and send result to the Boost::log, based on severity level. In header file would be defined different macros, which would select a correct severity level. There is the code:
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#define DEBUG(msg, ...) Logger::write_log(debug, msg, ##__VA_ARGS__);
#define INFO(msg, ...) Logger::write_log(info, msg, ##__VA_ARGS__);
#define WARNING(msg, ...) Logger::write_log(warning, msg, ##__VA_ARGS__);
#define ERROR(msg, ...) Logger::write_log(error, msg, ##__VA_ARGS__);
namespace logging = boost::log;
void write_log(auto level, const char *message, ...)
{
char buffer[512];
va_list args;
// Parse ellipsis and add arguments to message
va_start (args, message);
vsnprintf (buffer, sizeof(buffer), message, args);
va_end (args);
BOOST_LOG_TRIVIAL(level) << buffer;
}
int main(int argc, char** argv)
{
DEBUG("Test string %s", "additional string");
return 0;
}
But during compilation I get the next error:
error: 'level' is not a member of 'boost::log::v2s_mt_nt5::trivial'
BOOST_LOG_TRIVIAL(level) << buffer;
Seems that my level argument have an incorrect type. I also tried to use logging::trivial::severity_level level instead of auto level, but this didn't help. How can I fix this error?
UPDATED:
there is working solution:
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#define DEBUG(msg, ...) Logger::write_log(debug, msg, ##__VA_ARGS__);
#define INFO(msg, ...) Logger::write_log(info, msg, ##__VA_ARGS__);
#define WARNING(msg, ...) Logger::write_log(warning, msg, ##__VA_ARGS__);
#define ERROR(msg, ...) Logger::write_log(error, msg, ##__VA_ARGS__);
namespace logging = boost::log;
enum severity_level
{
debug,
info,
warning,
error,
exception
};
src::severity_logger<severity_level> slg;
void write_log(severity_level level, const char *message, ...)
{
char buffer[512];
va_list args;
// Parse ellipsis and add arguments to message
va_start (args, message);
vsnprintf (buffer, sizeof(buffer), message, args);
va_end (args);
BOOST_LOG_SEV(slg, level) << buffer;
}
int main(int argc, char** argv)
{
DEBUG("Test string %s", "additional string");
return 0;
}
Follow boost log example and define:
// severity levels
enum severity_level
{
trace,
debug,
info,
warning,
error,
fatal
};
And you need to make your function to accept proper type:
void write_log(severity_level level, const char *message, ...){ ... }
Another option:
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#define DEBUG(msg, ...) Logger::write_log(logging::trivial::debug, msg, ##__VA_ARGS__);
#define INFO(msg, ...) Logger::write_log(logging::trivial::info, msg, ##__VA_ARGS__);
#define WARNING(msg, ...) Logger::write_log(logging::trivial::warning, msg, ##__VA_ARGS__);
#define ERROR(msg, ...) Logger::write_log(logging::trivial::error, msg, ##__VA_ARGS__);
namespace logging = boost::log;
#define LOG_TRIVIAL(lvl)\
BOOST_LOG_STREAM_WITH_PARAMS(::boost::log::trivial::logger::get(),\
(::boost::log::keywords::severity = lvl))
void write_log(logging::trivial::severity_level level, const char *message, ...)
{
char buffer[512];
va_list args;
// Parse ellipsis and add arguments to message
va_start(args, message);
vsnprintf(buffer, sizeof(buffer), message, args);
va_end(args);
LOG_TRIVIAL(level) << buffer;
}
int main(int argc, char** argv)
{
DEBUG("Test string %s", "additional string");
return 0;
}
My advice: create your own severity. It's just an enum! Follow the source code of that "level" (using your IDE) to see that it's a simple enum. Copy it to your implementation, and change it as necessary. This is how it looks (after changing its name):
enum my_severity_level
{
trace,
debug,
info,
warning,
error,
fatal
};
Take that to your code, and use it as necessary.
That write_log function should be like this:
void write_log(my_severity_level level, const char *message, ...) { ... }

C #define nested in #ifdef [duplicate]

This question already has answers here:
#ifdef inside #define
(6 answers)
Closed 9 years ago.
For some reason I need to define some nested definition. but the pre-processor
remove a part of my macro.
Look at following code:
#define SINGLE_ITERATION y+=xext[++xIndex]*H[hCounter--];
#define LOOP_ITERATION SINGLE_ITERATION \
SINGLE_ITERATION SINGLE_ITERATION \
SINGLE_ITERATION SINGLE_ITERATION \
SINGLE_ITERATION SINGLE_ITERATION \
SINGLE_ITERATION
#define DEBUG_CODE #ifdef MEMORIZE \
myOutput[xCounter]=y; \
#endif \
#ifdef STORING \
fprintf(fid,"%f\r\n",y); \
#endif
#define OUT_LOP_ITERATION y=0; \
xIndex=xCounter-HL;\
for(hCounter=HL_MINUS_1;hCounter>0;)
{LOOP_ITERATION} \
SINGLE_ITERATION
But the problem is when the MEMORIZE flag is defined. Here is the output of pre-processor created by compiler
for( xCounter=XL_MINUS_1;xCounter>=0;xCounter--)
{
y=0;
xIndex=xCounter-HL;
for(hCounter=HL_MINUS_1;hCounter>0;)
{
y+=xext[++xIndex]*H[hCounter--];
y+=xext[++xIndex]*H[hCounter--];
y+=xext[++xIndex]*H[hCounter--];
y+=xext[++xIndex]*H[hCounter--];
y+=xext[++xIndex]*H[hCounter--];
y+=xext[++xIndex]*H[hCounter--];
y+=xext[++xIndex]*H[hCounter--];
y+=xext[++xIndex]*H[hCounter--];
}
y+=xext[++xIndex]*H[hCounter--];
#ifdef
myOutput[xCounter]=y;
#endif
#ifdef STORING
fprintf(fid,"%f\r\n",y);
#endif
}
which has a problem in the last part.in the :
#ifdef
myOutput[xCounter]=y;
#endif
#ifdef STORING
fprintf(fid,"%f\r\n",y);
#endif
}
which must be
#ifdef MEMORIZE
myOutput[xCounter]=y;
#endif
#ifdef STORING
fprintf(fid,"%f\r\n",y);
#endif
}
and the pre-processor omitted the MEMORIZE because it is defined currently.
Please help me to solve it.
You probably wanted:
#ifdef MEMORIZE
#define DEBUG_CODE myOutput[xCounter]=y;
#endif
#ifdef STORING
#define DEBUG_CODE fprintf(fid,"%f\r\n",y);
#endif
You may try this:
#if defined(MEMORIZE) && defined(STORING)
#define DEBUG_CODE myOutput[xCounter]=y;\
fprintf(fid,"%f\r\n",y);
#elif defined(MEMORIZE)
#define DEBUG_CODE myOutput[xCounter]=y;
#elif defined(STORING)
#define DEBUG_CODE fprintf(fid,"%f\r\n",y);
#else
#define DEBUG_CODE
#endif