我正在阅读我的编程语言书籍,学习有关参数传递的一些事情,并且有人怀疑与价值/恢复呼叫有关。
我理解它在一般情况下是如何工作的,但请考虑这种情况:
procedure P(x, y, i){
x[i]=y[5-i]
if( i<4 ) P(x, y, i+1)
}
procedure main(){
a=(1, 2, 3, 4, 5)
P(a, a, 0)
}
一旦调用P(a,a,0),就会创建两个'a'的本地副本(让我们称之为a_0和a_1)。但是当它返回时,a_0和a_1将具有不同的值。
a_0 = (5, 4, 3, 2, 5)
a_1 = (1, 2, 3, 4, 5)
因此,当它试图用新值恢复'a'时,我们发现了两种不同的可能性。这会发生什么?它会首先恢复到a_0并被a_1覆盖吗? P(a,a,0)之后'a'的值是多少?
抱歉错误的标签,但我尝试使用“参数”之类的东西,但我还不允许创建新标签。
提前致谢。
答案 0 :(得分:3)
在这种情况下,有三种可能的方法来定义语义:
禁止此类陈述。编译器静态检查并防止此类情况。这可能很难实现,参数是通过一系列过程调用传递的。
语义是其中一个副本优先于另一个副本。这可以通过逐个恢复每个参数值来实现。两个引用相同原始变量的事实意味着该变量中有两个副本,后者将成功。
语义未定义,每个编译器都可以根据需要自由实现。 C对于过程参数的评估顺序具有这样的语义。在这种情况下,程序员需要注意这一点,以避免编写不可移植的代码。
因此实际的语义将取决于您正在考虑的语言/编译器组合。另一方面,如果提供了编程语言的明确的形式语义(并且已经证明某些属性,例如它是明确的),那么检查语义是确定程序结果应该是什么的方式。
有趣的问题是,call-by-copy-restore的形式语义是什么样的。
答案 1 :(得分:0)
完全取决于您使用的特定语言的规则。你的例子看起来像伪代码,而不是任何真正的语言;所以答案可以是你喜欢的任何东西。 ;)
我所知道的唯一使用call-by-copy的真正语言是Fortran。我不是Fortran专家,但Fortran-2008标准似乎表明你的例子是非法的 - 如果你在Fortran中尝试它,编译器可以做任何它喜欢的事情。
如果有效之间存在部分或完全重叠 同一程序和两个不同虚拟参数的参数 伪参数既没有
中POINTER
也没有TARGET
属性 重叠部分不得定义,重新定义或成为 在执行过程期间未定义。例如,在CALL SUB (A (1:5), A (3:9))
A(3:5)
不得通过定义,重新定义或未定义 第一个伪参数,因为它是相关参数的一部分 使用第二个伪参数,不得定义,重新定义或 通过第二个伪参数变得不确定,因为它是一部分 与第一个伪参数关联的参数。A(1:2)
通过第一个伪参数仍然可以定义,A(6:9)
仍然存在 可以通过第二个伪论证来定义。
ISO/IEC 1539–1:2010 (E),p。 301,注12.34
在实践中,我相信所有现代Fortran编译器都使用call-by-reference而不是逐个拷贝,因此问题永远不会出现。
在Objective-C(obscure circumstances)中引用了副本,但该语言没有标准或规范;它只是由今年编译器所做的定义。它的当前规则似乎是将值复制回实际参数,因为它们从左到右显示在参数列表中,因此a
的最终值将是y
的值,而不是x
的价值。例如:
cat >pass-by-copy.m <<EOF
#import <Foundation/Foundation.h>
void sub(NSString **x, NSString **y) {
*y = @"bar";
*x = @"baz";
}
int main() {
NSString *a = @"foo";
sub(&a,&a); // looks like call-by-reference, is actually call-by-copy
NSLog(@"%@\n", a); // prints "bar", not "baz"
}
EOF
clang -fobjc-arc -framework Foundation pass-by-copy.m -o pass-by-copy
./pass-by-copy
2012-09-02 22:37:26.677 pass-by-copy[72719:707] bar