2010-06-07 4 views
9

У меня есть некоторый код 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» в зависимости от того, какой компилятор используется.

+1

Возможно, было бы лучше, если бы вы использовали разные переменные в вашей примерной программе. Кроме того, вы должны поместить «\ n» * после * значения, которые вы печатаете, а не раньше. В настоящее время это будет напечатать «2 23» – DevinB

+0

Вам следует попробовать что-то более ясное. Этот синтаксис довольно странный для человека. Сделайте код простым, не пытайтесь писать сложные вещи. – INS

ответ

26

Ну, есть две вещи, чтобы рассмотреть с примерами кода:

  1. Порядок вычисления аргументов функции не определен, так ли ++a или a++ оценивается первым зависит от конкретной реализации.
  2. Изменение значения 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 
+0

Верно ли во втором случае, что 'a' обновляется до вызова функции? Я знаю, что результат выражения * '++ a' равен 2, который передается в' xyz', но я понимаю, что побочный эффект необязательно может быть применен до вызова функции. –

+2

@John: Да: после оценки всех аргументов функции есть точка последовательности, но до вызова функции. –

9

Цитирование Керниган & Ritchie, Глава 2.12:

Порядок аргументы функции не указаны, поэтому заявление

printf("%d %d\n", ++n, power(2, n)); /* WRONG */ 

может производить разные результаты с помощью различных компиляторов, в зависимости от ли n увеличивается до выключения питания . Решение, конечно, писать

++n; 
printf("%d %d\n", n, power(2, n)); 

вызовов функций, вложенным назначение заявления и приращение и операторы декремента вызывают `` побочные эффектов «» - некоторые переменный изменяются в качестве побочного продукта оценки выражение. В любом выражении с участием побочных эффектов может быть тонких зависимостей порядка , переменные, участвующие в выражении , обновляются. Одна несчастная ситуация характерна заявление

a[i] = i++; 

вопрос является индексом ли старое значение I или новый. Компиляторы могут интерпретировать это в различными способами и генерировать разные ответы в зависимости от их интерпретации . Стандарт умышленно оставляет большинство таких вопросов неуказанный. Когда возникают побочные эффекты (присвоение переменных) в выражении остается на усмотрение компилятора , поскольку наилучший порядок сильно зависит от архитектуры машины .(Стандарт имеет указать, что все побочные эффекты на аргументов вступают в силу до того, как функции вызывается, но это не помощи в вызове PRINTF выше). Морали, что написание кода, который зависит от порядка оценки является плохой практикой программирования на любом языке . Естественно, необходимо знать, чего не следует избегать, но если вы не знаете, как это делается на различных машинах, вы не соблазнитесь , чтобы воспользоваться конкретной реализацией .

2

Унарное последовательность оценки оператора для функции:

#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 

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

Хорошая работа по поиску отличного примера такого поведения.

-1

Для юниорских операторов есть предварительный приращение (++ i) и пост-инкремент (i ++). Для предварительного приращения значение, которое должно быть увеличено, будет добавлено до операции. Например:

#include <iostream> 
using namespace std; 

void main() 
{ 
    int i = 0; 
    cout << ++i; 
} 

В этом случае выходной сигнал будет 1. Переменная «я» был увеличен на величину от 1 до каких-либо других операций, т.е. «COUT < < ++ я».

Теперь, если мы сделали пост-приращение в одной и той же функции:

#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 

Я надеюсь, что это помогает !!