64-引用与函数执行

实验二 引用与函数 实验目的和要求1、熟悉引用的概念,掌握引用的定义方法,学会引用在C++程序中的应用。2、掌握函数的定义和调用方法。3、练习重载函数的使用。实验内容1、调试下列程序,写出输出结果,并解释输出结果。(1)实验程序://sy2_1.cpp #include<iostream> using namespace std; int main() { double dd=3.9,de=1.3... 阅读详情

64-引用与函数执行

一个函数的执行结果要返回给调用者,除了使用return功能,还有一种办法,那就是以引用的形式传递参数,然后在内部修改这个参数的值。前一种方法往往只能返回一个值,如果我们的函数执行结果具有多种数据,便需要把这些数据打包到一个数组、类等复合类型的变量中才能得以实现;但后一种方法相比而言就简单一些了。

运行时传递引用:Call-time Pass-by-ref

标题有点绕口,其实很简单,功能如以下php代码所示:

<?php
function byref_calltime($a) {
    $a = '(modified by ref!)';
}

$foo = 'I am a string';

//使用&传递引用
byref_calltime(&$foo);
echo $foo;
//输出'(modified by ref!)'
?>

我们在传递参数的时候使用&操作符,便可以传递foo变量的引用过去,而不是copy一份。当我们在函数内核修改这个参数时,函数外部的foo也跟着被一起修改了。同样的功能我们如何在扩展里实现呢,其实很简单,请看下面的源码:

ZEND_FUNCTION(byref_calltime)
{
    zval *a;

    //我们我接收的参数传给zval *a;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a) == FAILURE)
    {
        RETURN_NULL();
    }

    //如果a不是以应用的方式传递的。
    if (!a->is_ref__gc)
    {
        return;
    }

    //将a转成字符串
    convert_to_string(a);

    //更改数据
    ZVAL_STRING(a," (modified by ref!)",1);
    return;
}

编译时的传递引用Compile-time Pass-by-ref

如果每一次都在调用函数时候都对参数加一个&符号真是太罗嗦了,有没有一个简单的办法呢,比如在定义函数的时候便声明这个参数是引用形式的,而不用用户自己加&符号表示引用,而由内核来完成这步操作?这个功能是有的,我们在PHP语言中可以这样实现。

<?php
// 在定义函数参数的时候加了引用符
function byref_compiletime(&$a) {
    $a = ' (modified by ref!)';
}
$foo = 'I am a string';

//这个地方我们没有加&引用符
byref_compiletime($foo);
echo $foo;
//输出 (modified by ref!)
?>

上面的代码中,我们只是把引用符号从函数调用里转移到函数定义里。此功能在扩展里面实现的话就颇费周折了,我们需要提前为它定义一个arginfo结构体来向内核通知此函数的这个特定行为。添加此函数到module_entry里需要这样:

ZEND_FE(byref_compiletime, byref_compiletime_arginfo)

byref_compiletime_arginfo十一个arginfo结构体,我们在前面的章节中已经用过一次了。

在Zend Engine 2 (PHP5+)中,arginfo的数据是由多个zend_arg_info结构体构成的数组,数组的每一个成员即每一个zend_arg_info结构体处理函数的一个参数。zend_arg_info结构体的定义如下:

typedef struct _zend_arg_info {
    const char *name;               /* 参数的名称*/
    zend_uint name_len;             /* 参数名称的长度*/
    const char *class_name;         /* 类名 */
    zend_uint class_name_len;       /* 类名长度*/
    zend_bool array_type_hint;      /* 数组类型提示 */
    zend_bool allow_null;           /* 是否允许为NULL */
    zend_bool pass_by_reference;    /* 是否引用传递 */
    zend_bool return_reference;     /* 返回值是否为引用形式 */ 
    int required_num_args;          /* 必要参数的数量 */
} zend_arg_info;

生成zend_arg_info结构的数组比较繁琐,为了方便PHP扩展开发者,内核已经准备好了相应的宏来专门处理此问题,首先先用一个宏函数来生成头部,然后用第二个宏生成具体的数据,最后用一个宏生成尾部代码。

