using __FUNCSIG__ in a macro expands it to be empty - c++

I am using an API which return int error codes and I decided to build a wrapper error class :
class Error
{
...
public:
Error(int ErrC, const char* UserMessage, const char* FileName, int LineNumber, const char* Function);
char * GetFunction();
...
}
I decided to venture into the world of macros and create a macro to instantiate the class for me :
#define API_ERROR(Code,MSG) API::Error(Code,MSG,__FILE__,__LINE__,__FUNCSIG__)
I then defined a Test function that is called by main
void TestFunc()
{
API::Error Error = API_ERROR(0,"Hello");
std::cout << Error.GetFunction();
}
Using the compiler option to output the post pre-processing results (Properties->C/C++->Preprocessor->Preprocess to a file) yielded
void TestFunc()
{
API::Error Error = API::Error(o,"Hello","...\\main.cpp",30,);
std::cout << Error.GetFunction();
}
I think this does not work because __FUNCSIG__ is only defined inside functions.
I have also tried
#define EMPTY()
#define DEFER(...) __VA_ARGS__ EMPTY()
#define API_ERROR(Code,MSG) API::Error(Code,MSG,__FILE__,__LINE__,DEFER(__FUNCSIG__))
But I think I misunderstood the author of the post.
Is there a way to make this work ?
I am using Visual Studio 2019 Community with the default MSVC++ compiler.

From this VS2019 predefined macro reference
The __FUNCSIG__ macro isn't expanded if you use the /EP or /P compiler option.
[Emphasis mine]
If you preprocess your source then the /EP or /P flags would be set, and the macro won't be expanded. It will only be expanded when actually building your source.
The __FUNCSIG__ macro will probably not be expanded by the preprocessor because it doesn't really know anything about C++ symbols. It might not even be a true preprocessor macro, and could be "expanded" (or replaced) at a later stage in compilation when C++ symbols are known.

Related

Replace 'Define macro' with empty implementation

