c++ - 编译器如何处理 a[i] 其中 a 是数组?如果 a 是一个指针呢?

标签 c++ c arrays pointers assembly

c-faq 告诉我当 a 是数组或指针时,该编译器会做不同的事情来处理 a[i]。以下是来自 c-faq 的示例:

char a[] = "hello";
char *p = "world";

Given the declarations above, when the compiler sees the expression a[3], it emits code to start at the location ``a'', move three past it, and fetch the character there. When it sees the expression p[3], it emits code to start at the location ``p'', fetch the pointer value there, add three to the pointer, and finally fetch the character pointed to.

但是有人告诉我,在处理 a[i] 时,编译器倾向于将 a(它是一个数组)转换为指向数组的指针。所以我想看看汇编代码,看看哪个是对的。

编辑:

这是该声明的来源。 c-faq 并注意这句话:

an expression of the form a[i] causes the array to decay into a pointer, following the rule above, and then to be subscripted just as would be a pointer variable in the expression p[i] (although the eventual memory accesses will be different, "

我对此感到很困惑:既然 a 已经衰减为指针,那么他为什么要说“内存访问会有所不同?”

这是我的代码:

// array.cpp
#include <cstdio>
using namespace std;

int main()
{
    char a[6] = "hello";
    char *p = "world";
    printf("%c\n", a[3]);
    printf("%c\n", p[3]);
}

这是我使用 g++ -S array.cpp 得到的部分汇编代码

    .file   "array.cpp" 
    .section    .rodata
.LC0:
    .string "world"
.LC1:
    .string "%c\n"
    .text
.globl main
    .type   main, @function
main:
.LFB2:
    leal    4(%esp), %ecx
.LCFI0:
    andl    $-16, %esp
    pushl   -4(%ecx)
.LCFI1:
    pushl   %ebp
.LCFI2:
    movl    %esp, %ebp
.LCFI3:
    pushl   %ecx
.LCFI4:
    subl    $36, %esp
.LCFI5:
    movl    $1819043176, -14(%ebp)
    movw    $111, -10(%ebp)
    movl    $.LC0, -8(%ebp)
    movzbl  -11(%ebp), %eax
    movsbl  %al,%eax
    movl    %eax, 4(%esp)
    movl    $.LC1, (%esp)
    call    printf
    movl    -8(%ebp), %eax
    addl    $3, %eax
    movzbl  (%eax), %eax
    movsbl  %al,%eax
    movl    %eax, 4(%esp)
    movl    $.LC1, (%esp)
    call    printf
    movl    $0, %eax
    addl    $36, %esp
    popl    %ecx
    popl    %ebp
    leal    -4(%ecx), %esp
    ret 

我无法从上面的代码中弄清楚 a[3] 和 p[3] 的机制。如:

  • “hello”在哪里初始化?
  • 1819043176 美元是什么意思?可能是“hello”的内存地址(a的地址)?
  • 我确定“-11(%ebp)”表示 a[3],但为什么呢?
  • 在“movl -8(%ebp), %eax”中,指针p的内容存储在EAX中,对吧?那么 $.LC0 是指指针 p 的内容吗?
  • “movsbl %al,%eax”是什么意思?
  • 另外,请注意以下 3 行代码:
    movl $1819043176, -14(%ebp)
    movw $111, -10(%ebp)
    movl $.LC0, -8(%ebp)

    最后一个使用“movl”,但为什么没有覆盖-10(%ebp)的内容? (我现在知道分析器了 :),地址是增量的,“movl $.LC0 -8(%ebp) 只会覆盖 {-8, -7, -6, -5}(%ebp))

对不起,我对机制以及汇编代码完全感到困惑......

非常感谢您的帮助。

最佳答案

a 是指向字符数组的指针。 p 是一个指向 char 的指针,在这种情况下,它恰好指向一个字符串字面量。

movl    $1819043176, -14(%ebp)
movw    $111, -10(%ebp)

初始化堆栈上的本地“hello”(这就是通过 ebp 引用它的原因)。由于“hello”有4个多字节,所以需要两条指令。

movzbl  -11(%ebp), %eax
movsbl  %al,%eax

References a[3]:这两个步骤的过程是因为在访问通过 ebp 引用的内存方面存在限制(我的 x86-fu 有点生锈)。

movl -8(%ebp), %eax 确实引用了 p 指针。

LC0 引用一个“相对内存”位置:一旦程序加载到内存中,就会分配一个固定的内存位置。

movsbl %al,%eax 的意思是:“移动单个字节,降低”(给予或接受......我必须查一下......我对此有点生疏正面)。 al 表示来自寄存器 eax 的一个字节。

关于c++ - 编译器如何处理 a[i] 其中 a 是数组?如果 a 是一个指针呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2073079/

相关文章:

javascript - 比较 javascript 中的数组,其中顺序并不重要

python - 在每个点的 numpy 矩阵中获取已知边界内的所有坐标点

c++ - 分配一个指向数组的指针

c++ - 没有共享所有权的获取者

C - 大端结构与小端结构相互转换

c - "C"以编程方式清除 Linux 机器上的 L2 缓存

java - 如何将数据存储在以下结构中?

未识别 C++ Windows 跳转列表类

c++ - 在 C++ 中用类型为 'double' 的乘数将复数对象与实部和虚部相乘

C 编程 - 整数值打印不正确