#define ZEND_BEGIN_ARG_INFO(name, pass_rest_by_reference)   ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, ZEND_RETURN_VALUE, -1)
#define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args)   \
    static const zend_arg_info name[] = {                                                                       \
        { NULL, 0, NULL, 0, 0, 0, pass_rest_by_reference, return_reference, required_num_args },


#define ZEND_ARG_INFO(pass_by_ref, name)        { #name, sizeof(#name)-1, NULL, 0, 0, 0, pass_by_ref, 0, 0 },
#define ZEND_ARG_PASS_INFO(pass_by_ref)         { NULL, 0, NULL, 0, 0, 0, pass_by_ref, 0, 0 },
#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, sizeof(#name)-1, #classname, sizeof(#classname)-1, 0, allow_null, pass_by_ref, 0, 0 },
#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, sizeof(#name)-1, NULL, 0, 1, allow_null, pass_by_ref, 0, 0 },


#define ZEND_END_ARG_INFO()     };

//这里我们先看
ZEND_BEGIN_ARG_INFO(name, pass_rest_by_reference)
ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference,required_num_args)

这两个宏函数的前两个参数的含义是一样的,name便是这个zend_arg_info数组变量的名字,这里我们定义它为:byref_compiletime_arginfo。pass_rest_by_reference如果被赋值为1,则代表着所有的参数默认都是需要以引用的方式传递的(在arginfo中单独声明的除外)。而对于ZEND_BEGIN_ARG_INFO_EX的后两个参数:

  • name和pass_rest_by_reference的含义同上。
  • return_reference:声明这个函数的返回值需要以引用的形式返回,这个参数已经在前面章节用过了。
  • required_num_args:函数被调用时,传递参数至少为前N个函数(也就是后面参数都有默认值),当设置为-1时,必须传递所有参数

接下来让我们看生成具体数据的宏:

ZEND_ARG_PASS_INFO(by_ref)
//强制所有参数使用引用的方式传递


ZEND_ARG_INFO(by_ref, name)
//如果by_ref为1,则名称为name的参数必须以引用的方式传递,


ZEND_ARG_ARRAY_INFO(by_ref, name, allow_null)
ZEND_ARG_OBJ_INFO(by_ref, name, classname, allow_null)
这两个宏实现了类型绑定,也就是说我们在传递某个参数时,必须是数组类型或者某个类的实例。如果最后的参数为真,则除了绑定的数据类型,还可以传递一个NULL数据。

//我们组合起来使用:
ZEND_BEGIN_ARG_INFO(byref_compiletime_arginfo, 0)
    ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO()

为了使我们的扩展能够兼容PHP4,还需要使用#ifdef进行特殊处理。

#ifdef ZEND_ENGINE_2
    ZEND_BEGIN_ARG_INFO(byref_compiletime_arginfo, 0)
        ZEND_ARG_PASS_INFO(1)
    ZEND_END_ARG_INFO()
#else /* ZE 1 */
static unsigned char byref_compiletime_arginfo[] =   { 1, BYREF_FORCE };
#endif

我们copy一份ZEND_FUNCTION(byref_calltime)的实现,并重名成ZEND_FUNCTION(byref_compiletime)就行了。或者直接弄个ZEND_FALIAS就行了:

ZEND_FE(byref_compiletime,byref_calltime,byref_compiletime_arginfo)
[Java JVM] Hotspot GC研究- 64位引用指针压缩技术 为什么需要指针压缩在上一篇文章 [Java JVM] Hotspot GC研究- 开篇&对象内存布局 中介绍对象内存布局时, 曾提到过, 由于在64位CPU下, 指针的宽度是64位的, 而实际的heap区域远远用不到这么大的内存, 使用64bit来存对象引用会造成浪费, 所以应该做点事情来节省资源. 如何做基于以下事实: CPU 使用的虚拟地址是64位的, 访问内存时, 必须使用64位的指针访问内 阅读详情

相关推荐

Python实现高光谱图像生成与增强:从RGB到多光谱转换(附完整代码)

本文分享一个基于Python的实用工具,能够将普通RGB图像转换为模拟高光谱图像,并进一步生成增强的彩色可见图像。为了直观展示图像细节,程序通过对特定波段的组合,生成了一幅增强的 RGB 彩色图像。该函数的主要目标是将一张普通的 RGB 图像转换为包含多个波段的高光谱图像。通过该函数,我们能直观地看到高光谱图像经过波段组合后所得到的彩色图像效果。通过以上代码,我们可以实现对海量图像数据的自动化处理,极大地提升工作效率。已附在文中,欢迎下载测试!通过以上步骤,我们可以生成一幅包含多个光谱波段信息的图像。

m0_74824642的博客 3665

php源代码解析:引用与函数执行

