Can I Access a calling function's name programmatically? - c++

I'm hoping to add a little functionality to a Log File system for a project I'm working on. For my LogError() calls, I would like to include the function the error occurred in. I'm wondering if there's a way that I can access the name of the function that called LogError() so I can programmatically access that information to add it to the log.
For example:
bool Engine::GraphicsManager::Initialize(const HWND i_hWindow_main)
{
if ( !InitializeWindow( i_hWindow_main ) )
{
Engine::LogManager::Instance().LogError(L"GraphicsManager::Initialize - Unable to initialize graphics window");
return false;
}
Engine::LogManager::Instance().LogMessage(L"Graphics window initialized successfully");
/* SNIP */
initialized = true;
return true;
}
In the above example, I'd like LogError() to be able to determine that it was called from GraphicsManager::Initialize() and output (at least part of) that function's name instead of putting that in everywhere by hand.
EDIT: I should have mentioned that my LogError() function (and the other logging functions) are essentially wrappers for vfwprintf_s() so they can take variable length argument lists. While I like the "use a macro" suggestions, I'm not sure how to tackle that potential issue (which is likely another question).
Is this still reasonable/possible?
Thanks!

You could add an argument for the function name, and pass in the __FUNCTION__ macro: http://msdn.microsoft.com/en-us/library/b0084kay%28v=vs.80%29.aspx
And you could also define a macro that will automatically replace ...log...() with ...log...(__FUNCTION__).

These are predefined macros and part of the C/C++ standard which you can use:
__FILE__ __LINE__
They are explained here

Make a Logging macro
EDIT: Some fixes to deal with wide characters
//support macros
#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define STRINGIZE(x) #x
#define __WFILE__ WIDEN(__FILE__)
#define __WFUNCTION__ WIDEN(__FUNCTION__)
#define __WLINE__ WIDEN( STRINGIZE(__LINE__) )
// logging macro
#define LOG(msg) Engine::LogManager::Instance().LogError(__WFILE__ L"::" __WFUNCTION__ L":" __WLINE__ L" - " msg)
Use it like this
if( error ) { LOG(L"Error!"); }
logs
File.cpp::Function:Line - Error!
This works by using C-style string concatenation. "aa" "bb" -> "aabb" along with some operator pasting to put L before "astring". It uses the __FILE__, __FUNCTION__, and __LINE__ macros to report where the error was logged from. __LINE__ is translated into a string with the STRINGIZE macro. Due to crappy compliance with the standard, BOOST_PP_STRINGIZE is recommended if you plan on using boost anyway.

Related

Custom #pragma message warning will instantiation trace

I have a basic #pragma message warning
#pragma message(__FILE__ "(" _CRT_STRINGIZE(__LINE__) ") : warning : T does not have an << operator.")
This is inside a Sfinae controlled overload testing for the presence of a << operator. This warning works and gets printed to the output window and added to the Error List in VS2019.
However it is missing the extra info that "native" warnings and errors give:
[ with T = int ]
And the extra stack/instantiation trace, allowing you to work out exactly which function call is causing the issue.
Is there a way to have my warning also display this extra useful info, as it stands my warning is unable to even tell the user what type triggered the warning, let alone which section of code/method call is causing the warning.
__PRETTY_FUNCTION__ for example does not work in #pragma message as it is a const char[] and #pragma message requires a constant string i.e. "bla bla".
A bit unorthodox, but you could use a [[deprecated("...")]] in front of your SFINAE-controlled overload to have info about both the actual type and the call stack.
I suggest that you could refer to this link.
// Statements like:
// #pragma message(Reminder "Fix this problem!")
// Which will cause messages like:
// C:\Source\Project\main.cpp(47): Reminder: Fix this problem!
// to show up during compiles. Note that you can NOT use the
// words "error" or "warning" in your reminders, since it will
// make the IDE think it should abort execution. You can double
// click on these messages and jump to the line in question.
#define Stringize( L ) #L
#define MakeString( M, L ) M(L)
#define $Line MakeString( Stringize, __LINE__ )
#define Reminder __FILE__ "(" $Line ") : Reminder: "
Once defined, use like so:
#pragma message(Reminder "Fix this problem!")
This will create output like:
C:\Source\Project\main.cpp(47): Reminder: Fix this problem!
Besides, while in general, you cannot have a #pragma directive within macros, MS C/C++ compilers 2008 and above do support a special vendor-specific extension called the __pragma which can be used with macros.

Convert C++ log source snippet to Windows Phone C++/CX

