log C++ class method callers (function name, line number) - c++

I have a class in my C++ code similar to the following:
class myClass
{
public:
void method1(int a, int b, std::string str);
};
Other classes can instantiate an object from myClass and call method1.
void caller()
{
obj1->method1(12, 4, "sample");
}
I want to log all the callers of myClass (function name, file name, line number). One possible solution is this:
class myClass
{
public:
method1(int a, int b, std::string str, const char *_function = __builtin_FUNCTION(), const char *_file = __builtin_FILE(), int _line = __builtin_LINE());
};
which is using __builtin_xxx as default arguments. This solution has multiple shortcomings:
It is an ugly solution
__builtin_xxx is only available in gcc version > 4.8
We have to add three default parameters to method1
IDE shows the default parameters on auto-completion that are not meant to be provided by the user!
Another solution is using __LINE__, __FILE__ and __func__ that is basically very similar to the previous solution. They are not defined outside of function scope, and they should be used like this:
void caller()
{
obj1->method1(12, 4, "sample", __func__, __FILE__, __LINE__);
}
Here is a working example for both solutions.
Is there any better solution to log the caller when the user calls method1 on myClass object. By a better solution I specifically mean not to change the method1's declaration by adding three more parameters!

Another ugly solution, but I'm using...
Use macros to automatically add __LINE__ __FILE__ ...etc. things into parameters.
For example
#define Method(param0,param1) Method(param0,param1,__LINE__)
It has a lot of problem, if you want macros work as normal function, you has to do a lot of things, and it still may not works.
I use it to help me log errors.

Looks like a duplicate of Print the file name, line number and function name of a calling function - C Prog
I'd pass the data to the function through parameters (maybe get the help of a macro)
int info(const char *fname, int lineno, const char *fxname, ...) { /* ... */ }
int debug(const char *fname, int lineno, const char *fxname, ...) { /* ... */ }
int error(const char *fname, int lineno, const char *fxname, ...) { /* ... */ }
And to call them
info(__FILE__, __LINE__, __func__, ...);
debug(__FILE__, __LINE__, __func__, ...);
error(__FILE__, __LINE__, __func__, ...);
Note: __func__ is C99; gcc, in mode C89 has __FUNCTION__

Related

Overloading C Preprocessor Macros - Discimination Based on Call Syntax