一个函数的执行结果要返回给调用者,除了使用return功能,还有一种办法,那就是以引用的形式传递参数,然后在内部修改这个参数的值。前一种方法往往只能返回一个值,如果我们的函数执行结果具有多种数据,便需要把这些数据打包到一个数组、类等复合类型的变量中才能得以实现;但后一种方法相比而言就简单一些了。 运行时传递引用:Call-time Pass-by-ref 标题有点绕口,其实很简单,功能

企鹅漫步 1336

开发板的使用

一、开发板使用学习大纲。 1、开发板组成、核心板资源,底板资源。 2、开发板连接、调试工具、串口参数配置。 3、开发板启动过程。 4、文件传输 1)使用串口传输。 上传/下载 2)使用网口传输。 上传/下载 5、临时/永久配置开发板IP地址。 6、开发板启动脚本。 二、开发板的组成。 核心板: CPU处理器: 芯片:S5P6818(三星) 内核: ARM cortex-A53 -> 八核处理器 运行内存:512MB*2=1G nandflash:4G 底板: 电源线:5V 串口...

qq_45633736的博客 2658

关于参数加不加引用的问题

1、问题1 这里操作符重载,我觉得加不加引用得出的结果都是一样的,那么我们加引用的目的是什么呢? 答:一般来说,对于自己编写的class或struct(特别是那种size特别大的),不采用值传递(因为拷贝值需要很多资源),采用引用传递。但是为了明确表明该实参在函数内部不会被修改,所以会使用const 引用来传参。 其实这题,你知道Complex类型size不大,用值传递也是OK的。 2、问题2 ...

xiebs的博客 770

别再死记硬背了!用‘瞬时极性法’5分钟搞定三极管反馈电路类型判断

本文介绍了使用‘瞬时极性法’快速判断三极管反馈电路类型的高效技巧。通过假设输入信号变化并追踪传递路径,该方法能准确区分正负反馈、电压电流反馈、串联并联反馈及交直流反馈,避免传统死记硬背的弊端,显著提升电路分析效率。

weixin_42524708的博客 183

PDF批量加水印 与 去除水印实践

我们可以给PDF加图片水印或文字水印,要去除图片水印,一般只需要删除最后一个图片对象即可。要去除文字水印,需要保证主体内容和文字水印在/Contents中位于不同的对象内,这样我们只需要删除文字水印对应的对象即可删除水印。而对于主体内容和文字水印已经混合在一个对象时,本文的提供的方法则无能为力,需要进一步深入分析PDF细节。

小小明-代码实体的专栏 2758

【 C++入门 】引用

目录 1、引用概念 2、引用特性 引用在定义时必须初识化 一个变量可以有多个引用 引用一旦引用一个实体,再不能引用其它实体 3、常引用 3.1、取别名的规则 权限放大error 权限不变 权限缩小 3.2、拓展1:如何给常量取别名 拓展2:临时变量具有常性 3.

bit_zyx的博客 2301

使用 ANSYS AEDT(双向耦合)对高功率射频同轴滤波器进行热分析

使用 ANSYS HFSS,可以精确计算 EM 损耗,然后将其导入 ANSYS 热分析并使用 ANSYS Icepak CFD 求解器进行仿真,以帮助工程师解决最复杂的热挑战,并预测其设计在温度变化下的表现。然后,RF 损耗将与 ANSYS Icepak CFD 求解器耦合,以执行热分析,包括传热的传导、对流和辐射模式,并计算温度曲线。在此演示中,我们将仿真下面的 RF 同轴滤波器,并计算由于所用材料的有限电导率和介电损耗而导致的 RF 传导损耗。设置 HFSS 设计后,我们可以开始 HFSS 仿真。

jkh920184196的博客 1050

函数的基本使用、函数定义与调用

一、函数的基本使用1、什么是函数? 在程序中,函数就具备某一功能的工具事先将工具准备好即函数的定义遇到应用场景拿来就用即函数的调用所以务必记住:#函数的使用必须遵循先定义,后调用的原则 2、为何要用函数 不用函数问题是: 1、程序冗长 2 程序的扩展性差 3 程序的可读性差 3 如何用函数: 函数的使用必须遵循先定义,后调用的原则 def 函数名(参数1,参数2,...): ...

aoni3517的博客 548

基于 YOLOv8 的自动驾驶车辆障碍物检测与避障路径规划

