HardcoreHenry HardcoreHenry - 3 years ago 219
C Question

Are __func__ and __FUNCTION__ pointers persistent?

For gcc projects, are the pointers returned by

guaranteed to point to persistent memory? (That is, can I safely deference the pointers in the scope of another function?) I know that
is supposed to act like a
const char __func__ = "filename"
at the beginning of the function, which implies that "filename" points to something in the data segment of the program, and that the pointer should therefore be valid outside of the function. The others are strings, which again, should create entries in the data section. That being said, I don't trust it, and I'm wondering if someone here can confirm whether the assumption is correct.

For example:

struct debugLog_t {
const char * func;
const char * file;
const char * function;
uint32_t line;
int val;
} log;

struct debugLog_t someLog = {};

someFunc() {
// create debug log:
if (x) {
//uh oh...
someLog.func = __func__;
someLog.function = __FUNCTION__;
someLog.file = __FILE__;
someLog.line = line;
someLog.val = val;

void dumpSomeLog() {
printf("%s(%s) -- %s.%d: error val is x\n",
someLog.function, someLog.func, someLog.file, someLog.line,

I want to do this to reduce memory/processing time of recording debug logs.

Answer Source

I won't call that persistent memory (read wikipage on persistence) but read only memory (or section) in the code segment.

And yes, __func__, __FUNCTION__, __FILE__ go there (as static const char[] arrays); like literal strings.

Notice that two occurrences of a literal string like "ab" may or not be compiled into the same addresses (likewise, "bc" can or not be equal to pointer "abc"+1). Likewise for two occurrences of __FILE__; however, within the same function, all occurrences of __func__ should have the same address.

With GCC (at least at -O1 optimization) literal constant strings of the same content share the same location. I would even believe that in function foo the __func__ and "foo" might share the same address (but with GCC they don't, even at -O2). You could check by compiling with gcc -fverbose-asm -S -O1 and look at the generated *.s assembler file.

For example:

 const char*f(int x) { 
   if (x==0) return "f";
   if (x>0) return  __func__;
   return __FUNCTION__;

gets compiled with gcc -O -fverbose-asm -S (using GCC 7 on Linux/Debian/Sid/x86-64) as

    .section    .rodata.str1.1,"aMS",@progbits,1
    .string "f"
    .globl  f
    .type   f, @function
 # f.c:2:   if (x==0) return "f";
    leaq    .LC0(%rip), %rax    #, <retval>
    testl   %edi, %edi  # x
    je  .L1 #,
 # f.c:3:   if (x>0) return  __func__;
    testl   %edi, %edi  # x
 # f.c:4:   return __FUNCTION__;
    leaq    __func__.1795(%rip), %rax   #, tmp94
    leaq    __FUNCTION__.1796(%rip), %rdx   #, tmp95
    cmovle  %rdx, %rax  # tmp94,, tmp95, <retval>
 # f.c:5: }
    rep ret
    .size   f, .-f
    .section    .rodata
    .type   __FUNCTION__.1796, @object
    .size   __FUNCTION__.1796, 2
    .string "f"
    .type   __func__.1795, @object
    .size   __func__.1795, 2
    .string "f"
    .ident  "GCC: (Debian 7.2.0-8) 7.2.0"

Even with -Os or -O3 I'm getting three different locations in the code segment.

However Clang 5 with -O3 (or even -O1) merge all three "f", __FUNCTION__ and __func__ by putting them at the same location (and optimize the test by removing it):

    .type   f,@function
f:                                      # @f
# BB#0:
    movl    $.L.str, %eax
    .size   f, .Lfunc_end0-f
                                        # -- End function
    .type   .L.str,@object          # @.str
    .section    .rodata.str1.1,"aMS",@progbits,1
    .asciz  "f"
    .size   .L.str, 2

So the pointers you care about are pointers to static const char[] in the code segment but you should not always expect that __func__ has the same address than __FUNCTION__ (even if that could be).

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download