C #: порядок оценки функции (против C) - PullRequest
5 голосов
/ 01 августа 2009

Возьмите следующий код C ( K & R стр. 77 ):

push(pop() - pop()); /* WRONG */

В книге говорится, что, поскольку - и / не являются коммутативными операторами, необходим порядок, в котором оцениваются функции 2 pop (очевидно, чтобы получить правильный результат) ... и таким образом сначала поместить результат первой функции в переменную, а затем продолжить арифметику, например:

op2 = pop();
push(op2 - pop());

Очевидно, это потому, что компилятор не может гарантировать, в каком порядке будут оцениваться функции (... почему?)


Мой вопрос: C # делает то же самое? как, я должен беспокоиться о такого рода вещи при работе с C #? и в этом отношении любой другой язык более высокого уровня?

Ответы [ 8 ]

11 голосов
/ 01 августа 2009

В C # слева направо: http://blogs.msdn.com/oldnewthing/archive/2007/08/14/4374222.aspx


Re: C ++ order

Очевидно, это потому, что компилятор не может гарантировать, в каком порядке будут оцениваться функции (... почему?)

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

5 голосов
/ 01 августа 2009

Чтобы ответить на ваш вопрос о том, почему C не определяет порядок операций, просто потому, что изобретатели C решили, что было бы полезно дать разработчикам компиляторов возможность оптимизировать оценку выражений. Они также решили, что это более ценно, чем дать программистам уверенность в оценке выражений.

Помните, что когда C изначально разрабатывался, машины были гораздо менее способными, чем сегодня, и было больше интереса предоставить компиляторам возможность для оптимизации. Сегодня более безопасному, более предсказуемому коду часто придавался больший вес.

2 голосов
/ 01 августа 2009

Нет, C # не делает то же самое. Он не использует границы оценки так же, как C, где порядок выполнения между границами не определен. Выражение вычисляется слева направо, как и следовало ожидать.

Если вы когда-либо не уверены в порядке выполнения или хотите сделать код более понятным, вы должны использовать локальную переменную для промежуточного результата. Локальные переменные очень дешевы в размещении, поскольку они размещаются в стеке, и в некоторых случаях компилятор даже может поместить переменную в регистр, чтобы она вообще не выделялась. Кроме того, в зависимости от того, как выглядит выражение, компилятору может понадобиться использовать локальную переменную для сохранения результата intermediade.

2 голосов
/ 01 августа 2009

С Невероятные приключения в кодировании: приоритет против ассоциативности против порядка :

Еще один способ взглянуть на это состоит в том, что правило в C # - это не «сначала сделать круглые скобки», а вместо того, чтобы заключить все в скобки, затем рекурсивно применить правило «вычислить левую сторону, затем оценить правую сторону, а затем выполнить операцию». ».

1 голос
/ 01 августа 2009

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

Это не совсем правильно. K & R допускает перестановку коммутативных операторов ( покончено с ANSI C ). Поскольку suibtraction является не коммутативным, оно не переставляется ... по этому правилу, по крайней мере.

(Un) к счастью, C также не не определяет порядок вычисления (за пределами довольно небольшая область действия ) - что означает компилятор может вызывать эти функции в любом порядке (при условии, что результат pop() - pop() полностью оценен перед вызовом push())

Что, в данном случае, приводит к той же проблеме, но по другой причине.

1 голос
/ 01 августа 2009

Порядок оценки четко определен в C # во всех случаях и слева направо. Из спецификации языка C # (§7.3):

Порядок вычисления операторов в выражении определяется приоритетом и ассоциативностью операторов (§7.2.1). Операнды в выражении оцениваются слева направо. Например, в F (i) + G (i ++) * H (i) метод F вызывается с использованием старого значения i, затем метод G вызывается со старым значением i и, наконец, вызывается метод H с новым значением я. Это отдельно от приоритета оператора и не связано с ним

В случае C ++ порядок не может быть определен; это то, что разрешение порядка быть неопределенным позволяет компилятору лучше оптимизировать код.

0 голосов
/ 01 августа 2009

Цвет меня удивил, но, видимо, C # делает «правильную» вещь и оценивает слева направо:

void Main()
{
    Console.WriteLine(Pop() - Pop()); // Prints -1
}

// Define other methods and classes here
bool switchVar = true;
int Pop()
{
    int ret;
    if (switchVar)
        ret = 1;
    else
        ret = 2;
    switchVar = !switchVar;

    return ret;
}
0 голосов
/ 01 августа 2009

Я считаю, что в C # список аргументов оценивается по порядку слева направо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...