__func__和__FUNCTION__指针是否持久?

时间:2017-10-02 19:36:46

标签: c gcc gnu

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

例如:

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);
}

我想这样做是为了减少录制调试日志的内存/处理时间。

3 个答案:

答案 0 :(得分:1)

我不会将持久性内存称为persistence上的wikipage),而是只读code segment中的内存(或部分)。

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

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

使用GCC(至少在-O1优化时)相同内容的文字常量字符串共享相同的位置。我甚至认为,在功能foo中,__func__"foo"可能共享相同的地址(但即使在-O2,他们也不会共享GCC)。您可以通过使用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__相同的地址(即使可能)

答案 1 :(得分:1)

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

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

__FUNCTION__基本相同。

答案 2 :(得分:1)

根据C2011,public ActionResult NewCountry(string button,string Country,string Notes) { switch (button) { case "Save": bool exists = InsertCountry(Country, Notes); if (exists) { return Redirect("/Maintenance/Maintenance/Country?alert=true"); } else return Redirect("/Maintenance/Maintenance/Country"); case "Cancel": //Need to redirect to the countries page. return Redirect("/Maintenance/Maintenance/Country"); } return View(); } 宏扩展为

  

当前源文件的假定名称( 字符串文字 )。

C2011 6.10.8.1/1;重点补充)

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

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

  

标识符__func__应由隐式声明   翻译好像,紧跟着每个人的开口支撑   函数定义,声明

__func__
     

出现了[...]。

C2011, 6.4.2.2/1

在这种情况下,标识符指定具有静态存储持续时间的static const char __func__[] = "function-name"; 数组。在这种情况下,也可以安全地记录指向此的指针,并在程序运行后的任意时间取消引用。

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