本文探讨基于YOLOv8的自动驾驶车辆障碍物检测与避障路径规划系统。在感知层面,采用YOLOv8模型实现多类别障碍物识别,结合单目视觉距离估计和ByteTrack多目标跟踪算法,完成障碍物的稳定检测与运动状态估计。在路径规划层面,设计分层规划架构,融合全局路径规划与局部避障算法,重点实现Frenet坐标系下的采样优化算法和基于模型预测控制的实时避障轨迹生成。通过完整的代码实现与仿真实验,验证系统在复杂交通场景下的有效性与实时性,为自动驾驶开发者提供从理论到实践的完整技术参考。 关键词:YOLOv8;自动驾驶

huanghm88的专栏 248

21天教你学会PCIe专栏(21)--总结和展望

回顾整个课程的主要内容和知识点总结PCIe技术的发展历程和现状展望PCIe技术的未来发展趋势和应用方向分享学习心得和实践经验1.1 课程回顾基础知识:了解了PCIe的基本概念、发展历程、标准和规范。分层结构:学习了PCIe的物理层、数据链路层和事务层的结构和功能。功能和特性:掌握了PCIe的热插拔、电源管理、多功能设备等高级功能。高速接口技术:学习了PCIe 4.0、5.0和未来趋势。实际案例分析:分析了GPU加速器和存储设备的PCIe设计和优化。常见问题和解决方案。

xiaoheshang_123的博客 672

【Qt教程31】GCC 9.3.1 ARM64 下含 QString 结构体的隐式拷贝构造崩溃

不要过早下结论—— 最初的memcpy越界理论在 demo 上无法复现,说明分析是错误的。只有通过对比实验(显式 vs 隐式拷贝构造)才能锁定根因在 GCC 的隐式代码生成Demo 复现—— 复现可能不触发编译器的特定优化路径,复现 demo 无法接近真实场景;最小化复现—— 脱离 QTableWidget 直接用测试,排除了 UI 层的干扰。

junxuezheng的博客 358

ESP32与DS18B20温度传感器的数据采集与告警系统

并且,通过自定义的微信告警功能,我们可以及时收到温度超过阈值的告警消息。随着物联网的快速发展,传感器在各种应用场景中发挥着重要的作用。本文将介绍如何使用ESP32微控制器与DS18B20温度传感器结合,通过串口输出和Web服务器实现温度数据的采集和监控,并使用自定义微信告警功能。上传完成后,打开串口监视器,您将看到ESP32连接到Wi-Fi网络,并开始监测温度。在您的计算机或移动设备上,打开一个Web浏览器,并输入ESP32的IP地址。在浏览器中输入ESP32的IP地址后,您将看到显示当前温度的页面。

loop_class349的博客 2243

Claudian 实战指南:3步把 Claude Code 嵌进 Obsidian,让 AI 直接管你的笔记库

