8

So I have this snippet of code

wchar_t funcName[] = __FUNCTIONW__;

but the problem with __FUNCTIONW__ is it has class info in the name when all I want is the function name. Now__FUNCTIONW__ just calls _CRT_WIDE(__FUNCTION__) which made me think I could call _CRT_WIDE(__func__) but that gives an error "identifier L__func__ is undefined"

__func__ is an implicitly declared identifier that expands to a character array variable containing the function name when it is used inside of a function. It was added to C in C99. From C99 §6.4.2.2/1:

The identifier __func__ is implicitly declared by the translator as if, immediately following the opening brace of each function definition, the declaration

static const char __func__[] = "function-name";

appeared, where function-name is the name of the lexically-enclosing function. This name is the unadorned name of the function.

I take this to mean __func_ is not a macro and it has nothing to do with preprocessing?

Is there another way I can get a wchar_t array at compile time?

noztol
  • 494
  • 6
  • 25

1 Answers1

3

As you cited the C standard already (actually, it's the bad one, you need C++ standard, but there you find the same...):

static const char __func__[] = "function-name";

You have now the same problem as if you wanted to convert any arbitrary other array at compile time, e. g.:

char buffer[16];
// convert to wchar_t[16]?

int array[4];
// convert to double[4]?

Type of array is int[4]. That is fix. It occupies 4*sizeof(int) bytes in memory, typically 16 bytes for most of nowaday's machines, which you can't magically change to 4*sizeof(double) bytes, typically 32 bytes (would be a nice trick to get a memory upgrade for free...).

There is no way to change char const __func__[] to a wchar_t[] at compile time, sorry. On the other hand, you should be able to use the ordinary char const array __func__ in many places you would use the wchar_t array (the array, not the wide string literal!):

std::wofstream ws; ws << __func__;
wchar_t buffer[64]; swprintf(buffer, sizeof(buffer), L"%s\n", __func__);

Problem will be with functions accepting e. g. wchar_t* while not having a char* overload. Then you won't get around converting the string at runtime (see mbstowcs).

If it helps, this might be an idea how to conveniently do it only once per function:

template <size_t N>
struct F
{
    wchar_t name[N];
    F(char const* func)
    {
        mbstowcs(name, func, N);
    }
};
#define F_INIT static F<sizeof(__func__)> func(__func__)
#define FUNC func.name

void foo()
{
    F_INIT;
    std::wcout << FUNC;
}

int main(int argc, char* argv[])
{
    F_INIT;
    std::wcout << FUNC;
    return 0;
}

Give them (template + macros) whatever name appears most appropriate to you...

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
  • wow this is very clever taking advantage of static var decls inside of functions. also in my work around I was converting to wstring and then to wchar_t* using std::wstring_convert> converter; std::wstring ws_func = converter.from_bytes(_ _func_ _); Only mention that last part b\c I was wondering if the struct and template would be needed if I just used the utilities on std::wstring and std::wstring_convert – noztol Jul 19 '16 at 22:22
  • 2
    Another way to go, but do it this way: `static std::wstring ws_func(std::wstring_convert>().from_bytes(__func__));` As being static, it is constructed only once. The converter, as only being used in the wstring's ctor, is only constructed once, too. No need for template or ordinary struct this way. – Aconcagua Jul 19 '16 at 22:40
  • There is an easier way. What works for file (https://stackoverflow.com/a/14421702/2532437), works for function as well. And this makes the compiler do it. Not even one run time call to mbstowcs. – Benilda Key Jun 15 '17 at 20:07
  • 2
    @BenKey , while `_T(__FUNCTION_)` works fine (`__FUNCTION__` is MSVC-specific), same approach won't work for `__func__` – AntonK Feb 02 '20 at 17:08