I faced a problem while implementing the logger.
First, I used to __LINE__
and __FILE__
with standard C Macro function like below
// global.h
..
namespace MyLogger {
class Logger
{
..
void _write(int _level, const char* _file, int _line, const char* _fmt, ...);
};
static Logger logger;
}; // namespace MyLogger
..
// avoid conflict..
#undef error
#undef trace
#define error(_MESSAGE_, ...) _write(LOG_LEVEL_ERROR, (const char*)__FILE__, (int)__LINE__, (const char*)_MESSAGE_, ##__VA_ARGS__)
#define info(_MESSAGE_, ...) _write(LOG_LEVEL_INFO, (const char*)__FILE__, (int)__LINE__, (const char*)_MESSAGE_, ##__VA_ARGS__)
#define trace(_MESSAGE_, ...) _write(LOG_LEVEL_TRACE, (const char*)__FILE__, (int)__LINE__, (const char*)_MESSAGE_, ##__VA_ARGS__)
..
// main.cpp
using namespace MyLogger;
// using like this
logger.error("- log error");
logger.info("- log info %s", "test 1");
..
In fact, it seems to work well. However, the problem occurred while using openv.
error and trace seem to conflicted with error and trace in opencv.
error: expected primary-expression before ‘int’ [build] CV_EXPORTS CV_NORETURN void error(int _code, const String& _err, const char* _func, const char* _file, int _line);
So I'm thinking about other methods using inline functions, not macros.
// global.h
..
//void _write(int _level, const char* _file, int _line, const char* _fmt, ...);
static inline void error(/* Is it possible to toss __LINE__ or __FILE__ ? */);
static inline void info(/* .. */);
static inline void trace(/* .. */);
..
// main.cpp
logger::error("- log error");
logger::info("%d %c %f, 1, 'A', '0.1');
Can I know the line or file of the location where the log was output through a method other than a macro?
CodePudding user response:
No, inline
functions/methods won't work the same as macro in this context.
Macros are simply text replacement, so the __LINE__
and __FILE__
will give accurate results. So macros are your only choice; see if you can name them better to avoid conflicts.
However the inline
functions are systematically compiled subunits. So the line number and the file names will always be same that of those functions where it resides.
Refer: Inline functions vs Preprocessor macros
CodePudding user response:
There are 3 stages in which C becomes a running program.
- Preprocessor
- Compiler
- Linker
__LINE__
and __FILE__
are processed by the preprocessor (stage 1). However, it's the compiler that decides about inlining (stage 2).
Other languages like C# have this in the compiler stage: [CallerMemberName]
, [CallerFilePath]
and [CallerLineNumber]
[MSDN] but I am don't think this exists in C at the moment.
CodePudding user response:
How about this:
#define log_error(_MESSAGE_, ...) \
logger._write( \
LOG_LEVEL_ERROR, \
(const char*)__FILE__, \
(int)__LINE__, \
(const char*)_MESSAGE_, \
##__VA_ARGS__)
There is no much difference (in the sense of typed characters) between logger.error
and log_error
. The advantages are, that you use a macro (__FILE__, __LINE__ are utilized as desired) and have your logger
class used only at one place (via the macro, in case you want to use a different logging mechanism), refactoring should be without any headaches.