Указатель и правильная оценка выражения в C - PullRequest
4 голосов
/ 15 февраля 2011

У меня вопрос на языке C. Рассмотрим следующий код (это минимальный пример):

#include <stdio.h>

    int f(int**, int*);

    int main(int argc, char *argv[])
    {
      int *u = NULL, t1=0, t2=1;

      u = &t1;
      printf("t1 : %d\n", t1);
      printf("t2 : %d\n\n", t2);

      *u = 36;
      printf("t1 : %d\n", t1);
      printf("t2 : %d\n\n", t2);

      *u = f(&u, &t2);
      printf("t1 : %d\n", t1);
      printf("t2 : %d\n\n", t2);

      return 0;
    }

    int f(int** p, int* e){
      *p = e;
      return 24;
    }

Когда я запускаю эту программу, я получаю следующий результат:

t1 : 0
t2 : 1

t1 : 36
t2 : 1

t1 : 24
t2 : 1

Что меня удивляет, так это то, что левая часть выражения (т.е. * u):

*u = f(&u, &t2);

фиксируется перед обработкой функции f. На самом деле я ожидал следующего результата, так как функция f изменяет указатель u:

t1 : 0
t2 : 1

t1 : 36
t2 : 1

t1 : 36
t2 : 24

Это нормально? Я что-то пропустил в своем классе C?

Ответы [ 4 ]

5 голосов
/ 15 февраля 2011

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

6,5 / 3:

За исключением случаев, указанных далее (для вызовов функций (), &&, ||, ?: и операторов запятой), порядок вычисления подвыражений и порядок возникновения побочных эффектов имеют вид оба не указаны.

Несмотря на то, что в вызове функции есть точка последовательности, нет никакой гарантии, что функция вызывается до или после вычисления *u.

0 голосов
/ 15 февраля 2011

Эй, это не какие-либо АНОМАЛЬНЫЕ поведения, компилятор работает правильно.

*u = f(&u, &t2);

int f(int** p, int* e)
{
  *p = e;               // It means value of t2 gets copied into memory location pointed by u i.e t1
  return 24;            // Now this 24 would get stored/overwrite in memory location pointed by u i.e t1
}                       // Thus no change occurs in t2

Помните, что функция "f" вносит изменения только в VALUE при расположении памяти, указанном U, а не по адресууказал ты.

0 голосов
/ 15 февраля 2011

Когда вызывается функция, ячейка памяти, в которой будет храниться возвращаемое значение, фиксируется. Хотя вы меняете то, на что указывает u, но назначения (ячейка памяти), которые могут возникнуть при вызове функции, уже исправлены.

На самом деле, если вы попробуете

#include <stdio.h>

    int f(int**, int*);

    int main(int argc, char *argv[])
    {
      int *u = NULL, t1=0, t2=1;

      u = &t1;
      printf("t1 : %d\n", t1);
      printf("t2 : %d\n\n", t2);

      *u = 36;
      printf("t1 : %d\n", t1);
      printf("t2 : %d\n\n", t2);

      *u = f(&u, &t2);
      printf("t1 : %d\n", t1);
      printf("t2 : %d\n\n", t2);

      printf("u : %d\n\n", *u);

      return 0;
    }

    int f(int** p, int* e){
      *p = e;
      return 24;
    }

Вы получите

t1 : 0
t2 : 1

t1 : 36
t2 : 1

t1 : 24
t2 : 1

u : 1
0 голосов
/ 15 февраля 2011

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

Редактировать: Прочитав другой ответ, я решил опубликовать свои спецификации. Я использую 64-разрядную версию Visual Studio 2010, 64-разрядную версию Windows 7 Ultimate.

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