__func__ 和 __FUNCTION__ 指针是否持久?

Are __func__ and __FUNCTION__ pointers persistent?

对于gcc项目,__FUNCTION____FILE____func__返回的指针是否保证指向持久内存? (也就是说,我可以安全地引用另一个函数范围内的指针吗?)我知道 __func__ 应该像函数开头的 const char __func__ = "filename" 一样,这意味着 "filename" 指向程序数据段中的某些内容,因此该指针在函数外应该是有效的。其他的是字符串,同样,它们应该在数据部分中创建条目。话虽这么说,我不相信它,我想知道这里是否有人可以确认这个假设是否正确。

例如:

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,
             someLog.val);
}

我想这样做是为了减少 memory/processing 记录调试日志的时间。

我不会称之为 持久 内存(阅读 persistence) but read only memory (or section) in the code segment 上的维基页面。

是的,__func____FUNCTION____FILE__ 去那里(作为 static const char[] 数组);像文字字符串。

请注意,像 "ab" 这样的文字字符串的两次出现可能会或不会被编译到相同的地址(同样,"bc" 可能等于也可能不等于指针 "abc"+1)。对于 __FILE__ 的两次出现也是如此;但是,在 same 函数中,所有出现的 __func__ 都应该具有相同的地址。

使用 GCC(至少在 -O1 优化时)相同内容的文字常量字符串共享相同的位置。我什至相信在函数 foo 中,__func__"foo" 可能共享相同的地址(但对于 GCC,它们不会,即使在 -O2)。您可以通过使用 gcc -fverbose-asm -S -O1 进行编译并查看生成的 *.s 汇编程序文件进行检查。

例如:

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

使用 gcc -O -fverbose-asm -S 编译(在 Linux/Debian/Sid/x86-64 上使用 GCC 7)作为

    .section    .rodata.str1.1,"aMS",@progbits,1
 .LC0:
    .string "f"
    .text
    .globl  f
    .type   f, @function
 f:
 .LFB0:
    .cfi_startproc
 # 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>
 .L1:
 # f.c:5: }
    rep ret
    .cfi_endproc
 .LFE0:
    .size   f, .-f
    .section    .rodata
    .type   __FUNCTION__.1796, @object
    .size   __FUNCTION__.1796, 2
 __FUNCTION__.1796:
    .string "f"
    .type   __func__.1795, @object
    .size   __func__.1795, 2
 __func__.1795:
    .string "f"
    .ident  "GCC: (Debian 7.2.0-8) 7.2.0"

即使使用 -Os-O3 我也在代码段中得到三个不同的位置。

然而 Clang 5 与 -O3(甚至 -O1)合并所有三个 "f"__FUNCTION____func__在同一位置(并通过删除它来优化测试):

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

所以你关心的指针是代码段中指向 static const char[] 的指针,但你不应该总是期望 __func____FUNCTION__ 具有相同的地址(即使那可能是)。

是的。这些常量实际上就像 static 声明一样。从 GCC docs 开始,__func__ 就像函数以

开头一样
static const char __func__[] = "function-name";

__FUNCTION__基本相同

根据 C2011,__FILE__ 宏扩展为

The presumed name of the current source file (a character string literal).

(C2011 6.10.8.1/1;已强调)

因此,是的,您可以将其分配给一个指针变量,并期望能够在程序的生命周期内安全地取消引用它。

该标准还指定了 __func__ 的形式,它实际上是一个隐式 变量 ,而不是宏:

The identifier __func__ shall be 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 [...].

(C2011, 6.4.2.2/1)

那么,在这种情况下,标识符指定一个const char的数组,具有静态存储持续时间。在这种情况下,在程序 运行.

中的任意时间记录指向 this 和取消引用的指针也是安全的

作为扩展和向后兼容性规定,GCC 还提供 __FUNCTION__ 作为 __func__ 的别名,因此前者的答案与后者的答案相同:是的,字符串它们引用驻留在持久内存中,您可以从另一个函数安全地访问它。