c将指向char数组的指针作为int *转换为将char *作为int *转换为相同的结果

时间:2018-06-14 16:25:45

标签: c

考虑以下C程序:

#include <stdio.h>
#include <stdlib.h>
int main(){
    char c[1] = {'Q'};
    printf("%c ",*(char*)(c));   // line 1
    printf("%c\n",*(char*)(&c));  // line 2
}

输出为Q Q

这是我对应该发生的事情的理解,c是指向char的指针,因此第1行打印的char应该是字母Q,因为指向char的指针被强制转换为指向char的指针(所以没有发生)然后它被解除引用。因为c指向的char是'Q',所以第1行打印'Q'。这似乎对我有意义。

然而第2行没有。 c的地址被转换为指向char的指针,因此我认为应该发生的是在解除引用之后,表达式*(char *)(&amp; c)应该简化为指针c的值,但表示为char。 / p>

这两个都给出了相同的结果,我不认为这是巧合,因为我已经尝试过许多不同的字母。我想知道为什么会这样。感谢

PS:
我试过这个:

#include <stdio.h>
#include <stdlib.h>
int main(){
    char c[10] = "asdf";
    printf("%c ",*(char*)(c));   // line 1
    printf("%c\n",*(char*)(&c));  // line 2
}

我得到了这个:a a

2 个答案:

答案 0 :(得分:3)

声明

char c[1] = {'Q'};

c是char array&amp; array namec本身代表该数组的基址。如果您打印c&c,则两者都会显示相同的结果。

旁注: - c表示指向数组第一个元素的指针,&c表示指向整个数组的指针。

int main(void){
        char c[1] = {'Q'};
        printf("%p %p\n",(void*)c,(void*)&c); /* bot results the same */
        return 0;
}

这就是为什么*(char*)(c)*(char*)(&c)产生相同结果的原因。例如

char c[10] = "asdf"; /* lets assume base address of c is 0x100 */

看起来像是

 --------------------------------------
 |  a   |   s   |   d   |  f   | \0   |
 --------------------------------------
0x100   0x101   0x102 ..
c

接下来如何表达这两个*(char*)(c)&amp; *(char*)(&c)已执行。

*(char*)(c)  =>  *(char*)(0x100)  => typecasted as char* means c points to 1 byte memory 
             =>   *(0x100)        => value in the first byte from 0x100 to 0x101 => a

*(char*)(&c)     =>  *(char*)(&(0x100)) => *(char*) (0x100) => c and &c are same 
                 =>   *(0x100)          => value in the first byte from 0x100 to 0x101 => a

答案 1 :(得分:0)

如果你考虑平等(void*) c == (void*) &c,你会发现它在逻辑上是正确的。以静态分配的整数为例:

int myvar = 2;

打印myvar的值是有意义的,因为它是一个整数,并且它是“普遍”可识别的。

现在你如何识别阵列?显然有一个存储器存储地址。

但你怎么打印呢?没有规则。如果没有理由这样做,那么区分c&c的重点是什么。可以推测c可以被解释为数组的第一个元素,但你可以想象这个选择的所有缺点。

编译器的推理实际上是不同的,特别是因为变量不存在,所以它用它可以使用的东西替换它们。

以此片段为例:

int a = 2;
char c[6] = {'a', 'b', 'c', 'd', 'e', '\0'};

printf("%p\n",  c);
printf("%p\n", (void*) &c);
printf("%d\n", a);
printf("%p\n", (void*) &a);

以下是gcc生成的程序集(intel语法):

    mov     DWORD PTR [rbp-4], 2     # int a = 2;
    mov     BYTE PTR [rbp-16], 97    # char c[6] = {'a', 'b', 'c', 'd', 'e', '\0'};
    mov     BYTE PTR [rbp-15], 98
    mov     BYTE PTR [rbp-14], 99
    mov     BYTE PTR [rbp-13], 100
    mov     BYTE PTR [rbp-12], 101
    mov     BYTE PTR [rbp-11], 0
    lea     rax, [rbp-16]            # printf("%p\n",  c);
    mov     rsi, rax
    mov     edi, OFFSET FLAT:.LC0
    mov     eax, 0
    call    printf
    lea     rax, [rbp-16]            # printf("%p\n", (void*) &c);
    mov     rsi, rax
    mov     edi, OFFSET FLAT:.LC0
    mov     eax, 0
    call    printf
    mov     eax, DWORD PTR [rbp-4]   # printf("%d\n", a);
    mov     esi, eax
    mov     edi, OFFSET FLAT:.LC1 [complete object constructor] [complete object constructor]
    mov     eax, 0
    call    printf
    lea     rax, [rbp-4]             # printf("%p\n", (void*) &a);
    mov     rsi, rax
    mov     edi, OFFSET FLAT:.LC0
    mov     eax, 0
    call    printf

编译器以相同的方式解释c&c