45

After years of using the big ugly MFC ASSERT macro, I have finally decided to ditch it and create the ultimate ASSERT macro.

I am fine with getting the file and line number, and even the expression that failed. I can display a messagebox with these in, and Abort/Retry/Cancel buttons.

And when I press Retry the VS debugger jumps to the line containing the ASSERT call (as opposed to the disassembly somewhere like some other ASSERT functions). So it's all pretty much working.

But what would be really cool would be to display the name of the function that failed.

Then I can decide whether to debug it without trying to guess what function it's in from the filename.

e.g. if I have the following function:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   ASSERT(lpCreateStruct->cx > 0);
   ...
}

Then when the ASSERT fires, the messagebox would show something like:

Function = CMainFrame::OnCreate

So, what's the simplest way of finding out the current function name, at runtime?

It should not use MFC or the .NET framework, even though I do use both of these.
It should be as portable as possible.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
demoncodemonkey
  • 11,730
  • 10
  • 61
  • 103
  • If you have access to the John Robbins' [Debugging Applications for Microsoft® .NET and Microsoft Windows®](http://www.amazon.com/Debugging-Applications-Microsoft®-Microsoft-Pro-Developer/dp/0735615365/ref=sr_1_16/175-5814253-7853112?ie=UTF8&s=electronics&qid=1237928779&sr=8-16) you should definitely look at the assertions from BugSlayerUtil library on the supplied CD. They are Windows-specific, but really ultimate. – Paul Mar 24 '09 at 21:09
  • I had a look at http://www.koders.com/cpp/fid3653A5E08C30DB8B7551729FBED0BC3D51B19AD8.aspx but it didn't seem to show the function name. Therefor I think my version is more ultimate than his :D – demoncodemonkey Mar 24 '09 at 22:00
  • It shows stacktrace. Stacktrace contains function names, doesn't it? – Paul Mar 24 '09 at 22:14
  • Ah I didn't notice that. Hmmmmmmm could be useful, but wouldn't that make your lovely messagebox quite unreadable? Point taken though. Maybe in v2 of my macro ;) – demoncodemonkey Mar 24 '09 at 22:21
  • For some reason link to the book is not visible in the answer, here it is: http://www.amazon.com/Debugging-Applications-Microsoft%C2%AE-Microsoft-Pro-Developer/dp/0735615365/ – Paul Mar 24 '09 at 22:22

8 Answers8

60

Your macro can contain the __FUNCTION__ macro. Make no mistake, the function name will be inserted into the expanded code at compile time, but it will be the correct function name for each call to your macro. So it "seems like" it happens in run-time ;)

e.g.

#define THROW_IF(val) if (val) throw "error in " __FUNCTION__

int foo()
{
    int a = 0;
    THROW_IF(a > 0); // will throw "error in foo()"
}
Assaf Lavie
  • 73,079
  • 34
  • 148
  • 203
  • 10
    Unfortunately, `__FUNCTION__` is not standard. `__func__` *is* standard, but it is not a string literal; it acts like a variable, so you can't concatenate it easily. – ephemient Mar 24 '09 at 20:25
  • right. but luckily the OP is using MFC and so cross-platformness is probably not a problem. – Assaf Lavie Mar 24 '09 at 20:35
  • 3
    I mentioned it because OP asked for portability. – ephemient Mar 24 '09 at 20:40
  • Unfortunately, __func__ is not part of Standard C++. –  Mar 24 '09 at 21:07
  • 1
    __FUNCTION__ is the winner, and it works brilliantly. It even tells you the namespace. I don't require true cross-platformness but only some of the projects in my solution use MFC, so the macro has to work without MFC (that's what I meant by "as portable as possible"). Thanks to all who contributed! – demoncodemonkey Mar 24 '09 at 22:15
  • Oh right, `__func__` is specified C99 but not (yet) in C++. Sigh... I guess `__FUNCTION__` is the winner, then. – ephemient Mar 24 '09 at 22:36
  • There's also `__FUNCSIG__` (again, VC++ specific) - this one includes the full signature of function, not just its name, and is handy to distinguish overloaded functions. – Pavel Minaev Jul 23 '09 at 22:07
  • 1
    As per [this](https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html) and [this](https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html), neither `__FUNCTION__` or `__func__` are macros. – sancho.s ReinstateMonicaCellio Apr 28 '17 at 03:49
28

The C++ preprocessor macro __FUNCTION__ gives the name of the function.

Note that if you use this, it's not really getting the filename, line number, or function name at runtime. Macros are expanded by the preprocessor, and compiled in.

Example program:

#include <iostream>

void function1()
{
        std::cout << "my function name is: " << __FUNCTION__ << "\n";
}

int main()
{
        std::cout << "my function name is: " << __FUNCTION__ << "\n";
        function1();
        return 0;
}

output:

my function name is: main
my function name is: function1
Zitrax
  • 19,036
  • 20
  • 88
  • 110
