![](/img/trans.png)
[英]Is there a difference between the address operator and a pointer in assembly?
[英]address operator and array in assembly level
Q1:地址运算符获取该变量的地址。 例如:
int var1;
int *p;
p = &var1;
程序在第3行将var1的地址带到变量p。
这是否意味着CPU创建了一个用于放置var1地址的空间(归因于地址运算符),然后将其赋予p?
问题2:以下代码:
int A[3]= {2, 4, 6};
int *p = A;
printf("%d\n", p);
printf("%d\n", *p);
打印p的值和p的解引用值(A [1]的值),它等效于:
int A[3]= {2, 4, 6};
printf("%d\n", A);
printf("%d\n", *A);
Q2中的第一个示例非常清楚地看到,CPU创建了另一个变量p来存储A的地址。
除了创建另一个变量p之外,第二个示例在CPU中是否做同样的事情?
谢谢
CPU不会“创建变量”。 您可以说编译器通过选择使用的指令在堆栈上为变量创建空间,或者在带有汇编程序指令的静态存储中为.data
, .rodata
或.bss
节保留空间。
如果将代码放置在http://godbolt.org/上且禁用了优化( -O0
),您将看到或多或少的期望,即x86,ARM或任何其他类型的实际asm将为每个变量保留空间它存在于C抽象机中,并在其中实际存储值。
但是在正常编译的实际代码( -O2
或-O3
)中,编译器利用了“好像”规则,该规则允许它发出它决定将产生与C源代码相同的可观察行为的任何asm指令,包括优化int *p
完全int *p
并等效于printf("%d\\n", 2);
。 但是,将地址A
传递给诸如printf
类的外部函数可能会导致编译器实际上在堆栈上创建该数组。 但是您永远不会占用p
本身的地址,因此没有理由让p
存在于内存中。
恐怕您在这里犯了两件事:
&
。 &
运算符的地址使您可以从与value类型相同的变量构造一个指向value的指针。 这意味着,当您编写:
p = &var1;
C获取变量var1
的地址,并将该值存储到指针变量p
。
当您通过名称引用数组时,获得的值是第一个元素的地址,因此
int *p = A;
与A的第一个元素的地址相同, 并将该值分配给int
变量p
的指针 。
当您这样做时:
int *p = &A;
你正在做的,从一个指针到数组指派int
到的类型阵列的变量int
,这是不同的类型。 从历史上看,编译器会自动转换类型并没有给出任何指示,但由于它是错误的,因此可能会混淆多个。 它在我的编译器上发出警告,尽管:
$ make pru2.o
cc -O -pipe -c pru2.c -o pru2.o
pru2.c:5:6: warning: incompatible pointer types initializing 'int *' with an expression of type 'int (*)[20]'
[-Wincompatible-pointer-types]
int *q = &A;
^ ~~
1 warning generated.
这在以后发布的代码中得到体现:
printf("%d\n", A); /* this is the same ass &A[0] */
printf("%d\n", *A); /* dereference that, as *(&A[0]) == A[0] */
在这里,重要的是(使用数组时)清楚地区分
&A
和
A
是不同的表达式,它们赋予(通常,否则认为是未定义的行为)相同的地址值,但作为指向不同类型的指针。
&A
是数组A
的地址,因此被定义为type
int (*)[sizeof A / sizeof A[0]]
而
A
表示A
的第一个元素的地址,因此它被定义为type
int *
(指向int
指针)可以通过简单地打印指向取消引用的指针的大小来显示,如:
int A[20];
...
printf("sizeof *(&A) == %z\n", sizeof *(&A));
和
printf("sizeof *A == %z\n", sizeof *A);
(第一个将为您提供完整数组的大小,表明数组A
的地址是指向20个int
s的数组的指针,而第二个将为您提供A
的第一个元素的大小,表明它的大小指向单个int
元素)
通常,数组在C语言中使用的方式非常有限,因为它们在许多情况下都与指针相似,因此无法通过值进行传递-使用数组名作为函数的参数将指针传递给第一个元素,使用数组的地址可使编译器传递相同的值,但作为指向n个元素的数组的指针---被调用的函数会将其视为简单的指针值,因为未指定的数组后缀[]
将由编译器转换为指针定义。
Q1:不,地址运算符不是var1
在堆栈上有空间的原因。 每当您在“本地”声明任何变量时,“计算机”都会在堆栈中为该变量分配内存。
问题2:是的。 请注意,在某些情况下,可以互换数组和指针。 也就是说,对于int [] my_array
和int * ptr
, *my_array
和*ptr
都将为您提供数组的第一个元素
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.