考虑以下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
答案 0 :(得分:3)
声明
char c[1] = {'Q'};
c
是char array&amp; array name
,c
本身代表该数组的基址。如果您打印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
。