编译器用a [i]做什么?a是数组?如果a是指针怎么办?

ibr*_*ead 14 c c++ arrays assembly pointers

c-faq告诉我,编译器在处理a [i]时做了不同的事情,而a是数组或指针.这是c-faq的一个例子:

char a[] = "hello";
char *p = "world";
Run Code Online (Sandbox Code Playgroud)

鉴于上面的声明,当编译器看到表达式a [3]时,它会发出代码从位置"a"开始,移动三个,然后在那里获取字符.当它看到表达式p [3]时,它会发出代码从"p"位置开始,在那里获取指针值,向指针添加三个,最后获取指向的字符.

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

编辑:

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

形式a [i]的表达式导致数组衰减成指针,遵循上面的规则,然后被下标,就像表达式p [i]中的指针变量一样(尽管最终的内存访问将是不同,"

我对此很困惑:既然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]);
}
Run Code Online (Sandbox Code Playgroud)

这是我使用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 
Run Code Online (Sandbox Code Playgroud)

我无法从上面的代码中找出[3]和p [3]的机制.如:

  • 在哪里"你好"初始化?
  • $ 1819043176是什么意思?也许这是"你好"(a的地址)的内存地址?
  • 我确信"-11(%ebp)"意味着[3],但为什么呢?
  • 在"movl -8(%ebp),%eax"中,poniter p的内容存储在EAX中,对吧?所以$ .LC0表示指针p的内容?
  • "movsbl%al,%eax"是什么意思?
  • 并且,请注意以下3行代码:
    movl $ 1819043176,-14(%ebp)
    movw $ 111,-10(%ebp)
    movl $ .LC0,-8(%ebp)

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

对不起,我对这个机制以及汇编代码感到很困惑......

非常感谢您的帮助.

jld*_*ont 5

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

movl    $1819043176, -14(%ebp)
movw    $111, -10(%ebp)
Run Code Online (Sandbox Code Playgroud)

初始化堆栈上的本地"hello"(这就是引用它的原因ebp).由于"hello"中有超过4个字节,因此需要两个指令.

movzbl  -11(%ebp), %eax
movsbl  %al,%eax
Run Code Online (Sandbox Code Playgroud)

参考文献a[3]:两步过程是因为在访问内存方面存在限制ebp(我的x86-fu有点生疏).

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

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

movsbl %al,%eax意思是:"移动单字节,降低"(给予或采取......我必须查找它......我在这方面有点生疏).al表示寄存器中的一个字节eax.