Claudian 是一个 Obsidian AI 插件,把 Claude Code、Codex 这类 AI 编程智能体直接搬进你的笔记库:整个 Vault 就是它的工作目录,读文件、写笔记、搜内容、跑命令全部开箱即用。如果你还在"终端里让 AI 干活、Obsidian 里自己手动整理"两个窗口之间来回切换,这套方案能直接把中间那步砍掉。 [![Claudian Obsidian AI 插件界面:

gitblog_01038的博客 1009

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

exe_to_dll核心原理揭秘:PE文件重定位与导出表构建技术

exe_to_dll是一款强大的工具,能够将可执行文件(EXE)转换为动态链接库(DLL),这一过程涉及复杂的PE文件格式操作和重定位技术。本文将深入解析其核心实现原理,帮助开发者理解EXE转DLL的关键技术点。 ## PE文件格式基础:从EXE到DLL的结构转换 PE(Portable Executable)文件是Windows平台上可执行文件的标准格式,无论是EXE还是DLL都遵循这一格式

gitblog_00911的博客 957

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

iOS逆向工程入门:利用class-dump与IDA解析ipa文件

本文详细介绍了iOS逆向工程的基础知识,重点讲解如何使用class-dump和IDA工具解析ipa文件。通过提取Objective-C头文件和反汇编分析,帮助开发者学习应用内部结构、发现安全漏洞,同时强调遵守法律法规的重要性。适合iOS开发者和安全研究人员入门学习。

weixin_42527160的博客 422

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

逆向工程初探:用IDA破解BUUCTF test_your_nc背后的故事

本文通过BUUCTF的test_your_nc题目,详细介绍了如何使用IDA Pro进行逆向工程分析。文章深入解析了程序通过system函数调用执行/bin/sh获取shell的底层机制,涵盖了汇编代码分析、参数传递原理及实战技巧,帮助初学者掌握静态分析与动态验证的基本方法。

pytorch8learner的博客 145

六十四、PHP内核探索:引用与函数执行 ☞ 以引用的形式传递参数

一个函数的执行结果要返回给调用者,除了使用return功能,还有一种办法,那就是以引用的形式传递参数,然后在内部修改这个参数的值。前一种方法往往只能返回一个值,如果我们的函数执行结果具有多种数据,便需要把这些数据打包到一个数组、类等复合类型的变量中才能得以实现;但后一种方法相比而言就简单一些了。 运行时传递引用:Call-time Pass-by-ref 标题有点绕口,其实很简单,功能如以下p...

进阶之旅 282

【C++】入门基础(二)引用、const引用、内联函数inline、nullptr

C++11中引入nullptr,nullptr是一个特殊的关键字,nullptr是一种特殊类型的字面量,它可以转换成任意其他类型的指针类型。上图中,a、b原本的值为2(其中b为a的引用),当执行a++ 时,a、b的值均加1,变为3;引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。C++中指针和引用就像两个性格迴异的亲兄弟,在实践中他们相辅相成,功能有重叠性,但是各有自己的特点,互相不可替代。现在令ra为a的别名,权限被放大。

2302_79531041的博客 855

关于dex 64K 引用限制

1.官方文档   https://developer.android.com/studio/build/multidex 主要内容: 什么是64K限制 编码时如何避免64K 限制 拆分dex避免64K 限制 2.DEX   DEX =DalvikExecutable , android Dalvik java 虚拟机的可执行字节码文件。APK文件包含 DEX,其...

banyinlve3147的博客 491

x86-64 下函数调用及栈帧原理

一蓑一笠一扁舟,一丈丝纶一寸钩。 一曲高歌一樽酒,一人独钓一江秋。 ——题秋江独钓图缘起在 C/C++ 程序中,函数调用是十分常见的操作。那么,这一操作的底层原理是怎样的?编译器帮我们做了哪些操作?CPU 中各寄存器及内存堆栈在函数调用时是如何被使用的?栈帧的创建和恢复是如何完成的?针对上述问题,本本文进行了探索和研究。通用寄存器使用惯例函数调用时,在硬件层面我们

奔跑的企鹅 1万+

Linux内核中64位除法函数do_div

使用asm/div64.h中宏do_div #include <asm/div64.h> unsigned long long x,y,result; unsigned long mod; mod = do_div(x,y); result = x; 64 bit division 结果保存在x中;余数保存在返回结果中。 【问题】 编译Linux下面的代码,经常会遇到这种错误: ...

墨染锦年的博客 7039

详解ARM64可执行程序的生成过程

例如,下面的汇编代码中,FADD D0, D0, D1 执行的了浮点运算 ,结果存放在浮点寄存器 D0 中。汇编器(如 GNU Assembler,as)将汇编代码文件(.s 文件)转换为机器代码,生成二进制的目标文件(.o 文件)。在ARM64的栈结构中,栈指针(SP)通常指向栈帧的底部(也就是较低地址的位置)。var_18 = -0x18 表示的是一个相对于当前 SP 的偏移量。文件包含:处理 #include 指令,将所需的头文件内容直接插入代码中,确保所有引用的函数和变量声明都在同一文件中。

1356

C++引用作为返回值在32位,64位

无论是在32位还是64位系统中,需要注意的是确保被引用的对象的生命周期足够长,以避免返回的引用指向无效的内存地址,导致未定义的行为。另外,编译器通常会在编译时进行优化,对于返回引用的函数,它可能会使用寄存器来保存返回值的地址,而不是在堆栈中创建临时对象。在使用引用作为返回值时,需要确保被引用的对象的生命周期足够长,否则返回的引用将指向无效的内存地址,导致未定义的行为。同样地,编译器通常会对返回引用的函数进行优化,可能会使用寄存器来保存返回值的地址,而不是在堆栈中创建临时对象。

m0_52801246的博客 237

C++入门--函数重载、引用

引⽤不是新定义⼀个变量,⽽是给已存在变量取了⼀个别名,编译器不会为引⽤变量开辟内存空间, 它和它引⽤的变量共⽤同⼀块内存空间。(这里共用内存的类型,和联合体有些类似。)(引用和指针类似,但是从代码角度,引用比指针好理解一些)

2301_79202899的博客 1012
上一篇: 63-函数调用与执行
下一篇: 65-匿名函数及闭包
phantom66
博客等级 码龄15年 25粉丝 126原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值