在 Pascal 中通过引用传递 [英] Pass by reference in Pascal

查看:116
本文介绍了在 Pascal 中通过引用传递的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不确定我是否正确理解 Pascal 中的引用传递是如何工作的.它是否像在 C++ 中一样创建别名 (https://isocpp.org/wiki/faq/referencesa>) 或者它的工作方式是否与 C 中类似,并且该过程获取指向变量的指针并使用该指针.

I'm not sure if I understand correctly how pass by reference in Pascal works. Does it create an alias as in C++ (https://isocpp.org/wiki/faq/references) or does it work similarly as in C and the procedure gets a pointer to the variable and uses this pointer.

我想我可以将我的问题表述为:Pascal 是否支持真正的通过引用传递,还是通过共享调用来完成.

I guess I could formulate my question as: Does Pascal support true passing by reference, or is it done by call by sharing.

例如 FreePascal 参考声明,该过程获取一个指针 (https://www.freepascal.org/docs-html/current/ref/refsu65.html),但根据 https://swinbrain.ict.swin.edu.au/wiki/Pass_by_Value_vs._Pass_by_Reference#Conclusion 和例如 https://cgi.csc.liv.ac.uk/~frans/OldLectures/2CS45/paramPassing/paramPassing.html#callByReference 在 Pascal 中按引用传递的工作方式与在 C(传递指针的地方)不同.

For example FreePascal reference states, that the procedure gets a pointer (https://www.freepascal.org/docs-html/current/ref/refsu65.html), but according to https://swinbrain.ict.swin.edu.au/wiki/Pass_by_Value_vs._Pass_by_Reference#Conclusion and for example https://cgi.csc.liv.ac.uk/~frans/OldLectures/2CS45/paramPassing/paramPassing.html#callByReference pass by reference in Pascal works differently than in C (where pointer is passed).

如果有人能解释一下差异或传递引用的含义是如何改变的(在现代语言中,我们说传递引用,但实际上它们是传递值,例如 Java).那么通过引用传递的原始含义是什么,它是如何工作的?那么在 Pascal 中呢?

If anyone can explain a bit more about the differences or how the meaning of pass by reference has changed (in modern languages we say pass by reference, but in fact they are pass by value, like for example Java). What is then the original meaning of pass by reference and how does it work? And how is it then in Pascal?

非常感谢.

推荐答案

通过引用传递

在 Delphi 中,通过引用传递(使用 varout)意味着传递一个指针.但请注意,语义按值传递"或按引用传递"与实际传递之间存在差异.

Pass by reference

in Delp pass by reference (using var or out) means passing a pointer. But note that there is a difference between the semantics "pass by value" or "pass by reference" and the actual passing.

与 C 的区别不在于实际的传递(通过指针),而在于这些关键字的含义.Var 只是通过引用传递.Out 以不同的方式对待某些托管类型,因为使用 out,您告诉编译器不保证会初始化输入值.否则,这些在技术上是相同的(但在语义上是不同的):传递(IOW,指向)原始值的地址.

The difference with C is not the actual passing (by pointer), just what these keywords mean. Var simply passes by reference. Out treats certain managed types differently, because with out, you tell the compiler the input value is not guaranteed to be initialized. Otherwise, these are technically the same (but not semantically): the address of (IOW, a pointer to) the original values is passed.

  • 传值的语义是例程获取原始值的本地副本,并且例程可以(如果允许)更改它而不影响原来的.更改应用于本地副本并在例程结束时消失.
  • 通过引用传递的语义是您正在访问(并且可能修改)原始.
  • The semantics of pass by value are that the routine gets a local copy of the original value, and that the routine can (if allowed) change it without affecting the original. The changes apply to the local copy and go away when the routine ends.
  • The semantics of pass by reference are that you are accessing (and perhaps modiyfing) the original.

但是由于优化的原因,实际生成的代码可能会有所不同.尤其是较大的结构(有多大取决于版本和平台——这在某处记录并随着时间的推移而改变)通常通过引用(作为指针)传递,即使语义说传值.在例程的序言中(在第一个 begin 之前运行的隐藏代码),这些结构被复制到例程的本地框架中.请注意,并非所有调用约定都这样做.有时,在调用之前对参数堆栈进行了完整复制,并且不传递指针.

But the actually generated code may be different, for reasons of optimization. Especially larger structures (how large depends on version and platform -- this is documented somewhere and has changed over time) are often passed by reference (as pointers) even if the semantics say pass by value. In the prologue of the routine (the hidden code that runs before the first begin) such structures are then copied to the local frame of the routine. Note that this is not done in all calling conventions. Sometimes a full copy is made to the parameter stack before the call and no pointer is passed.

由于您仍然有一个本地副本,并且没有修改原始副本,因此这仍然被视为传值,就像您声明的那样.所有技术性的东西对用户来说都是透明的,所以区别只是在较低的层次上.这仅在您编写汇编程序或必须在 CPU 窗口中读取生成的代码时才重要.

Since you still have a local copy, and don't modify the original, this is still considered pass by value, just like you declared. All the technical stuff happens transparently for the user, so the difference is only at a lower level. This only matters if you write assembler or must read generated code in the CPU window.

如果声明了一个值参数const,则无论如何都不会修改原始值,因此可以省略将大型结构复制到本地框架,并且可以通过以下方式访问(只读)值引用(指针),即使语义传值.在这种情况下,小值总是按值传递(在寄存器或堆栈中).

If a value parameter is declared const, the original is not modified anyway, so the copying of a large structure to the local frame may be omitted and the values can accessed (read-only) by reference (pointer), even if the semantics are pass by value. Small values are always passed by value (in a register or on the stack), in such cases.

尽管将 const var 作为参数修饰符是没有意义的(某些东西可以是常量或变量,但不能两者兼有),但您仍然可以强制通过 的引用传递const 参数,通过使用 [ref] 修饰符属性:const [ref] X: Integer[ref] const X: Integer.整数通常按值传递(在寄存器中或堆栈中,取决于调用约定和平台).

Although it doesn't make sense to have const var as parameter modifier (something is either constant or variable, but not both), you can still force the passing by reference of a const parameter, by using the [ref] modifier attribute: const [ref] X: Integer or [ref] const X: Integer. The integer would usually be passed by value (in a register or on the stack, depending on calling convention and platform).

请注意,如果您按值传递引用类型(例如对象、动态数组等),按值传递语义仅适用于引用本身,即您可以获得它们的副本,并且可以修改参考而不会影响原始内容.

Note that if you pass reference types (e.g. objects, dynamic arrays, etc.) by value, the pass by value semantics only apply to the references themselves, i.e. you get a copy of them and you can modify the reference without affecting the original.

BUT:这些引用所指向的项目(对象、数组等)可以修改.只有引用本身是本地副本,而不是它们指向的内容.因此,如果您在按值传递的对象引用上调用方法,那么该对象(在堆上)毕竟可能会被修改!这不是因为按值传递或作为常量传递不能正常工作,而是因为引用是什么.

BUT: the items (objects, arrays, etc.) to which these references point can be modified. Only the references themselves are local copies, not to what they point. So if you call a method on an object reference passed by value, that object (on the heap) may be modified after all! That is not because pass-by-value or pass-as-const do not work properly, but because of what references are.

  • 按值传递意味着对原始文件进行副本,并且可以在本地修改该副本.
  • 通过引用传递意味着对原始文件的引用(指针)被传递,任何修改都会修改原始文件.
  • 在幕后,技术上,在按值传递语义中,毕竟可以传递指针.如有必要,将原件复制一份,这样原件终究不会被修改.
  • 按值传递引用类型,甚至作为 const 传递引用类型意味着它们指向的原始(堆)项被防止被修改.没有类似 C++ 的 const 概念来防止这种情况发生.
  • Pass by value means a copy of the original is made and that copy can be modified locally.
  • Pass by reference means a reference (pointer) to the original is passed and any modification modifies the original.
  • Under the hood, technically, in pass by value semantics, a pointer may be passed after all. If necessary, a copy of the original is made, so the original is not modified after all.
  • Passing reference types by value or even as const does not mean the original (heap) items to which they point are prevented from being modified. There is no C++-like const concept to prevent this.

可以在我的(非常受欢迎的)文章 中找到更多关于引用和指针的信息寻址指针.

A little more about references and pointers can be found in my (very popular) article Addressing pointers.

这篇关于在 Pascal 中通过引用传递的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