【发布时间】:2020-11-18 06:16:10
【问题描述】:
如下面的代码,函数指针y、z、b的行为相同。即使*x 会被理解为指针x 的数据,&x 也会被理解为指向x 的指针。
typedef void (*func)(void);
void x(void){
printf("asdsag\n");
return;
}
int main(int argc, char const *argv[])
{
func y = *x;
func z = x;
func b = &x;
y();
z();
b();
return 0;
}
现在看看这段代码。
void test(int **p){
printf("%p\n",p);
return;
}
int main(int argc, char const *argv[])
{
int * p[5];
test(p);
test(&p);
return 0;
}
此代码为所有 3 种情况打印相同的指针。 这是上面代码编译后的汇编
main:
@ args = 0, pretend = 0, frame = 32
@ frame_needed = 1, uses_anonymous_args = 0
push {r7, lr}
sub sp, sp, #32
add r7, sp, #0
str r0, [r7, #4]
str r1, [r7]
ldr r3, [r7, #12]
mov r0, r3
bl test
add r3, r7, #12
mov r0, r3
bl test
add r3, r7, #12
mov r0, r3
bl test
movs r3, #0
mov r0, r3
adds r7, r7, #32
mov sp, r7
@ sp needed
pop {r7, pc}
.size main, .-main
似乎他们对所有三种情况都采用相同的r7+#12。
[问题] 对于以上给出的所有信息,我应该如何理解 C99 中的 p,*p,&p?
[信息] 这是使用 gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabihf 构建的
[更新]@tadman 关于不兼容指针的更新
#include <stdio.h>
void test1(void **p){
printf("%p\n",p);
return;
}
void test2(void *p){
printf("%p\n",p);
return;
}
int main(int argc, char const *argv[])
{
void * p[5] = {0};
test1(p);
test2(&p);
return 0;
}
即使-Wall 也没有警告
这是输出:
0x7fff5615bb20
0x7fff5615bb20
P/S 第一种情况我错了,所以我删除它。
【问题讨论】:
-
第二段代码应该会产生很多警告。试试
-Wall。仅仅因为它编译并不意味着它是正确的。 -
GCC 和许多编译器一样,会尝试按照您的要求去做,即使它没有任何意义。将一些随机的
int投射到指针中是可以的,只要您从不使用指针,但这也意味着它毫无意义。仅仅因为汇编代码相同并不意味着您已经定义了行为,只是一致行为。这与既定行为之间存在巨大差距。 -
是的,这很重要,因为只有一种用法是有效的,其余的只是垃圾数据。 “不兼容的指针类型”是个大问题。
-
使用未初始化的数据也是一件大事。
-
这取决于
p是什么。如果它是一个函数,那么*p、&p和p基本上都是一样的,甚至&**&&*&*p因为这些运算符什么都不做。如果它是像int这样的原语,那么运营商就是一笔巨大的交易,并且会从根本上改变它所代表的内容。