I'm currently working on a cpp logger which aims at displaying the __FILE__ and the __LINE__ before each printed message. In my case, we are mostly using 2 methods for printing out: printf-style and std::cout-style. For the moment I have a macros for each style:
#define HATFormatFatal(...) HATLogger::logFormat(HATLogger::LogLevel::FATAL, __FILE__, __LINE__, __VA_ARGS__)
#define HATFormatError(...) HATLogger::logFormat(HATLogger::LogLevel::ERROR, __FILE__, __LINE__, __VA_ARGS__)
etc... and:
#define HATStreamFatal HATLogger::logStream(HATLogger::LogLevel::FATAL, __FILE__, __LINE__)
#define HATStreamError HATLogger::logStream(HATLogger::LogLevel::ERROR, __FILE__, __LINE__)
These macros can be called in the following:
HATFormatError("This is an %s message", "ERROR");
HATStreamError << "This is an " << "ERROR" << " message" << std::endl;
I would like to call them with the same name: HATLogError. The right macro would be determine at compilation while looking for parenthesis. So far I've seen some examples showing how it is possible to discriminate the macros by the number of arguments, but nothing that could handle a "non-parenthesis" case.
Does anyone have any idea on how this could be achieved ?
The simplest approach would be not overloading the macro at all, but instead having the macro return an object that has both operator<< and operator() overloaded. Something like this:
class error_logger {
public:
error_logger(
HATLogger::LogLevel level,
char const * file,
char const * line
) : level{level}, file{file}, line{line} { }
template <typename... T>
void operator()(T && ... args) {
HATLogger::logFormat(level, file, line, std::forward<T>(args)...);
}
template <typename T>
HATLogger::logStream operator<<(T && arg) {
HATLogger::logStream stream{level, file, line};
stream << std::forward<T>(arg);
return stream;
}
private:
HATLogger::LogLevel level;
char const * file;
char const * line;
};
(This example assumes HATLogger::logStream can be moved. Adjustments to this example implementation may need to be made based on the details of your code, but the basic approach is what I'm demonstrating here.)
Now you could do:
#define HATFormatFatal (error_logger{HATLogger::LogLevel::FATAL, __FILE__, __LINE__})
And then both HATFormatFatal << ... and HATFormatFatal(...) can be used.

C++ - How to bind a callback to a class method without being static?

I have my class:
class Foo
{
public:
(...)
private:
void mycallback(void* buff, wifi_promiscuous_pkt_type_t type);
void registerMyCallback();
};
The mycallback is the callback.
I want to use a method esp_wifi_set_promiscuous_rx_cb to register the mycallback so that when a WiFi packet is detected, this callback method will be executed.
The esp_wifi_set_promiscuous_rx_cb signature is:
esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);
Where the wifi_promiscuous_cb_t definition is:
typedef void (* wifi_promiscuous_cb_t)(void *buf, wifi_promiscuous_pkt_type_t type);
I want to use the mycallback method inside my class, therefore I simply can't use like this:
void Foo::registerMyCallback()
{
esp_wifi_set_promiscuous_rx_cb(&mycallback);
}
I know that I could use something similar if I would just make my method as static.
Is there anyway that I bind mycallback to esp_wifi_set_promiscuous_rx_cb without making the callback static?
I have tried the following:
esp_wifi_set_promiscuous_rx_cb(std::bind(&Foo::mycallback, this, std::placeholders::_1, std::placeholders::_2));
But I am still having the following error:
cannot convert 'std::_Bind_helper<false, void (Foo::Foo::*)(void*, wifi_promiscuous_pkt_type_t),
Foo::Foo*, const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type
to
'wifi_promiscuous_cb_t {aka void (*)(void*, wifi_promiscuous_pkt_type_t)}' for argument '1'
Th library you are using is C package.
Thus the only guaranteed way pass a valid function is to pass a C function with C linkage. This function can then call the method on your object.
If you want the callback method to be non static you need to store a pointer (ore reference) to the callback object somewhere that your callback function can find it. (in most C callback functions you can provide a void* object that is passed to your callback, but this interface does not seem to allow this so you will have to save the value yourself).
Foo* myCBObject = nullptr;
extern "C" void myCB(void *buf, wifi_promiscuous_pkt_type_t type)
{
try
{
myCBObject->mycallback(buff, type);
}
catch(...) {} // Don't allow exceptions to cross C linkage
}
...
// Your code.
void Foo::registerMyCallback()
{
myCBObject = this;
esp_wifi_set_promiscuous_rx_cb(myCB);
}
Note: You should NOT be registering static member functions with a C library. If this works it is only by chance. There is no guarantee that a static function has the same calling convention of a C function (they usually do but that is not guaranteed).
After some research, I hope I found the solution. The trick is to bind member function first and then obtain the function pointer from the std::function. Notice the usage of my_wifi_promiscuous_cb_t and std::function::target<>().
#include <iostream>
#include <functional>
using namespace std::placeholders;
// using fake definitions
extern "C"
{
enum wifi_promiscuous_pkt_type_t {};
typedef int32_t esp_err_t;
typedef void (*wifi_promiscuous_cb_t)(void* buf, wifi_promiscuous_pkt_type_t type);
typedef void my_wifi_promiscuous_cb_t(void* buf, wifi_promiscuous_pkt_type_t type);
esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb)
{
return 0;
}
}
class Class
{
public:
void mycallback(void* buff, wifi_promiscuous_pkt_type_t type) {}
void registerMyCallback() {
std::function<void(void*, wifi_promiscuous_pkt_type_t)> fun2 = std::bind(&Class::mycallback, this, _1, _2);
esp_wifi_set_promiscuous_rx_cb(fun2.target<my_wifi_promiscuous_cb_t>());
}
};
int main()
{
Class c;
c.registerMyCallback();
}