I usually use the #define macro to add code that will be here while compiling as debug time and not while compiling as release. For instance:
#ifdef NDEBUG
# define LOG(msg) (void)msg
#else
# define LOG(msg) MyDebugLogger(msg)
#endif
Instead of that, I was thinking of using plain function and, just not providing the body for the release method:
void MyDebugLogger(std::string const& msg);
In MyDebugLogger.cpp:
void MyDebugLogger(std::string const& msg)
{
#ifdef NDEBUG
std::clog << msg << "\n"; // Or whatever
#else
(void)msg;
#endif
}
I'm expecting that the compilers will have the power to strip out the call and add no extra cost in Release. Am I correct?
For some reason, could it be a bad practice?
EDIT: My question is: If I use macros as before, I know that in Release mode, the executable will be smaller and faster, as all the code has been removed.
If I use the function, will it be the same? As the compiler may understand that the function does nothing and is not necessary. (Or it will add an extra, even small, for calling an empty function)
practically you would do the same as with the macro:
void MyDebugLogger(std::string const& msg)
{
#ifdef NDEBUG
std::clog << msg << "\n"; // Or whatever
#endif
}
You'r example should work, with a little tweak. In your current version the compiler "sees" just the function signature and will emit a call to it's symbol, which will later be resolved via the linker, so it can't optimize it out on it's own. (Link Time Optimizations might help with that, but that depends very much on you'r setup and dynamic linking would make this impossible). So maybe try something like this
in the header:
// Assuming you are using clang or gcc,
// but is required to not give an error by the standard and probably
// not even needed.
[[gnu::always_inline]]
void MyDebugLogger(std::string const& msg [[maybe_unused]])
{
#ifdef NDEBUG
MyDebugLoggerImplementation(msg);
#endif
}
And then implement it in you .cpp file. Another benefit of this method is that you
method needs the Logger to be compiled with NDEBUG while this method gives the client code the choice.

Resharper C++ and Plog logger

I am using Plog in my project for logging. I also use resharper c++.
There are several macros used for logging that make it less verbose. One of the macros always gets marked as an issue with Resharper but I don't know why.
The macro is LOGD which expands to
if (!plog::get<0>() || !plog::get<0>()-
>checkSeverity(plog::debug)) {;} else (*plog::get<0>()) +=
plog::Record(plog::debug, __FUNCTION__, 151, "",
__if_exists(this) { this } __if_not_exists(this) { 0 }) <<
"Message";
The warning points to the usage of "this" as it expects an identifier.
The method it is calling has a signature of:
Record(Severity severity, const char* func, size_t line, const char* file, const void* object)
: m_severity(severity), m_tid(util::gettid()), m_object(object), m_line(line), m_func(func), m_file(file)
Does anyone have experience with this an know how to modify the macro so it does not complain?
I've filed RSCPP-22423, we'll try to fix this in one of the 2018.2 EAP builds. Until then, you can redefine the PLOG_GET_THIS macro for ReSharper C++ like this:
#include <plog/Log.h>
#if defined(__RESHARPER__)
#define PLOG_GET_THIS() reinterpret_cast<void*>(0)
#endif
Or similarly update the original definition of PLOG_GET_THIS (it already checks for the similar __INTELLISENSE__ macro to determine if __if_exists can be used).

Stringize __VA_ARGS__ (C++ variadic macros)

Let's have
class Item{
public:
Item(int id,const char *name,const char *props=NULL);
};
And I want to write:
ITEM(1,FIRST);
ITEM(2,SECOND, WithSomeProps);
With a macro
#define ITEM(ID,NAME,...) new Item(ID,NAME, #__VA_ARGS__ )
That #__VA_ARGS__ compiles well on gcc but gives an error on VStudio. Is there a solid and portable solution?
I want to have a collection of ITEM() in a .h file that will be included several times with different #definitions of ITEM.
GCC and Visual Studio handle Variadic Macros differently, because Macros are based on the compiler preprocessor (they are expanded at preprocessing time).
One of the difference is how they handle the empty variadic macros.
One of them will allow empty __VA_ARGS__ while the other will cause a compiler error if the __VA_ARGS__ is empty.
On your example the first the line ITEM(1,FIRST) will cause an error at compile time, while working ok on the other .
One workaround for this is to have an empty first argument, so your constructor will be something like :
Item(int id,const char *name,void *allwaysNull, const char *props=NULL);
And then have your Macro initialziations like this
ITEM(1,0,FIRST)
ITEM(2,0,SECOND,WithSomeProps)
What is weird is that from my experience it was GCC that was having problems with empty VA_ARGS for variadic macros...

C++ expected type specifier error

I am trying to write a wrapper function to figure out who is calling a specific function. So in .h file I added the following: (and implementation in the .cc file)
extern int foo(/*some arguments*/);
extern void call_log(const char*file,const char*function,const int line,const char*args);
#define foo(...) (call_log(__FILE__, __FUNCTION__, __LINE__, "" #__VA_ARGS__), foo(__VA_ARGS__))
However, I get the following error:
error: expected a type specifier
(call_log(__FILE__, __FUNCTION__, __LINE__, "" #__VA_ARGS__),foo(__VA_ARGS__)
Assume that the foo function is called with some parameters and returns an int.
the compiler is gcc 3.4
Thanks
EDIT
removed "." and extra spaced, yet problem still there. Can anyone see what can cause it. Also notice that I am using variadic macros -- supported by my compiler (c99)
Edit 2
Just to get the claims about my illegal use of some c/c++ constructs. The following code below works, and I am trying to adapt it to my current (above function)
#include <stdio.h>
int funcA( int a, int b ){ return a+b; }
// instrumentation
void call_log(const char*file,const char*function,const int line,const char*args){
printf("file:%s line: %i function: %s args: %s\n",file,line,function,args);
}
#define funcA(...) \
(call_log(__FILE__, __FUNCTION__, __LINE__, "" #__VA_ARGS__), funcA(__VA_ARGS__))
// testing
void funcB()
{
funcA(7,8);
}
int main(void){
int x = funcA(1,2)+
funcA(3,4);
printf( "x: %i (==10)\n", x );
funcA(5,6);
funcB();
}
Edit 3
As litb pointed out, the problem is, in fact, due to macro substitutions. I also noticed that foo is not only a function call but also used as ptr->foo[] in some cases. Any ides how to resolve this sort of issues, without breaking more code
The best way to find out what's wrong would be to make the compiler show the preprocessed code. You can then easier spot the problem in the offending line.
If I'm not mistaken I believe you have a number of syntax errors in the definition and declaration of call_log.
In the definition I am pretty sure you need a space between the const char* and the variable name. ie...
extern void call_log(const char* file,const char* function,const int line,const char* args);
In addition, in the declaration, I don't think you can append #__VA_ARGS__ to "" in the manner you are doing. The macro will resolved this as:
(call_log(file_name, function_name, line_#, "" arg1, arg2...), foo(args[])
which is not a valid function call. On a side-note you are also missing a semicolon after the macro definition.
Finally, I do not see a reference to foo(args) in your macro definition; It's possible I'm missing some context but you may wish to look at that as well.
Hope this helps...
CJ

How do I temporarily disable a macro expansion in C/C++?

For some reason I need to temporarily disable some macros in a header file and the #undef MACRONAME will make the code compile but it will undef the existing macro.
Is there a way of just disabling it?
I should mention that you do not really know the values of the macros and that I'm looking for a cross compiler solution (should work at least in GCC and MSVC).
In MSVC you could use push_macro pragma, GCC supports it for compatibility with Microsoft Windows compilers.
#pragma push_macro("MACRONAME")
#undef MACRONAME
// some actions
#pragma pop_macro("MACRONAME")
Using just the facilities defined by Standard C (C89, C99 or C11), the only 'disable' mechanism is #undef.
The problem is there is no 're-enable' mechanism.
As others have pointed out, if the header file containing the macro definitions is structured so that it does not contain any typedef or enum declarations (these cannot be repeated; function and variable declarations can be repeated), then you could #undef the macro, do what you need without the macro in effect, and then re-include the header, possibly after undefining its protection against reinclusion.
If the macros are not defined in a header, of course, you are stuck until you refactor the code so that they are in a header.
One other trick is available - if the macros are function-like macros and not object-like macros.
#define nonsense(a, b) b /\= a
int (nonsense)(int a, int b)
{
return (a > b) ? a : b;
}
The function nonsense() is defined fine, despite the macro immediately before it. This is because a macro invocation - for a function-like macro - must be immediately followed by an open parenthesis (give or take white space, possibly including comments). In the function definition line, the token after 'nonsense' is a close parenthesis, so it is not an invocation of the nonsense macro.
Had the macro been an argument-less object-like macro, the trick would not work:
#define nonsense min
int (nonsense)(int a, int b)
{
// Think about it - what is the function really called?
return (a > b) ? a : b;
}
This code defines a bogus function that's called min and is nonsensical. And there's no protection from the macro.
This is one of the reasons why the standard is careful to define which namespaces are reserved for 'The Implementation'. The Implementation is allowed to define macros for any purpose it desires or needs, of any type (function-like or object-like) it desires or needs, provided those names are reserved to the implementation. If you as a consumer of the services of The Implementation try to use or define a name reserved to the implementation, you must be aware that your code will probably break sooner or later, and that it will be your fault, not the fault of The Implementation.
Macros make my knees go weak, but wouldn't the most universal solution be to restructure your code so that you wouldn't need to reenable the macro again in the same source file? Wouldn't it be possible to extract some code into a separate function and a separate source file where you can undef the offending macro.
The macros come from some header file, so you should have access to their values. You can then do something like
#include <foo.h> // declares macro FOO
// Do things with FOO
#undef FOO
// do things without FOO
#include <foo.h> // reenable FOO
Your header should then be designed along these lines
#ifndef FOO
#define FOO do_something(x,y)
#endif
EDIT:
You may think that it's that easy:
#ifdef macro
#define DISABLED_macro macro
#undef macro
#endif
// do what you want with macro
#ifdef DISABLED_macro
#define macro DISABLED_macro
#endif
But it's not (like the following example demonstrates)!
#include <iostream>
#include <limits>
#include <windows.h>
#ifdef max
#define DISABLED_max max
#undef max
#endif
int main()
{
std::cout << std::numeric_limits<unsigned long>::max() << std::endl;
#ifdef DISABLED_max
#define max DISABLED_max
#endif
std::cout << max(15,3) << std::endl; // error C3861: "max": identifier not found
return 0;
}
Using #undef on the macro and re-including the original header is also not likely to work, because of the header guards.
So what's left is using the push_macro/pop_macro #pragma directives.
#pragma push_macro("MACRO")
#undef MACRO
// do what you want
#pragma pop_macro("MACRO")
There are specific rules for function-like macroses invokation in C/C++ language.
The function-like macroses have to be invoked in the following way:
Macros-name
Left parethesis
One token for each argument separated by commas
Each token in this list can be separared from another by whitespaces (i.e. actual whitespaces and commas)
With one trick you "disable preprocessor mechanism" with breaking rules for function-like macro invokation, but be still within a rules of function calling mechanism...
#include <iostream>
using namespace std;
inline const char* WHAT(){return "Hello from function";}
#define WHAT() "Hello from macro"
int main()
{
cout << (*WHAT)() << "\n"; // use function
cout << (WHAT)() << "\n"; // use function
cout << WHAT () << "\n"; // use macro
return 0;
}