I just started developing for Windows Phone and I'm stuck with one piece of exisiting code I need to maintain. It's a macro from a logging lib that is used in many places of existing code.
This is the macro:
#define LOG_FORMAT_FUNCTION(fmtarg, firstvararg) __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
And this is a method definition that fails to use the above macro with error "{ expected" (In German "Error: Es wurde ein '{' erwartet."):
void LogTrace_s(const char* category, const char* format, ...) LOG_FORMAT_FUNCTION(2, 3);
Can you help me get rid of the error? I'd also like to know what actually the macro does exactly.
Edit: After rading this here I now understand that this macro is good for error checking formatted strings. Now that I know, I need it even more. But I still have no clue how to translate this to MS C++.
Yes you CAN just omit it. Use
#if _MSVC_VER
#define LOG_FORMAT_FUNCTION(fmtarg, firstvararg)
#endif
It is annotating the function with extra information to help gcc give you better warnings. It does not change the behavior of the code in any way.

How do I use _DEBUG_ERROR in my own code?

Inside the <vector> header, there is code like this:
_DEBUG_ERROR("vector iterator not dereferencable");
_SCL_SECURE_OUT_OF_RANGE;
Which halts the program with a message and gives the programmer a chance to debug the code.
For a little toy project, I want to use _DEBUG_ERROR myself. It is defined in <xutility>.
However, when I include <xutility> and try to use _DEBUG_ERROR, I get the following error:
error C3861: "_Debug_message": identifier not found.
But _Debug_message is defined inside <xutility>, in line 28! Why does the compiler complain?
Also, is there another (maybe even somewhat portable?) way to halt the program for debugging?
Not 100% certain but I'm fairly sure it's actually std::_Debug_message. And PlasmaHH is right: assert() is the normal solution. You can write assert(!"message") to get a custom message. (Note the !)
You can use ASSERT or _ASSERT macro for assert-and-debug. Or, you can craft your own assert-macro. Use the definition of _ASSERT (taken from crtdbg.h):
#define _ASSERT_EXPR(expr, msg) \
(void) ((!!(expr)) || \
(1 != _CrtDbgReportW(_CRT_ASSERT, _CRT_WIDE(__FILE__), __LINE__, NULL, L"%s", msg)) || \
(_CrtDbgBreak(), 0))
The important function here is _CrtDbgReportW, which will display the assertion dialog-box having three standard buttons (Abort, Retry and Ignore). Depending on return value you can then call other functions. In the macro given above, function _CrtDbgBreak is called when user hits 'Retry' button (which causes function to return 1, see MSDN).
You may write to a log file, display to debug output window (using OutputDebugString), or do things you may like.

c++ PRINT macro linux - add date and time

in my c++ linux application I have this macro:
#define PRINT(format,arg...) printf(format,##arg)
I want to add a date and time to the beggining of the string that come to PRINT. (it is a log, so I want it at runtime, with variables)
how to change this macro in order to do it?
thanks
Do you want compile time or runtime added to the string? If the former:
#define PRINT(format,arg...) printf(__DATE__ ":" __TIME__ " " format,##arg)
will work most of the time.
Note that this will only work if invocations of PRINT only use a string literal for the format string. (ie, PRINT( "foo" ) will work, but PRINT( x ) where x is a variable will not).
If you want a runtime date and time, just append "%s" to the format and then add a call to a function that returns what you want before the arguments.
If you want local runtime date and can use boost.date_time
#define DATE_TODAY to_simple_string(day_clock::local_day())
#define PRINT(format,arg...) printf( (DATE_TODAY + ": " + format).c_str(), ##arg)
You can also use day_clock::universal_day() if you want UTC time.
Assuming that you want the compile time date and that you compiler has a __DATE__ macro that returns the date
#define PRINT(format,arg...) printf(__DATE__ ": " format,##arg)
If you want runtime date, then you can do something like that:
std::string format_current_time()
{
// format the time as you like and return it as an std::string
}
#define PRINT(format,arg...) printf("%s: " format, format_current_time.c_str(), ##arg)
If you need the current datetime, you have to implement a regular function to do what you ask, since it's impossible for a C macro to return the data you are looking for.
Remember that a C macro is replaced by the C preprocessor at compile time.

Is there a TRACE statement for basic win32 C++?

In MFC C++ (Visual Studio 6) I am used to using the TRACE macro for debugging. Is there an equivalent statement for plain win32?
_RPTn works great, though not quite as convenient. Here is some code that recreates the MFC TRACE statement as a function allowing variable number of arguments. Also adds TraceEx macro which prepends source file and line number so you can click back to the location of the statement.
Update: The original code on CodeGuru wouldn't compile for me in Release mode so I changed the way that TRACE statements are removed for Release mode. Here is my full source that I put into Trace.h. Thanks to Thomas Rizos for the original:
// TRACE macro for win32
#ifndef __TRACE_H__850CE873
#define __TRACE_H__850CE873
#include <crtdbg.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#ifdef _DEBUG
#define TRACEMAXSTRING 1024
char szBuffer[TRACEMAXSTRING];
inline void TRACE(const char* format,...)
{
va_list args;
va_start(args,format);
int nBuf;
nBuf = _vsnprintf(szBuffer,
TRACEMAXSTRING,
format,
args);
va_end(args);
_RPT0(_CRT_WARN,szBuffer);
}
#define TRACEF _snprintf(szBuffer,TRACEMAXSTRING,"%s(%d): ", \
&strrchr(__FILE__,'\\')[1],__LINE__); \
_RPT0(_CRT_WARN,szBuffer); \
TRACE
#else
// Remove for release mode
#define TRACE ((void)0)
#define TRACEF ((void)0)
#endif
#endif // __TRACE_H__850CE873
From the msdn docs, Macros for Reporting:
You can use the _RPTn, and _RPTFn macros, defined in CRTDBG.H, to replace the use of printf statements for debugging. These macros automatically disappear in your release build when _DEBUG is not defined, so there is no need to enclose them in #ifdefs.
There is also OutputDebugString. However that will not be removed when compiling release.
Trace macros that provide messages with source code link, run-time callstack information, and function prototype information with parameter values:
Extended Trace: Trace macros for Win32
I just use something like this (from memory, not tested at all...)
#define TRACE(msg) {\
std::ostringstream ss; \
ss << msg << "\n"; \
OutputDebugString(msg.str()); \
}
And then I can write things like :-
TRACE("MyClass::MyFunction returned " << value << " with data=" << some.data);
You can wrap that in some #ifdefs to remove it in release builds easily enough.
I found that using the _RPT() macro will also work with a C source file in Visual Studio 2005. This article Debugging with Visual Studio 2005/2008: Logging and Tracing provides an overview of TRACE, _RPT, and other logging type macros.
I generate a line for a log file called the ASSRTLOG which contains logs and when writing the log to the file, I also do the following source code line:
_RPT1(_CRT_WARN, "ASSRTLOG: %s", szLog1);
This line puts the same log that is going into the log file into the output window of the Visual Studio 2005 IDE.
You might be interested in the mechanics behind the approach we are using for logging. We have a function PifLogAbort() which accepts a series of arguments that are then used to generate a log. These arguments include the name of the file where the log is being generated along with the line number. The macro looks like this:
#define NHPOS_ASSERT_TEXT(x, txt) if (!(x)) { PifLogAbort( (UCHAR *) #x , (UCHAR *) __FILE__ , (UCHAR *) txt , __LINE__ );}
and the function prototype for PifLogAbort() look like this:
PifLogNoAbort(UCHAR *lpCondition, UCHAR *lpFilename, UCHAR *lpFunctionname, ULONG ulLineNo)
and to use the macro we will insert a line like this:
NHPOS_ASSERT_TEXT(sBRetCode >= 0, "CliEtkTimeIn(): EtkTimeIn() returned error");
What this macro will do is that if the return code is less than 0 (the assertion fails), a log will be generated with the provided text. The log includes the condition that generated the log along with file name and line number.
The function PifLogAbort() generates logs with a specified length and treats the output file as a circular buffer. The logs have a time and date stamp as well.
In those cases where we want to generate the descriptive text dynamically at run time, perhaps to provide the actual error code value, we use the sprintf() function with a buffer as in the following code sequence:
if (sErrorSave != STUB_BM_DOWN) {
char xBuff[128];
sprintf(xBuff, "CstSendBMasterFH: CstComReadStatus() - 0x%x, sError = %d", usCstComReadStatus, CliMsg.sError);
NHPOS_ASSERT_TEXT((sErrorSave == STUB_BM_DOWN), xBuff);
}
If we want the logs to not be generated, all we need to do is to go to the single header file where the macro is defined and define it to be nothing then recompile. However we have found that these logs can be very valuable when investigating field issues and are especially useful during integration testing.
Windows Events are a potential replacement for TRACE macros, depending on your particular scenario. The code gets compiled into both Debug and Release configurations. Event tracing can then be dynamically enabled and disabled, displayed in real-time, or dumped on a client's machine for later diagnosis. The traces can be correlated with trace information gathered from other parts of the OS as well.
If you merely need to dump information whenever code reaches certain checkpoints, together with variable content, stack traces, or caller names, Visual Studio's Tracepoints are a non-intrusive option to do so.