提问人:7888 提问时间:4/23/2023 最后编辑:7888 更新时间:4/25/2023 访问量:75
有没有办法在没有手动静态分析的情况下判断 C 常量指针是否在 GCC 和 Clang 中进行比较?
Are there any way to tell if comparison between C constant pointers are made in GCC and Clang without manual static analysis?
问:
这是为了查看哪些代码行受 -fmerge-all-constants 的影响。
例如:
// main.c
#include <assert.h>
#include <stdio.h>
int foo(const int* p){
const int c[2] = {68,41};
assert(p != c);
if(!p)
return foo(c);
puts("DONE");
return 0;
}
int main(void){
foo(NULL);
}
它应该包括文件名、行和行的内容。这个例子会像 main.c:8 和 .
如果使用宏函数,例如 ,它应该告诉此宏执行与行号和文件名的常量指针比较。assert(p != c);
#define min(X, Y) ((X) < (Y) ? (X) : (Y))
我尝试在互联网上搜索,但找不到。
答:
根据语言定义,指针参数和本地数组不能具有相同的地址,因此它们总是比较为不相等。p
c
局部数组必须具有不同于其他变量的地址(如果使用),包括其他递归级别的 的其他实例,并且指针参数不能作为当前递归级别的局部变量传入,因此永远不能等于 。这与选项无关。c
c
foo()
p
c
p
c
-fmerge-all-constants
如果我编译以下代码:
int foo(const int* p) {
const int c[2] = {68,41};
return p != c;
}
使用 ,我在 x86 上得到这样的东西(为简洁起见被截断):gcc -O2 -S -masm=intel
foo:
mov eax, 1
ret
编译器能够推断出它始终为 true,因此它始终返回 1 (),而无需在运行时测试指针。由于除了在可以消除的比较中之外,不使用,因此也可以消除。p != c
true
c
c
我从你的问题中可以看出,你是在问如何判断编译器是否在比较 和 地址。最好通过查看生成的汇编代码来完成此操作,如上所示,该代码消除了 中的比较。p
c
-O2
该选项是不安全的,因为它可能会合并不同递归级别的常量局部数组,即使它们以相同的方式初始化,如果使用这些地址,例如将它们传递给另一个函数调用,或将它们与其他地址进行比较,这些数组也必须具有不同的地址。-fmerge-all-constants
但是,编译器可以自由地优化指针比较,无论它是否合并了所有级别的常量数组,因为指针比较可以在语言规则内单独优化,并且对数组最终是否被合并没有影响或依赖性。
通过比较 的地址,您隐含地同意将有一个唯一的地址用于比较目的,无论它实际上最终是否是唯一的。c
p
c
从文档中:
-fmerge-all-constants
尝试合并相同的常量和相同的变量。
此选项意味着 .除此之外,还要考虑例如,甚至常量初始化 数组或带有整数或 浮点类型。像 C 或 C++ 这样的语言需要每个变量, 在递归调用中包含同一变量的多个实例, 具有不同的位置,因此使用此选项会导致 不合格行为。
-fmerge-constants
-fmerge-constants
safer 不会合并使用地址的常量变量,也不会合并递归函数中的常量局部变量。-fmerge-constants
评论
const
-fmerge-all-constants
const
-fmerge-all-constants