C指针/数组值混淆
假设我们有以下代码:C指针/数组值混淆,c,arrays,pointers,C,Arrays,Pointers,假设我们有以下代码: typedef union { float e[4]; __v4sf v; float *s; } __vec4f; float test[12]; int main(){ __vec4f one; printf("adrs: &one.s = 0x%x, &one.e = 0x%x\n", &one.s, &one.e); printf("vals: one.s = 0x%x, one.e = 0
typedef union {
float e[4];
__v4sf v;
float *s;
} __vec4f;
float test[12];
int main(){
__vec4f one;
printf("adrs: &one.s = 0x%x, &one.e = 0x%x\n", &one.s, &one.e);
printf("vals: one.s = 0x%x, one.e = 0x%x\n",one.s,one.e);
one.s = test;
printf("adrs: &one.s = 0x%x, &one.e = 0x%x\n", &one.s, &one.e);
printf("vals: one.s = 0x%x, one.e = 0x%x\n",one.s,one.e);
return 0;
}
运行时,结果如下所示:
adrs: &one.s = 0xbffff270, &one.e = 0xbffff270
vals: one.s = 0x927ff590, one.e = 0xbffff270
adrs: &one.s = 0xbffff270, &one.e = 0xbffff270
vals: one.s = 0x52a0, one.e = 0xbffff270
我们可以看到One.s
和One.e
的地址是相等的(正如预期的那样),但是值不是。
这就是让我困惑的地方。e的“值”是它的地址
数组的名称只是其地址的一个标记,因此
arrayname
和arrayname
在任何上下文中都是相同的除了&
运算符的操作数或sizeof
运算符计算为其第一个元素的地址之外,数组的名称在任何上下文中都是相同的
此外,您的代码充满了未定义的行为,因为您正在使用%x
打印指针%x
仅当传递的表达式的(升级)类型为无符号int
时才有效。数组的“值”是第一个元素的地址。你可以从结果中看到这一点。如果您打印:
printf("vals: one.s = 0x%x, one.e[0] = 0x%x\n",one.s,one.e[0]);
那么您应该得到相同的答案。one.e是one.e数组的地址。1.s是1.s的值。如果需要e的值,则需要访问一个.e[0]…一个.e[3]。编译器对待静态分配数组的方式不同于浮点ptr。通过使用-S标志编译,您可以在gcc中看到这一点。下面是第一个和第二个printf语句的代码:
printf("adrs: &one.s = 0x%x, &one.e = 0x%x\n", &one.s, &one.e);
movl $.LC0, %eax
leaq -16(%rbp), %rdx
leaq -16(%rbp), %rcx
movq %rcx, %rsi
movq %rax, %rdi
movl $0, %eax
call printf
printf("vals: one.s = 0x%x, one.e = 0x%x\n",one.s,one.e);
movq -16(%rbp), %rcx
movl $.LC1, %eax
leaq -16(%rbp), %rdx
movq %rcx, %rsi
movq %rax, %rdi
movl $0, %eax
call printf
您可以看到,第一个调用有两条“加载有效地址”指令(&one.s和&one.e),但第二个printf调用只有一条这样的指令。“leaq-16(%rbp),%rdx”命令将地址%rbp-16(比%rbp寄存器中存储的地址少2个字节)移动到%rdx寄存器中,然后printf命令使用它填充一个的输出。e。在第一个版本中,重复此命令以将相同地址加载到%rcx中
在第二个版本中,通过“movq-16(%rbp),%rcx”命令填充%rcx寄存器。与“leaq”不同,“movq”是一条在内存中对指定地址(%rbp-16)处的值执行查找的指令。在内存中,它们是相同的,但它们的解释完全不同