Detect this variable availability

I am currently adapting a Windows C++ project to make it work on Linux.
I defined several macros to print formatted lines to a log file.
They are printf-like so I can write this:
WARN("%d::%s<", 42, "baz");
It's pretty easy to print something like:
[thread_id][WARN][/path/to/main.cpp:15][Fri 03/01/2019
10:38:54.408][this_value] 42::baz<
this_value is value of this or NULL if this is not defined (static function, extern "C" function).
My current code is:
#if defined(_WIN32) && !defined(__INTELLISENSE__)
#define SET_ZIS __if_exists (this) { zis = this; }
#else
#define SET_ZIS
#endif
#define _LOG(...) \
do \
{ \
void *zis = NULL; \
SET_ZIS \
GetLoggerInstance()->logMessage(__VA_ARGS__); \
} while(0)
#define LOG(...) _LOG(level, __FILE__, __LINE__, __func__, zis, __VA_ARGS__)
#define WARN(...) LOG(ILogger_level::LEVEL_WARN, __VA_ARGS__)
Is there a standard way to detect if this exists?
Maybe using std::is_* or a SFINAE trick ?
I use extern-ed "C" functions to construct objects ("this" is meaningless) and call members on instanciated objects ("this" is meaningful). "Constructors" are exported in a shared object and dynamically consumed by a C++ project. Doing it that way, I don't have to manage mangled names.
extern "C" int CreateMyClass(std::shared_ptr<MyClass> *newClass);
int CreateMyClass(std::shared_ptr<MyClass> *newClass)
{
RELAY("(%p)", newClass);
*newClass = std::make_shared<MyClass>(42, "baz");
return 0;
}
MyClass::MyClass(int a, char *b)
{
RELAY("(%d,%s)", a, b);
}
EDIT: Here's a simple test case:
#include <memory> /* For std::shared_ptr */
#define RELAY(...) printf("[%p][%s]\n", this, __func__)
class MyClass
{
public:
MyClass(int a, const char *b);
static void test();
};
extern "C" int CreateMyClass(std::shared_ptr<MyClass> *newClass);
int CreateMyClass(std::shared_ptr<MyClass> *newClass)
{
RELAY("(%p)", newClass);
*newClass = std::make_shared<MyClass>(42, "baz");
return 0;
}
MyClass::MyClass(int a, const char *b)
{
RELAY("(%d,%s)", a, b);
}
void MyClass::test()
{
RELAY("()");
printf("some work");
}
int main(int argc, char **argv)
{
std::shared_ptr<MyClass> newClass;
int ret = CreateMyClass(&newClass);
MyClass::test();
return ret;
}
g++ gives the following errors:
test.c: In function ‘int CreateMyClass(std::shared_ptr<MyClass>*)’:
test.c:2:41: error: invalid use of ‘this’ in non-member function
#define RELAY(...) printf("[%p][%s]\n", this, __func__)
^
test.c:14:3: note: in expansion of macro ‘RELAY’
RELAY("(%p)", newClass);
^~~~~
test.c: In static member function ‘static void MyClass::test()’:
test.c:2:41: error: ‘this’ is unavailable for static member functions
#define RELAY(...) printf("[%p][%s]\n", this, __func__)
^
test.c:26:3: note: in expansion of macro ‘RELAY’
RELAY("()");
^~~~~
CreateMyClass is not static ("non-member function"), so this is unavailable. Same thing for the static function.
The this reference only exists and always exists inside the non-static member functions of a c++ class/struct. It's a pointer to the memory address of the instance of the class a function is operating on. As far as logging is concerned, I'm not sure how you'd use that aside from digging through a memory dump, and I'm not 100% sure that the instance address would even be useful for that.

wrap of functions avoid duplicating

