美文网首页
C语言到汇编-指针与数组2

C语言到汇编-指针与数组2

作者: 故事观察日记 | 来源:发表于2020-04-16 21:53 被阅读0次

本章剩下的内容主要有:

1.指针与数组 & 地址算术运算
2.字符指针与函数
3.多维数组 & 指针与多维数组
4.指向函数的指针

每个内容举一个例子,第一个例子:

int a[10] = {1,2,3,4,5,6};
int *pa = &a[0];

main(){ 
    pa = &a[0]; 
    pa = a;
    int x = *pa;
    int i;
    for(i=0; i<5; i++){
        printf("%d", a[i]);
        printf("%d", pa[i]);
        printf("%d", *(pa+i));
    }
}

指针类型的pa 指向了a[0],即pa 的值是a[0]的地址。数组变量a 的值也是数组的首地址,所以pa 的两种赋值方式完全相同。x 的值是a[0],即1。pa[i]*(pa+i)指向的也是同一个元素。对照编译后的汇编代码,如下:

.globl _a
    .data
_a:
    .long   1
    .long   2
    .long   3
    .long   4
    .long   5
    .long   6
    .space 16
.globl _pa
_pa:
    .long   _a
    .section .rdata,"dr"
LC0:
    .ascii "%d\0"
    .text
.globl _main
_main:
    mov DWORD PTR _pa, OFFSET FLAT:_a
    mov DWORD PTR _pa, OFFSET FLAT:_a
    mov eax, DWORD PTR _pa
    mov eax, DWORD PTR [eax]
    mov DWORD PTR [ebp-4], eax
    mov DWORD PTR [ebp-8], 0
L2:
    cmp DWORD PTR [ebp-8], 4
    jg  L3
    mov eax, DWORD PTR [ebp-8]
    mov eax, DWORD PTR _a[0+eax*4]
    mov DWORD PTR [esp+4], eax
    mov DWORD PTR [esp], OFFSET FLAT:LC0
    call    _printf
    mov eax, DWORD PTR [ebp-8]
    lea edx, [0+eax*4]
    mov eax, DWORD PTR _pa
    mov eax, DWORD PTR [edx+eax]
    mov DWORD PTR [esp+4], eax
    mov DWORD PTR [esp], OFFSET FLAT:LC0
    call    _printf
    mov eax, DWORD PTR [ebp-8]
    lea edx, [0+eax*4]
    mov eax, DWORD PTR _pa
    mov eax, DWORD PTR [edx+eax]
    mov DWORD PTR [esp+4], eax
    mov DWORD PTR [esp], OFFSET FLAT:LC0
    call    _printf
    lea eax, [ebp-8]
    inc DWORD PTR [eax]
    jmp L2
L3:
    leave
    ret

可以看到_pa 的值就是标号_a ,而后面两个printf 的代码也完全一样。
第二个例子,字符指针与函数:

char amessage[] = "now is the time"; /* 定义一个数组 */
char *pmessage = "now is the time"; /* 定义一个指针 */
char *b[] = {"xxx","yyy"};
main(){
    char *a[] = {amessage,pmessage};
}

编译后的汇编代码:

.globl _amessage
    .data
_amessage:
    .ascii "now is the time\0"
    .section .rdata,"dr"
LC0:
    .ascii "now is the time\0"
.globl _pmessage
    .data
_pmessage:
    .long   LC0
    .section .rdata,"dr"
LC1:
    .ascii "xxx\0"
LC2:
    .ascii "yyy\0"
.globl _b
    .data
_b:
    .long   LC1
    .long   LC2
    .text
.globl _main
_main:
    mov DWORD PTR [ebp-8], OFFSET FLAT:_amessage
    mov eax, DWORD PTR _pmessage
    mov DWORD PTR [ebp-4], eax
    leave
    ret

变量ab 是指针数组,在汇编代码中与其他变量其实并无不同,在函数内部都是一个内存空间,在函数外部都是一个标号。
第三个例子,指针与多维数组:

static char daytab[2][13] = { 
 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 
 {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} 
 };
 
int a[10][20]; 
int *w[10];
 
 main(){
     int a = daytab[1][10];
     f(daytab);
 }
 
 f(char daytab[][13])
 {
     char b = daytab[1][10];
 }

编译后的汇编代码:

    .data
_daytab:
    .byte   0
    .byte   31
    .byte   28
    .byte   31
    .byte   30
    .byte   31
    .byte   30
    .byte   31
    .byte   31
    .byte   30
    .byte   31
    .byte   30
    .byte   31
    .byte   0
    .byte   31
    .byte   29
    .byte   31
    .byte   30
    .byte   31
    .byte   30
    .byte   31
    .byte   31
    .byte   30
    .byte   31
    .byte   30
    .byte   31
    .text
.globl _main
_main:
    movsx   eax, BYTE PTR _daytab+23
    mov DWORD PTR [ebp-4], eax
    mov DWORD PTR [esp], OFFSET FLAT:_daytab
    call    _f
    leave
    ret
