__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 [...].
那么,在这种情况下,标识符指定一个const char
的数组,具有静态存储持续时间。在这种情况下,在程序 运行.
中的任意时间记录指向 this 和取消引用的指针也是安全的
作为扩展和向后兼容性规定,GCC 还提供 __FUNCTION__
作为 __func__
的别名,因此前者的答案与后者的答案相同:是的,字符串它们引用驻留在持久内存中,您可以从另一个函数安全地访问它。
对于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 declarationstatic const char __func__[] = "function-name";
appeared [...].
那么,在这种情况下,标识符指定一个const char
的数组,具有静态存储持续时间。在这种情况下,在程序 运行.
作为扩展和向后兼容性规定,GCC 还提供 __FUNCTION__
作为 __func__
的别名,因此前者的答案与后者的答案相同:是的,字符串它们引用驻留在持久内存中,您可以从另一个函数安全地访问它。