I have third party C library. I want to use it in c++
Every function return error code.
when i have to use it I have to write code like this:
int err;
err=libFun1(....);
check(err);
err=libFun2(....);
check(err);
I want to wrap this functions and avoid code duplication of check. Every of this librabry function have different number parameters. What will be a good design for this?
How about a templated function:
template <typename T>
int CallWrapper(T func)
{
int error = func();
check(error);
return error;
}
Then call it with CallWrapper(libFun1);.
/edit 4: The C++11-Way using variadic templates, inspired by Gill Bates' solution:
template <typename T, class ...A> int CallWrapper(T func, A... args) {
int error = func(args...);
check(error);
return error;
}
CallWrapper(libFun1);
CallWrapper(libFun2, 4711);
CallWrapper(libFun3, 42, 23);
/edit 5: older solutions, beginning with first solution:
#define LIBFUN1() do { \
int err = libFun1(); \
check(err); \
} while (0)
#define LIBFUN2() do { \
int err = libFun2(); \
check(err); \
} while (0)
LIBFUN1();
LIBFUN2();
Put the #defines in some header file. Please note the MISSING semicolon after the while (). This way, you can naively use LIBFUN1() and so on in any context, where a statement is allowed like if (...) LIBFUN1(); else LIBFUN2();
/edit 3: Instead of using #defines, static inline functions would do the job too:
static inline int checked_libFun1() {
int err = libFun1();
check(err);
return err;
}
static inline int checked_libFun2() {
int err = libFun2();
check(err);
return err;
}
checked_libFun1();
checked_libFun2();
/edit 2: #Myst suggested to use variadic macros that contain the name of the function to call. This could look like this:
#define call_void(name) do { \
int err = name(); \
check(err); \
} while (0)
#define call_args(name, ...) do { \
int err = name(__VA_ARGS__); \
check(err); \
} while (0)
call_void(libFun1);
call_args(libFun2, 42);
The two macros are needed because you have to distinguish between functions not accepting any arguments and functions accepting any number of arguments greater one. So, here, libFun2(42) would be called
You can use exceptions and catch them.
One way is to use Macros like:
#include <exception>
#define THROW_ON_ERROR(libFunc) do{ \
int err = libFunc(); \
if(check(err)) \
throw std::exception(); \
}while(0); \
and you code will look like this:
try
{
THROW_ON_ERROR(libFun1);
THROW_ON_ERROR(libFun2);
}catch(const std::exception& e)
{
//handle...
}
This method is not very modern but does the job. It was just to pass the point of converting the error status code convention which is the common way in C to exception handling which is a nice way in C++ (not sure if common).
Also you can use your own exceptions to pass some data.
You can do the same thing by calling a function like:
#include <functional>
class LibFuncException : public std::exception
{
public:
explicit LibFuncException(int err) : m_err(err) {}
int GetError() const { return m_err; }
private:
int m_err;
};
void ThrowOnError(std::function<int()> libFunc)
{
int err = libFunc();
if(check(err)
throw LibFuncException(err);
}
and your code can:
try{
ThrowOnError(libFunc1);
ThrowOnError(libFunc2);
} catch(const LibFuncException& e)
{
std::cout << "Error: << e.GetError() << std::endl;
}
EDIT:
if your library function sometime receive arguments you can either call the ThrowOnError with a lambda like so:
int x = 10;
const char* str = "Hello World";
ThrowOnError([x, str]() { return libFuncWithArgs(x, str); });
Or if you want to be extreme you can have a variadic template like someone suggested already
From given code, you may simply write
check(libFun1(/*...*/));
check(libFun2(/*...*/));
Possibly, you may want to wrap each method to have only one call from user side:
void chekedLibFun1(/*...*/) { check(libFun1(/*...*/)); }
void chekedLibFun2(/*...*/) { check(libFun2(/*...*/)); }
and so previous code becomes:
checkedLibFun1(/*...*/);
checkedLibFun2(/*...*/);
I can see a few ways to do this:
Template functions (#GillBates has you covered).
An inline function (maybe with variadic arguments).
Simple macros (#usr and #ZivS have you covered).
A variadic Macro.
Since you're writing for C++, I'd probably use Template functions... the only thing negative about that option is that function argument handling (assuming the library functions accept arguments) could be a headache.
I think the C approach of a variadic Macro would work better, also providing compile-time unwrapping (vs. runtime unwrapping).
i.e. (this is only an example, I didn't even test the code)
int checkerr(int err) {
if(!err)
return 0;
// ... handle errors, exit if need be.
}
#define CALL_CLIB(fn_name, ...) checkerr((fn_name)(__VA_ARGS__))
You can use it like so:
// will print "this is only 1 example"
CALL_CLIB(printf, "this is only %d, %s", 1, "example");
You can make it also more complex, if you want, adding try, catch or whatever you want into the mix.

Error: variable '*' has initializer but incomplete type and one other

I know there are a couple other questions on this specific question, but nothing that I can find on it seems to work, so I'm posting my specific code.
Here is the code:
#ifndef __MEMORY_TRACKER_H__
#define __MEMORY_TRACKER_H__
#include <unordered_map>
namespace cige
{
namespace memory
{
class CIGE_API MemoryTracker
{
protected:
typedef struct AllocRecord
{
size_t bytes;
std::string filename;
size_t line;
std::string func;
AllocRecord() :
bytes(0), line(0)
{ }
AllocRecord(size_t sz, const char* file, size_t ln, const char* fun) :
bytes(sz), line(ln)
{
if (file)
filename = file;
if (fun)
func = fun;
}
} AllocRecord;
std::string m_leakFileName;
bool m_dumpToConsole;
typedef std::unordered_map<void*, AllocRecord> AllocMap;
AllocMap m_allocationMap;
size_t m_totalAllocations;
bool m_recordEnable;
protected:
void reportLeaks();
MemoryTracker() :
m_leakFileName("CIGEMemory.log"), m_dumpToConsole(true), m_totalAllocations(0), m_recordEnable(true)
{ }
public:
void setReportFileName(const std::string& name)
{
m_leakFileName = name;
}
const std::string& getReportFileName() const
{
return m_leakFileName;
}
void setReportToConsoleOutput(bool b)
{
m_dumpToConsole = b;
}
bool getReportToConsoleOutput() const
{
return m_dumpToConsole;
}
void setRecordEnable(bool b)
{
m_recordEnable = b;
}
bool getRecordEnable() const
{
return m_recordEnable;
}
size_t getTotalMemoryAllocated() const
{
return m_totalAllocations;
}
void _recordAlloc(void* ptr, size_t sz, const char* file = nullptr, size_t ln = 0, const char* fun = nullptr);
void _recordDealloc(void* ptr);
~MemoryTracker()
{
reportLeaks();
}
static MemoryTracker& get();
};
}
}
#endif // __MEMORY_TRACKER_H__
I'm getting: variable 'cige::memory::CIGE_API cige::memory::MemoryTracker' has initializer but incomplete type at the line with the class declaration. I've looked all over and I cant find any answers that have fixed this issue.
I'm also having the error expected '}' or ',' or ';' before 'protected' at the line with protected, right above the struct.
Any help with either of these two errors would be appreciated.
EDIT: CIGE_API is defined in a separate file (which is included), as __declspec(dllexport).
EDIT2: I fixed my problem (see the answer below). It was basically just Code::Blocks derping out pretty bad.
Looks like CIGE_API is not defined. So compiler try to resolve it like variable declaration class Type Variable {initializer-list}, where Type is CIGE_API and Variable is MemoryTracker.
In other words, syntactically you're predeclaring CIGE_API type and creating variable of this type instead of defining a class.
The definition
class CIGE_API MemoryTracker { ... };
is not valid C++. I guess CIGE_API is a macro defined to an implementation specific extension, but you didn't include the corresponding header which defines that macro.
Ok I ended up fixing my own problem. Code::Blocks wasn't properly finding files that were in my project (about the third time this has happened).
In entirely unrelated news, does anyone know another cross-platform IDE that works well for C++? (I already know about Eclipse).