繁体   English   中英

汇编程序级别的地址运算符和数组

[英]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存在于内存中。

恐怕您在这里犯了两件事:

  • 使用地址运算符&
  • 在C中使用数组

&运算符的地址使您可以从与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_arrayint * ptr*my_array*ptr都将为您提供数组的第一个元素

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM