Приоритет операторов в данных выражениях

Выражение 1: *p++; где p - указатель на целое число.

p будет увеличиваться сначала, а затем значение, к которому он указывает, берется из-за ассоциативности (справа налево). Правильно?

Выражение 2: a=*p++; где p - указатель на целое число.

Сначала берется значение p, а затем присваивается a, а затем p увеличивается из-за пост-приращения. Правильно?

Ответ 1

Прежде всего, позвольте мне сказать вам, что ни ассоциативность и порядок оценки на самом деле имеет значение здесь. Это все о приоритете оператора. Рассмотрим сначала определения. (акцент мой)

  • Приоритет. В математике и компьютерном программировании порядок операций (или приоритет оператора) набор правил, которые отражают соглашения о , какие процедуры выполнять сначала, чтобы оценить данное математическое выражение.

  • Associativity: на языках программирования ассоциативность (или фиксированность) оператора свойство, которое определяет, как операторы с одинаковым приоритетом сгруппированы в отсутствие круглых скобок.

  • Порядок оценки: порядок оценки операндов любого оператора C, включая заказ оценки аргументов функции в выражении функции-вызова, а порядок оценки подвыражений в любом выражении неуточнен, за исключением нескольких случаев. В основном существуют два типа оценки: a) вычисление значения b) побочный эффект.


Пост-инкремент имеет более высокий приоритет, поэтому сначала он будет оценен.

Теперь так получилось, что приращение значения является побочным эффектом операции, которая секвенируется после "вычисления значений". Таким образом, результат вычисления значения будет неизменным значением операнда p (который снова здесь разыменовывается из-за использования оператора *), а затем происходит приращение.

Цитата C11, глава §6.5.2.4,

Результатом оператора postfix ++ является значение операнда. В качестве побочного эффекта значение объекта операнда увеличивается (то есть значение 1 соответствующего типа добавлено к нему). См. Обсуждения аддитивных операторов и составное назначение для информацию об ограничениях, типах и преобразованиях и о воздействии операций на указатели. Вычисление значения результата секвенируется перед побочным эффектом обновление сохраненного значения операнда. [.....]

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

Если вы используете первое выражение "as-is", ваш компилятор должен выдать предупреждение о неиспользуемом значении.

Ответ 2

Операторы Postfix имеют более высокие приоритеты, чем унарные операторы.

Таким образом, это выражение

*p++

эквивалентно выражению

*( p++ )

В соответствии со стандартом C (6.5.2.4 операторы приращения и уменьшения постинфайма)

2 Результат оператора postfix ++ - это значение Операнд. В качестве побочного эффекта значение объекта операнда (то есть значение 1 соответствующего типа добавляется к Это). См. Обсуждения аддитивных операторов и составное назначение для информации о ограничениях, типах и преобразованиях и эффектах операций над указателями. Вычисление значения результата секвенированы перед побочным эффектом обновления сохраненного значения операнд.

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

Что касается унарного оператора, то (6.5.3.2 Операторы адреса и косвенности)

4 Оператор унарного * обозначает косвенность. Если операнд указывает на функция, результат - обозначение функции; если он указывает на объект, результатом будет lvalue, обозначающий объект. Если операнд имеет тип '' указатель на тип, результат имеет тип типа ''. Если неверное значение было присвоено указателю, поведение унарный * оператор undefined

Итак, конечный результат выражения

*( p++ )

- это значение объекта, на которое указывает указатель p, который также увеличивается из-за побочного эффекта. Это значение присваивается переменной a в инструкции

a=*p++;

Например, если существуют следующие объявления

char s[] = "Hello";
char *p = s;
char a;

то после этого утверждения

a = *p++;

объект a будет иметь символ 'H', а указатель p будет указывать на второй символ массива s, который соответствует символу 'e'.

Ответ 3

Ассоциативность здесь не имеет отношения. Ассоциативность имеет значение только тогда, когда у вас есть соседние операторы с одинаковым приоритетом. Но в этом случае ++ имеет более высокий приоритет, чем *, поэтому имеет значение только приоритет. Из-за приоритета выражение эквивалентно выражению:

*(p++)

Так как он использует post-increment, p++ увеличивает указатель, но выражение возвращает значение указателя перед его увеличением. Затем косвенное использование использует этот оригинальный указатель для извлечения значения. Это эффективно эквивалентно:

int *temp = p;
p = p + 1;
*temp;

Второе выражение одно и то же, за исключением того, что оно присваивает значение другой переменной, так что последний оператор становится:

a = *temp;

Ответ 4

Выражение

*p++

эквивалентно

*(p++)

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

и выражение

a=*p++

по той же причине эквивалентна

a=*(p++)

В обоих случаях выражение p++ оценивается как p.

Ответ 5

  • v = i++;: i возвращается в операцию равенства и затем назначается v. Впоследствии i увеличивается (EDIT: технически это не обязательно выполняется в этом порядке). Таким образом, v имеет старое значение i. Я помню это так: ++ записывается последним и, следовательно, бывает последним.
  • v = ++i;: i увеличивается, а затем возвращается для назначения v. v и i имеют одинаковое значение.
  • Если вы не используете возвращаемое значение, они делают то же самое (хотя в некоторых случаях разные реализации могут принести разную производительность). Например. in для циклов, for(int i=0; i<n; i++) совпадает с for(int i=0; i<n; ++i). Последнее иногда автоматически предпочтительнее, потому что оно имеет тенденцию быть быстрее для некоторых объектов.
  • * имеет более низкий приоритет, чем ++, поэтому *p++ совпадает с *(p++). Таким образом, в этом случае p возвращается в *, который разыгрывает его. Затем адрес в p увеличивается на один элемент. *++p сначала увеличивает адрес p, затем разыгрывает его.
  • v = (*p)++; устанавливает v равным старому значению, на которое указывает p, а затем увеличивает его, а v = ++(*p); увеличивает значение, на которое указывает p, а затем устанавливает v равным ему. Адрес в p не изменяется.

Пример: если,

int a[] = {1,2};

затем

int v = *a++;

и

int v = *++a;

оба будут уклоняться от a, но в первом случае v будет 1, а во втором - 2.

Ответ 6

*p++; где p - указатель на целое число.

p будет увеличиваться сначала, а затем значение, к которому он указывает, берется из-за ассоциативности (справа налево). Правильно?

Нет. В post-increment значение копируется во временное (rvalue), тогда значение l увеличивается в качестве побочного эффекта.

a=*p++; где p - указатель на целое число.

Сначала берется значение p, а затем присваивается a, а затем p увеличивается из-за пост-приращения. Правильно?

Нет, это тоже не правильно. Инкремент p может произойти до записи в a. Важно то, что значение, хранящееся в a, было загружено с использованием временной копии предыдущего значения p.

Выполняется ли эта выборка памяти до того, как запись в память с новым значением p не указана, а любой код, который опирается на порядок, - это поведение undefined.

Любая из этих последовательностей разрешена:

  • Скопируйте p во временное THEN increment p, THEN значение нагрузки по адресу, указанному во временном THEN, сохранит загруженное значение до a
  • Скопируйте p во временное THEN значение нагрузки по адресу, указанному во временном (это значение будет помещено во временное) THEN increment p THEN сохраните загруженное значение до a
  • Скопируйте p во временное THEN значение нагрузки по адресу, указанному во временном THEN, сохраните загруженное значение до a THEN increment p

Вот два примера кода, которые являются undefined, потому что они полагаются на порядок побочных эффектов:

int a = 7;
int *p = &a;
a = (*p)++;  // undefined behavior, do not do this!!

void *pv;
pv = &pv;
void *pv2;
pv2 = *(pv++);  // undefined behavior, do not do this!!!

Скобки не создают точку последовательности (или упорядочиваются до отношения, в новой редакции). Версия кода с круглыми скобками равно как undefined как версия без.