YenTheFirst
  • 2,172
  • 13
  • 11
  • 1
    __FUNCTION__ is not part of the C++ language standard (I didn't downvote yoou for this, but I guess someone else did) –  Mar 24 '09 at 20:24
  • good point, I think I misread something. according to http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html, __func__ is part of the C99 standard (although not necessarily everything supports it). __FUNCTION__ is not, although if the big compliers (MSDN/GCC) support it, it's effectively portable. – YenTheFirst Mar 24 '09 at 20:34
  • 1
    Note that __func__ is not part of C++ either. –  Mar 24 '09 at 20:39
  • Thanks, nice answer. And I'll let you off for saying __FUNCTION__ is portable. It's portable enough for me anyway :) – demoncodemonkey Mar 24 '09 at 22:07
  • Thanks. :) I think I realize my mistake, too. C99 is a C standard, not C++. – YenTheFirst Mar 24 '09 at 22:19
  • @YenTheFirst - Given that you realized you posted incorrect info, would you consider fixing the answer instead of just leaving a comment? – sancho.s ReinstateMonicaCellio Apr 28 '17 at 04:01
19

There's no standard solution. However, BOOST_CURRENT_FUNCTION is portable for all practical purposes. The header does not not depend on any of the other Boost headers, so can be used standalone if the overhead of the whole library is unacceptable.

Zitrax
  • 19,036
  • 20
  • 88
  • 110
fizzer
  • 13,551
  • 9
  • 39
  • 61
  • 1
    Thanks, I don't use Boost (yet) but at least I know there's a substitute for __FUNCTION__ if I ever have the need to port it. – demoncodemonkey Mar 24 '09 at 22:04
  • The header for {{BOOST_CURRENT_FUNCTION}} is standalone. You can just download it and put it in your codebase without anything else from Boost. – Andy Thomas Oct 01 '15 at 07:16
11

__FUNCTION__ or __FUNC__ or __PRETTY_FUNCTION__

http://msdn.microsoft.com/en-us/library/b0084kay(VS.80).aspx http://gcc.gnu.org/onlinedocs/gcc/Function-Names.html

Werner Henze
  • 16,404
  • 12
  • 44
  • 69
DaClown
  • 4,171
  • 6
  • 31
  • 31
10

In GCC you can use the __PRETTY_FUNCTION__ macro.
Microsoft also have an equivalent __func__ macro although I don't have that available to try.

e.g. to use __PRETTY_FUNCTION__ putting something like this at the beginning of your functions and you'll get a complete trace

void foo(char* bar){
  cout << __PRETTY_FUNCTION__ << std::endl
}

which will output

void foo(char* bar)

You also have the __FILE__ and __LINE__ macros available under all standard c/c++ compilers if you want to output even more information.

In practice I have a special debugging class which I use instead of cout. By defining appropriate environment variables I can get a full program trace. You could do something similar. These macros are incredibly handy and it's really great to be able to turn on selective debugging like this in the field.

EDIT: apparently __func__ is part of the standard? didn't know that. Unfortunately, it only gives the function name and not the parameters as well. I do like gcc's __PRETTY_FUNC__ but it's not portable to other compilers.

GCC also supports __FUNCTION__.

hookenz
  • 36,432
  • 45
  • 177
  • 286
  • 1
    For Microsoft, `__FUNCSIG__` works similarly to `__PRETTY_FUNCTION__`. (Neither they nor `__func__` are macros, for the record.) – celticminstrel Oct 11 '19 at 16:01
5

You can use the __FUNCTION__ macro which at compile time will be expanded to the name of the function.

Here's an example of how to use it in an assert macro.

#define ASSERT(cond) \
    do { if (!(cond)) \
    MessageBoxFunction("Failed: %s in Function %s", #cond, __FUNCTION__);\
    } while(0)

void MessageBoxFunction(const char* const msg,  ...)
{
    char szAssertMsg[2048];

    // format args
    va_list vargs;
    va_start(vargs, msg);
    vsprintf(szAssertMsg, msg, vargs);
    va_end(vargs);

    ::MessageBoxA(NULL, szAssertMsg, "Failed Assertion", MB_ICONERROR | MB_OK);
}
Werner Henze
  • 16,404
  • 12
  • 44
  • 69
Andrew Grant
  • 58,260
  • 22
  • 130
  • 143
4

C++20 std::source_location::function_name

No macros are needed now that we have proper standardization:

main.cpp

#include <iostream>
#include <string_view>
#include <source_location>

void log(std::string_view message,
         const std::source_location& location = std::source_location::current()
) {
    std::cout << "info:"
              << location.file_name() << ":"
              << location.line() << ":"
              << location.function_name() << " "
              << message << '\n';
}

int f(int i) {
    log("Hello world!"); // Line 16
    return i + 1;
}

int f(double i) {
    log("Hello world!"); // Line 21
    return i + 1.0;
}

int main() {
    f(1);
    f(1.0);
}

Compile and run:

g++ -ggdb3 -O0 -std=c++20 -Wall -Wextra -pedantic -o source_location.out source_location.cpp
./source_location.out

Output:

info:source_location.cpp:16:int f(int) Hello world!
info:source_location.cpp:21:int f(double) Hello world!

so note how the call preserves caller information, so we see the desired main call location instead of log.

I have covered the relevant standards in a bit more detail at: What's the difference between __PRETTY_FUNCTION__, __FUNCTION__, __func__?

Tested on Ubuntu 22.04, GCC 11.3.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
1

you can easily use func. it will take back you current function name at runtime which raised the exception.

usage:

cout << __func__ << ": " << e.what();
Hosein Basafa
  • 1,068
  • 8
  • 11