C 函数指针和函数指针是持久的吗?

C 函数指针和函数指针是持久的吗?,c,gcc,gnu,C,Gcc,Gnu,对于gcc项目,是否保证由_函数_、_文件_和_函数_返回的指针指向持久内存?也就是说,我可以安全地遵从另一个函数范围内的指针吗?我知道_ufunc_uu在函数的开头应该像const char _func_u=filename一样,这意味着filename指向程序数据段中的某个内容,因此指针应该在函数之外有效。其他的是字符串,它们同样应该在数据部分中创建条目。尽管如此,我不相信它,我想知道这里是否有人能证实这个假设是否正确 例如: struct debugLog_t { const

对于gcc项目,是否保证由_函数_、_文件_和_函数_返回的指针指向持久内存?也就是说,我可以安全地遵从另一个函数范围内的指针吗?我知道_ufunc_uu在函数的开头应该像const char _func_u=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);
}
 const char*f(int x) { 
   if (x==0) return "f";
   if (x>0) return  __func__;
   return __FUNCTION__;
 }
我想这样做是为了减少记录调试日志的内存/处理时间。

我不会调用上的持久内存read wikipage,而是中的只读内存或节

是的,uuu func_uuu,uuu函数uuu,uuu文件uuu作为静态常量char[]数组放到那里;就像文字字符串一样

请注意,像ab这样的文字字符串的两个匹配项可能被编译成相同的地址,也可能不被编译成相同的地址。同样,bc可以等于或不等于指针abc+1。对于两次出现的_文件_;但是,在同一个函数中,所有出现的_func_uu都应该具有相同的地址

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

例如:

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);
}
 const char*f(int x) { 
   if (x==0) return "f";
   if (x>0) return  __func__;
   return __FUNCTION__;
 }
在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"

因此,您关心的指针是指向代码段中的static const char[]的指针,但您不应该总是期望uu func u与u FUNCTION u具有相同的地址,即使可能是这样。

是的。这些常量实际上起着静态声明的作用。从中,_func__的作用就像函数以开头一样

static const char __func__[] = "function-name";
和uuu函数uuu基本相同。

根据C2011,uuu文件uuu宏扩展为

当前源文件的假定名称为字符串文字

);重点补充

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

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

标识符uuu func_uuu应由 翻译好像,紧接着每个 函数定义、声明

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

在这种情况下,标识符指定一个具有静态存储持续时间的常量字符数组。在这种情况下,也可以安全地在程序运行过程中记录指向它的指针,并在此后的任意时间取消引用


作为扩展和向后兼容性条款,GCC还提供了_函数_作为_func _的别名,因此前者适用于后者:是的,它们引用的字符串驻留在持久内存中,您可以从另一个函数安全访问。

,_uuufunc_uuuuu就是这样定义的,但那会去哪里呢?在每个函数内部或在翻译单元级别?实际上,这些不是字符串文本。但常数数组。扩展为字符串文字需要文件,日期和时间也需要文件,请参见6.10.8.1__函数uuu是一个GCC扩展,但IIRC它一直被视为与uuu func uuuu差不多。谢谢,@zwol。我不知道我怎么会忽视这一点——我确实在寻找它。更新。