首页 开发编程 正文

php怎么给列表赋值

test函数中的1129:%eax便是把返回值2存放到eax寄存器中。-0x4(%rbp)则先调用test函数,test()函数把main()函数传递过来的一个值存放到了一个栈地址当中。...

php怎么给列表赋值,函数的返回值返回到main函数后?

根据所用编译器和CPU的不同,以及返回值数据类型的不同,C语言中的函数返回值可能通过寄存器传递,也可能通过栈传递。对大多数CPU和编译器来说,出于性能考虑,能使用寄存器传递的,尽量使用寄存器传递,只有当寄存器不够用的时候,才会通过栈传递。

针对这两种情况,我分别举个x64 + GCC环境下的例子来说明。

通过寄存器传递返回值

如下图中的一段简单的代码,返回值是一个有符号整数类型

我们看下x64/GCC下面对应的汇编代码:

test函数中的

1129: mov $0x2,%eax

便是把返回值2存放到eax寄存器中。而main函数中的

113d: callq 1125 <test>

1142: mov %eax,-0x4(%rbp)

则先调用test函数,然后把返回值从eax中取出,并存放到rbp 4的地址处,也就是赋值给局部变量a。

通过栈传递返回值

下面这个例子中,test()函数返回一个结构体struct result。(注:这里只是为了演示用栈传递返回值,实际项目中不建议函数直接返回结构体,可以用结构体指针代替)

(这个例子第一眼看上去会有些许复杂,千万不要懵逼,汇编代码不是洪水猛兽,掌握一些基本的汇编代码对修炼内功、调试问题都是大有裨益的:)

在x64/GCC环境下的汇编代码如下:

先看main()函数:

我们先看main()函数中调用test()的几条指令:

ret = test();

11dd: lea -0x50(%rbp), %rax

11e1: mov %rax, %rdi

11e4: mov $0x0, %eax

11e9: callq 1135 <test>

11dd和11e1两条指令的作用是把栈地址rbp 0x50存放到rdi寄存器中,我们暂且不去管这个地址是用来做什么的,等看了test()函数之后自然就会明白。后面两条指令是把eax清零,然后调用test()函数。

test()函数的汇编代码如下:

test()的汇编看起来是不是有点复杂呢?不要紧张,其实做的事情很简单,就是给局部变量r分配栈空间,然后对它进行初始化,然后把r的值存放到一个内存地址当中,最后把这个内存地址放到rax寄存器中,并返回出去。我们仔细分析一下:

1139: mov %rdi, -0x28(%rbp)

这条指令是把rdi寄存器的值存放到栈空间rbp 0x28的地址处。还记得rdi寄存器中存放的是什么吗?回想一下,在main()函数调用test()函数之前,是不是把一个地址存放到rdi寄存器中了呢?忘了的话,再去看一下。我们先不管这个值用来做什么,只要记得,test()函数把main()函数传递过来的一个值存放到了一个栈地址当中。

接下来的这几条指令,就是对局部变量r进行初始化:

struct result r = {1, 2, 3, 4};

113d: movq $0x1, -0x20(%rbp)

1145: movq $0x2, -0x18(%rbp)

114d: movq $0x3, -0x10(%rbp)

1155: movq $0x4, -0x8(%rbp)

下面就要把r的值返回出去了,我们来看看编译器是怎么做的,先看这几条指令:

return r;

115d: mov -0x28(%rbp), %rcx

1161: mov -0x20(%rbp), %rax

1165: mov -0x18(%rbp), %rdx

1169: mov %rax, (%rcx)

116c: mov %rdx, 0x8(%rcx)

115d这条指令,是把栈中rbp-0x28处的值放到rcx寄存器中,还记得这个地址存放的值是什么吗?对了,就是test()入口处从rdi中取出来的那个值,也就是main()函数通过rdi寄存器传递给test()的一个值。然后,1161和1169两条指令把r.a值存放到rcx寄存器指向的地址处,1165和116c两条指令把r.b的值存放到rcx寄存器指向的地址再偏移8的位置处。

现在我们再来回过头想一下,main()函数通过rdi寄存器传递给test()函数的那个值是用来做什么的呢?对了,那个值其实就是存放test()函数返回值的那块内存的地址。

那么记下来的几条指令就比较容易理解了:

1170: mov -0x10(%rbp), %rax

1174: mov -0x8(%rbp), %rdx

1178: mov %rax, 0x10(%rcx)

117c: mov %rdx, 0x18(%rcx)

1170和1178把r.c存放到rcx + 0x10地址处,1174和117c把r.d存放到rcx + 0x18地址处。

到这里为止,test()函数已经把局部变量struct result r的所有字段的值全部存放到main()函数通过rdi寄存器传递给test()的那个内存地址中。

最后,看一下剩下的几条指令:

1180: mov -0x28(%rbp), %rax

1184: pop %rbp

1185: retq

1180指令把rbp 0x28处的值rax中,也就是把存放返回值的那块内存的地址,存放到rax寄存器中,最后返回出去。