.globl _f
_f:
    push    ebp
    mov ebp, esp
    sub esp, 4
    mov eax, DWORD PTR [ebp+8]
    add eax, 23
    movzx   eax, BYTE PTR [eax]
    mov BYTE PTR [ebp-1], al
    leave
    ret
    .comm   _a, 800  # 800
    .comm   _w, 48   # 40

可以发现,汇编代码中并不区分一维还是二维数组,而是调用时根据行和列的值计算出具体位置。
最后一个例子,指向函数的指针:

 int f(int i){
     return i+1;
 }
 
 int w(int i){
     return i+2;
 }
 
int useforw(int (*x)(int));
 
 main(){
     int (*pf)(int);
     pf = f;
     int a = 1;
     int b = 2;
     b = (int (*)(int)) a;
     useforw(f);
     useforw(w);
     useforw((int (*)(int))(1+1==2 ? f : w));
 }
 
 int useforw(int (*x)(int)){
     int y = (*x)(9);
 }

main 函数上面定义了两个函数fw ,省去了声明。useforw 函数的参数是一个指向函数的指针,也即函数指针。函数指针其实就是指向了函数代码的首地址,而函数名也是代码的首地址,这和数组很类似,在汇编代码中,数组名和函数名都是一个标号。
main 函数中第一行:

     int (*pf)(int);

声明了一个函数指针变量,变量名为pf ,类型为int (*)(int)。接着把函数f 的地址赋给了pf 。其实不管pf 是什么类型,int 型还是看起来很复杂的指针型,在汇编代码中都只是一个没有姓名的内存空间而已。
后面的代码将变量a 强制转换为int (*)(int)类型,也就是函数指针类型,这种写法是可以的,但是不能用(int (*)(int)) a;这种方式来将a 声明为此种类型的变量。
编译后的汇编代码如下:

    .text
.globl _f
_f:
    push    ebp
    mov ebp, esp
    mov eax, DWORD PTR [ebp+8]
    inc eax
    pop ebp
    ret
.globl _w
_w:
    push    ebp
    mov ebp, esp
    mov eax, DWORD PTR [ebp+8]
    add eax, 2
    pop ebp
    ret
.globl _main
_main:
    mov DWORD PTR [ebp-4], OFFSET FLAT:_f
    mov DWORD PTR [ebp-8], 1
    mov DWORD PTR [ebp-12], 2
    mov eax, DWORD PTR [ebp-8]
    mov DWORD PTR [ebp-12], eax
    mov DWORD PTR [esp], OFFSET FLAT:_f
    call    _useforw
    mov DWORD PTR [esp], OFFSET FLAT:_w
    call    _useforw
    mov DWORD PTR [esp], OFFSET FLAT:_f
    call    _useforw
    leave
    ret
.globl _useforw
_useforw:
    push    ebp
    mov ebp, esp
    sub esp, 8
    mov DWORD PTR [esp], 9
    mov eax, DWORD PTR [ebp+8]
    call    eax
    mov DWORD PTR [ebp-4], eax
    leave
    ret

可以看到,函数指针作为参数时,虽然写法看起来复杂,实际只是把函数名/标号的地址传递了过去。
好了,第五章就到这里,下一篇开始学习第六章——结构。

相关文章

  • C语言到汇编-指针与数组2

    本章剩下的内容主要有: 每个内容举一个例子,第一个例子: 指针类型的pa 指向了a[0],即pa 的值是a[0]的...

  • C语言到汇编-指针与数组1

    指针是一种保存变量地址的变量。下面代码声明了指针变量p ,它的值是x 的地址: 一元运算符&可用于取一个对象的地址...

  • C语言中的指针与数组

    C语言中的指针与数组 @(C语言)[排序算法, 快速排序, C实现] 引言 相信指针与数组是不少同学在初学C语言时...

  • 02-C语言的指针

    02-C语言的指针 目标 C语言指针释义 指针用法 指针与数组 指针与函数的参数 二级指针 函数指针 指针在C中很...

  • C语言21 指针数组与数组指针

    C语言21 指针数组与数组指针 指针数组的定义 指针数组的赋值 结构体指针数组 分析下面的代码 数组指针的定义 数...

  • 指针数组和数组指针

    指针数组|存储指针的数组 在C语言和C++语言中,数组元素全为指针的数组称为指针数组。 例如:int *p[10]...

  • C语言的指针与数组(进阶篇之一)

    一、一维数组与指针 (1).数组指针在C语言中,数组的首地址称为数组指针。而C++规定,数组的首地址可用数组名a表...

  • 指针与数组的区别和联系

    原文地址:指针与数组的区别和联系作者:zhenhuaqin 一.指针与数组的联系: 指针与数组是C语言中很重要的两...

  • 慕课网-Linux C语言指针与内存-学习笔记

    Linux C语言指针与内存 工具与原理 指针 数组 字符串 堆内存与栈内存 gdb内存调试工具。 C语言中指针的...

  • 浅谈C语言数组与指针的关系

    浅谈指针定义细节及其与数组的关系 前言 翁恺老师曾经说过,指针是 C 语言的灵魂,是使 C 语言成为 “C语言” ...

网友评论

      本文标题:C语言到汇编-指针与数组2

      本文链接:https://www.haomeiwen.com/subject/hmsdvhtx.html