2016-03-01 7 views
2

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

Когда у нас есть указатель на C и используйте его в инструкции post increment, приращение сообщения всегда будет происходить после того, как строка кода будет разрешена.

int array[6] = {0,1,2,3,4,5}; 
int* p = array; 
printf("%d", *p++); // This will output 0 then increment pointer to 1 

выход:

0 

Очень простые вещи. Теперь вот где я получаю немного диссонанса в информации, которую люди рассказывают мне и моему собственному опыту.

// Same code as Before 
int array[0] = {0,1,2,3,4,5}; 
int* p = array; 
printf("%d", *(p++)); // Issue with this line 

выход:

0 

Теперь, когда я бегу, что второй вариант кода Результатом является то, что он будет выводить 0 THEN увеличивает значение указателя. Порядок действий, подразумеваемый скобками, по-видимому, нарушен. Однако некоторые другие ответы на этом сайте говорят мне, что правильная вещь, которая должна произойти, заключается в том, что приращение должно произойти до разыменования. Поэтому, я думаю, мой вопрос заключается в следующем: правильно ли я понимаю? Операторы post increment всегда выполняются в конце строки?

Дополнительная информация:

я компиляции с GCC на Linux Mint с GCC версии 4.8.4 убунту

Я также проверил это на GCC на Debian с версией Debian 4.7.2

+0

_ Порядок операций, подразумеваемых скобками_ - '(' и ')', является скобкой, а не скобками. Я предполагаю, что это то, о чем вы говорите в контексте. Правильная терминология необходима для хорошего общения. – mah

+1

Действительно ли это компиляция без ошибок? Инициализация вашего массива неверна, а ваши косые черты комментариев неверны. – Rob

+0

Я сделал явные исправления к сообщению. Должен ли я также зафиксировать объявление массива? –

ответ

4

OP «Результат состоит в том, что он выдает 0 THEN, увеличивает указатель». не является правильным.

Постфикс приращения возвращает значение указателя. Рассмотрим это значение как копию исходного значения указателя. Указатель увеличивается, что не влияет на копию.

Результатом оператора postfix ++ является значение операнда. В качестве побочного эффекта значение объекта операнда увеличивается. ... C11dr 6.5.2.4 2

Затем копия указателя отменена и возвращает 0. То есть функциональный последовательность событий.

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

«конец строки» не участвует в коде. Это очень важно в конце выражения.

+0

* Это конец выражения, который важен * ... не совсем для этого обсуждения, точки последовательности важны. – chqrlie

+0

@chqrlie Согласитесь, оба момента. – chux

+0

проклятый, отличный ответ, который сейчас так много имеет смысл. Поэтому оператор ++ фактически возвращает значение операнда.Но значение операнда фактически увеличивается. Итак, если это так, это означает, что такое сравнение всегда было бы ложным? if (i ++ == 1 && i == 1); , но if (i == 1 && i ++ == 1); может возвратить true? – user2601592

2

Там нет разницы в значении между *p++ и *(p++).

Это связано с тем, что операторы постфиксатора имеют более высокий приоритет, чем унарные операторы.

Оба эти выражения означают, что «p увеличивается, а его предыдущее значение разыменовывается».

Если вы хотите увеличить объект, на который ссылается указатель, вам необходимо переопределить приоритет, написав (*p)++.

Никакая версия вашего кода не может выдавать выходные данные и затем приращение p. Причина в том, что p увеличивается в выражении аргумента , который производит значение, которое передается в printf. В C точка последовательности возникает непосредственно перед вызовом функции. Таким образом, новое значение p должно оседать до выполнения printf. И выход не может произойти до тех пор, пока не вызывается printf.

Теперь вы должны взять вышеуказанное с небольшим количеством соли. Так как p - локальная переменная, ее изменение не является внешне видимым эффектом. Если новое значение p нигде не используется, приращение можно полностью оптимизировать. Но предположим, что у нас был файл int * volatile p; в области файлов, и вместо этого он использовался. Тогда выражение printf("...", *p++) должно увеличивать p до того, как будет вызываться printf.

+0

Постерическое приращение является унарным оператором – nicomp

+0

@nicomp Действительно, в компьютерная наука, которая верна, и хорошо, что вы обратили внимание в школе. Однако в терминологии ISO C мы имеем «унарные выражения» и «постфиксные выражения». См. C99 6.5.2 «Операторы Postfix» и 6.5.3 «Унарные выражения». Значительное значение «унарного оператора» в C состоит в том, что он является одним из возможных операторов в унарном выражении, играя роль, описанную в этой части грамматики (где она появляется слева). – Kaz

+0

Благодарю вас за подтверждение. Отныне я буду говорить только по терминологии ISO C. – nicomp

0

Вот мой пример. Давайте проигнорируем функцию printf и упростим ситуацию.

Если бы мы сказали

int i; 
int p=0; 
i = p++; 

Тогда я был бы равен нулю, поскольку р была равна нулю, но теперь р было увеличивается на единицу; поэтому теперь я все равно равен нулю, а p равен 1.

Игнорирование объявлений i и p как целых чисел, если мы обертываем это, как в примере, i = *(p++), тогда происходит одно и то же действие, но теперь я вижу значение, указанное at by p, которое имеет значение 0. Однако значение p теперь увеличилось на единицу.

+2

Ваше объяснение добавляет путаницу, смешивая типы 'int' и' int * 'для' p'. Почему бы просто не сказать, что 'i = * (p ++)' эквивалентно '(i = * p, p = p + 1, i)' – chqrlie

+0

@chqrlie Каждое объяснение должно быть как можно более простым. – Rob

+0

действительно! моя вписывается в 1-строчный комментарий ';-)' – chqrlie

2

Выражение p++ имеет результат (величина p до приращения) и побочный эффект в (значение p обновляется, чтобы указывать на следующий объект типа int).

Постфикс ++ имеет более высокий приоритет, чем одинарный *, поэтому *p++ уже обрабатываются как *(p++); вы не увидите различий в поведении между этими двумя формами. IOW, оператор разыменования применяется к результату от p++; линия

printf("%d", *p++); 

является примерно эквивалентно

printf("%d", *p); 
p++; 

с оговоркой, что p фактически будет обновляться до вызова printf .

Однако (*p)++будет быть другим; вместо увеличения указателя вы увеличиваете значение pуказывает на.


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