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)处的值执行查找的指令。

在内存中,它们是相同的,但它们的解释完全不同