Порядок операций для преинкремента и постинкремента в аргументе функции?
У меня есть немного кода C:
main()
{
int a=1;
void xyz(int,int);
xyz(++a,a++); //which Unary Operator is executed first, ++a or a++?
printf("%d",a);
}
void xyz(int x,int y)
{
printf("\n%d %d",x,y);
}
Функция xyz
имеет два переданных параметра, ++a
а также a++
, Может кто-нибудь объяснить последовательность операций, чтобы объяснить результат?
Приведенный выше код выводит "3 13" или "2 23" в зависимости от того, какой компилятор используется.
4 ответа
Ну, есть две вещи, которые следует рассмотреть с вашим примером кода:
- Порядок вычисления аргументов функции не определен, так что
++a
или жеa++
оценивается первым, зависит от реализации. - Изменение значения
a
более одного раза без точки последовательности между модификациями приводит к неопределенному поведению. Итак, результаты вашего кода не определены.
Если мы упростим ваш код и удалим неопределенное и неопределенное поведение, тогда мы можем ответить на вопрос:
void xyz(int x) { }
int a = 1;
xyz(a++); // 1 is passed to xyz, then a is incremented to be 2
int a = 1;
xyz(++a); // a is incremented to be 2, then that 2 is passed to xyz
Цитирую Кернигана и Ричи, глава 2.12:
Порядок, в котором оцениваются аргументы функции, не указан, поэтому оператор
printf("%d %d\n", ++n, power(2, n)); /* WRONG */
может давать разные результаты с разными компиляторами, в зависимости от того, увеличивается ли n перед вызовом power. Решение, конечно, состоит в том, чтобы написать
++n; printf("%d %d\n", n, power(2, n));
Вызовы функций, вложенные операторы присваивания, а также операторы увеличения и уменьшения вызывают `` побочные эффекты '' - некоторая переменная изменяется как побочный продукт оценки выражения. В любом выражении, связанном с побочными эффектами, могут быть тонкие зависимости от порядка обновления переменных, участвующих в выражении. Одна несчастная ситуация типична для утверждения
a[i] = i++;
Вопрос в том, является ли нижний индекс старым значением i или новым. Компиляторы могут интерпретировать это по-разному и генерировать разные ответы в зависимости от их интерпретации. Стандарт намеренно оставляет большинство таких вопросов не уточненными. Когда побочные эффекты (присвоение переменных) происходят внутри выражения, оставляется на усмотрение компилятора, поскольку наилучший порядок сильно зависит от архитектуры машины. (Стандарт определяет, что все побочные эффекты на аргументы вступают в силу до вызова функции, но это не поможет при вызове printf выше.) Мораль состоит в том, что написание кода, который зависит от порядка вычисления, является плохой практикой программирования в любой язык. Естественно, необходимо знать, чего следует избегать, но если вы не знаете, как они выполняются на разных машинах, у вас не будет соблазна воспользоваться конкретной реализацией.
Последовательность оценки унарного оператора для функции:
#include <stdio.h>
void xyz(int x, int y) {
printf("x:%d y:%d ", x, y);
}
main() {
int a;
a=1; xyz(++a, a); printf("a:%d\n", a);
a=1; xyz(a, a++); printf("a:%d\n", a);
a=1; xyz(++a, a++); printf("a:%d\n", a);
}
будет выводить
x:2 y:2 a:2
x:2 y:1 a:2
x:3 y:1 a:3
На моей системе. Это указывает на то, что второй параметр функции оценивается первым. Не стоит полагаться на порядок оценки параметров функции. Он не определен, поэтому будет отличаться в разных системах.
Хорошая работа по поиску изящного примера такого поведения, все же.
Для унитарных операторов есть преинкремент (++i) и постинкремент (i++). Для предварительного увеличения значение, которое будет увеличено, будет добавлено перед операцией. Например:
#include <iostream>
using namespace std;
void main()
{
int i = 0;
cout << ++i;
}
В этом случае выходные данные будут равны 1. Переменная 'i' была увеличена на значение 1 перед любыми другими операциями, например, 'cout << ++i'.
Теперь, если мы выполнили постинкремент в той же функции:
#include <iostream>
using namespace std;
void main()
{
int i = 0;
cout << i++;
}
Выход будет только 0. Это происходит потому, что приращение произойдет после операции. Но так как вы хотите знать о передаче их в качестве параметров, вот как это будет происходить:
#include <iostream>
using namespace std;
// Function Prototypes
void PrintNumbers(int, int);
void main()
{
int a = 0, b = 0;
PrintNumbers(++a, b++);
}
void PrintNumbers(int a, int b)
{
cout << "First number: " << a << endl;
cout << "Second number: " << b << endl;
}
При передаче этих переменных в качестве параметров, вывод будет:
First number: 1
Second number: 0
Надеюсь, это поможет!!