Вызов по значению / результат (он же копирование / восстановление) - PullRequest
3 голосов
/ 08 марта 2011

Я читаю свою книгу «Языки программирования», узнаю кое-что о передаче параметров, и у меня возникло сомнение относительно вызова по значению / восстановлению.

Я понимаю, как это работает в общих случаях, но учту этоcase:

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?Каким будет значение «a» после P (a, a, 0)?

Извините за неправильный тег, но я попытался использовать что-то вроде «параметра», и мне не разрешено создавать новыетеги еще.

Заранее спасибо.

Ответы [ 2 ]

3 голосов
/ 08 марта 2011

В таких ситуациях существует три возможных способа определения семантики:

  • Запрещать такие операторы.Компилятор статически проверяет и предотвращает подобные ситуации.Этого может быть трудно достичь, если аргумент передается через серию вызовов процедур.

  • Семантика заключается в том, что одна из копий имеет приоритет над другой.Это было бы реализовано путем восстановления каждого значения аргумента обратно одно за другим.Тот факт, что два ссылаются на одну и ту же исходную переменную, будет означать, что в эту переменную внесены две копии, и последняя будет успешной.

  • Семантика не определена, и каждый компилятор может реализовать ее по своему усмотрению.C имеет такую ​​семантику для порядка оценки аргументов процедур.В таких случаях программист должен знать об этом, чтобы не писать непереносимый код.

Таким образом, фактическая семантика будет зависеть от того, какую комбинацию языка / компилятора вы рассматриваете.С другой стороны, если предоставляется однозначная формальная семантика языка программирования (и определенные свойства были доказаны, например, то, что он однозначен), то проверка семантики - это способ определить, каким должен быть результат вашей программы..

Интересный вопрос - как выглядит формальная семантика call-by-copy-restore.

0 голосов
/ 03 сентября 2012

Это полностью зависит от правил конкретного языка, который вы используете.Ваш пример выглядит как псевдокод, а не как настоящий язык;поэтому ответ может быть любым, что вам нравится.;)

Единственный известный мне реальный язык, который использует вызов за копией, - это Фортран.Я не эксперт по Фортрану, но стандарт Фортрана-2008 выглядит как , утверждая, что ваш пример просто недопустим - если вы попробуете его в Фортране, компилятору будет разрешено делать практически все, что ему захочется.1005 *

Если между действующими аргументами двух разных фиктивных аргументов одной и той же процедуры есть частичное или полное перекрытие, а фиктивные аргументы не имеют ни атрибута 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

На практике я полагаю, что все современные компиляторы Фортрана используют вызов по ссылке вместо вызова по копии, поэтому проблема никогда не возникает.

Вызов-by-copy также используется в Objective-C под капотом (при неясных обстоятельствах ), но этот язык не имеет стандарта или спецификации;это просто определяется тем, что делает компилятор в этом году.Его текущее правило, кажется, состоит в том, что значения копируются обратно в фактические параметры, как они появляются в списке параметров слева направо, так что конечное значение 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
...