到这里,是不是清晰多了呢?我们再来总结一下这个过程:

main()函数把一个栈空间中的地址rbp 0x30通过rdi寄存器传递给test()函数test()函数从rdi寄存器中取得这个地址,然后把要返回的值存放到这个地址指向的内存中test()把这个地址存放到rax寄存器中,并返回给main()函数掌握一定汇编知识的重要性

可能对于很多童鞋来说,汇编语言比较晦涩难懂,难以掌握。确实,作为一个最为接近机器语言的编程语言来说,汇编确实比较晦涩,除了一些做底层系统软件的童鞋外,日常工作中直接用汇编写代码的机会确实不多,但是,这并不意味着掌握汇编语言就毫无用处。

掌握一定的汇编知识,会对整个计算机的原理和体系结构有更深入的理解,很多东西都能够知其然并知其所以然。尤其那些对底层系统软件感兴趣的童鞋,如BIOS/bootloader、OS内核、设备驱动、编译器、虚拟机等,汇编语言更是必须要掌握的。有些做上层应用的童鞋,如前端开发等,平时用到汇编的机会不多,但是在调试一些问题的时候,如果能够了解一些汇编知识,就会如虎添翼,事半功倍。

总之,不管所用的开发语言是C/C++还是Java、Python、PHP、Javascript,不管是做系统软件开发,还是做前端开发,只要是有志于干程序员这一行当的,掌握一定的汇编,对完善自己的技术知识体系,增强自己调试问题的能力,和对计算机体系结构的理解都大有裨益。

思考题

能坚持读到这里,我想你已经基本清楚C语言的函数返回值是怎么传递的了。

那么,不妨思考一下,C语言的函数参数又是怎么传递的呢?😁欢迎留言,或者私信讨论,要是有人感兴趣,我可以写篇文章介绍一下。

最后,对这个问题有不清楚的地方,欢迎留言讨论。也欢迎关注,我计划在接下来的一段时间,更新一些偏底层的东西,如Linux kernel(e.g. memory management、process management、scheduling、timekeeping, etc.)、KVM/Qemu virtualization、compiler、debugger等,有兴趣的童鞋欢迎关注,互相交流学习。

c语言construct使用方法?

construct():构造函数/方法

构造函数(constructor method,也称为构造器)是类中的一种特殊函数,当使用 new 关键字实例化一个对象时,构造函数将会自动调用。在 PHP3.0 和 PHP4.0 中,构造函数是一个与其所在类同名的函数。而在 PHP5 中,虽然也支持 PHP3.0 和 PHP4.0 中的用法,但是更推荐使用__construct作为类的构造函数,这样做的好处就是构造函数无需随着类名的改变而做出修改。在 PHP7.0 中废弃了 PHP3.0 和 PHP4.0 中的用法,构造函数必须使用__construct 来定义。

构造函数就是当对象被创建时,类中被自动调用的第一个函数,并且一个类中只能存在一个构造函数。和普通函数类似构造函数也可以带有参数,如果构造函数有参数的话,那么在实例化也需要传入对应的参数,

创建构造函数的语法格式如下:

public function __construct(参数列表){ ... ...}

其中,参数列表是可选的,不需要时可以省略。如果没有在代码中显式地声明构造函数,类中会默认存在一个没有参数列表并且内容为空的构造函数。如果显式地声明构造函数则类中的默认构造方法将不会存在。所以构造函数通常用来做一些准备工作,比如为某些参数赋值等。

php中不属于赋值运算符的是?

双等号,三个等号,大于号,小于号

定义符号常量的正确方式?

定义符号常量的一般格式:

CONST<常量标识符>=<常量>

说明:常量说明部分以关键字const开头, 后面的标识符为常量标识符,其中"="号后的常量为整数、实数、字符、 字符串(字符、字符串常量在后面章节中将作介绍)。而且,在常量说明部分可以将几个常量说明成符号常量,共用一个关键字"const"。

例如: 则在本程序中pi和zero作为符号常量,分别代表实数3.14159和整数0。也就是说,常量说明部分既定义了常量名及其值,又隐含定义了常量的类型。

关于符号常量,应注意下列几点:⑴符号常量一经定义,在程序的执行部分就只能使用该常量标识符,而不能修改其值。⑵使用符号常量比直接用数值更能体现"见名知义"的原则,也便于修改参数,故一个较好的程序中,应尽量使用符号常量,在执行部分基本上不出现直接常量。

php传值跟引用到底是怎么回事?

传值和传引用、传地址的区别:

1、传值,是把实参的值赋值给行参那么对行参的修改,不会影响实参的值2、传地址是传值的一种特殊方式,只是他传递的是地址,不是普通的如int那么传地址以后,实参和行参都指向同一个对象3、传引用真正的以地址的方式传递参数传递以后,行参和实参都是同一个对象,只是他们名字不同而已对行参的修改将影响实参的值

本文转载自互联网,如有侵权,联系删除