Постфиксный / Префиксный приоритет оператора и ассоциативность - PullRequest
1 голос
/ 24 июня 2019

Я запутался по поводу приоритета и ассоциативности операторов постфикса / префикса.

С одной стороны, когда я читаю книгу K & R, в ней говорится:

(* ф) ++

Круглые скобки необходимы в последнем примере; без них выражение будет увеличивать ip вместо того, на что оно указывает, потому что унарные операторы, такие как * и ++, ассоциируются справа налево.

Нет упоминания о разнице ассоциативности между постфиксными / префиксными операторами Оба относятся одинаково. В книге также говорится, что * и ++ имеют одинаковый приоритет.

С другой стороны, эта страница гласит:

1) Приоритет префикса ++ и * одинаков. Ассоциативность обоих справа налево.

2) Приоритет постфикса ++ выше, чем * и префикса ++. Ассоциативность postfix ++ слева направо.

Кому я должен доверять? Что-то изменилось с пересмотром C за эти годы?

Ответы [ 3 ]

3 голосов
/ 24 июня 2019

TL; DR : два описания говорят об одном и том же, используя одни и те же слова и символы с немного отличающимся значением.

С одной стороны, когда я читаю книгу K & R, в ней говорится:

(*ip)++

круглые скобки необходимы в последнем примере; без них выражение будет увеличивать IP вместо того, на что оно указывает, потому что унарные операторы типа * и ++ ассоциируются справа налево.

Никаких упоминаний о разнице ассоциативности между постфиксные / префиксные операторы. Оба относятся одинаково. Книга также утверждает, что * и ++ имеют одинаковый приоритет.

Непонятно, какую редакцию K & R вы читаете, но первая, по крайней мере, рассматривает префиксную и постфиксную версии операторов увеличения и уменьшения как один оператор каждый, причем эффекты зависят от того, предшествует или следует их операнд им.

С другой стороны, эта страница гласит:

1) Приоритет префикса ++ и * одинаков. Ассоциативность обоих справа налево.

2) Приоритет постфикса ++ выше, чем * и префикса ++. Ассоциативность postfix ++ слева направо.

Стандарт языка и большинство современных обработок описывают версии префикса и постфикса как различные операторы, неоднозначные по их положению относительно своего операнда. Остальная часть этого ответа объясняет, как это альтернативное описание того же самого.

Заметьте, что когда задействованы только унарные операторы, вопросы об ассоциативности возникают только между одним префиксом и одним постфиксным оператором с одинаковым приоритетом. Среди цепочки только префиксных или только постфиксных операций нет никакой двусмысленности в отношении того, как они ассоциируются. Например, учитывая - - x, вы не можете сознательно сгруппировать его как (- -) x. Единственная альтернатива - - (- x).

Далее обратите внимание, что все операторы с наивысшим приоритетом являются постфиксными унарными операторами, и что в K & R все операторы второго приоритета являются префиксными унарными операторами, кроме ambi-fix ++ и --. Применяя ассоциативность справа налево к операторам второго приоритета, устраняет неоднозначность только выражений с постфиксным ++ или -- и префиксным унарным оператором и делает это в пользу постфиксного оператора. Это эквивалентно современному подходу различения постфиксных и префиксных версий этих операторов и присвоения более высокого приоритета постфиксным версиям.

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

Что касается слева направо против ассоциативности справа налево, вопрос, опять же, спорный для уровня приоритета, содержащего только префиксные или только постфиксные операторы. Однако описание постфиксных операторов как ассоциирующих слева направо и префиксных операторов как ассоциированных справа налево согласуется с их семантическим порядком операций.

2 голосов
/ 24 июня 2019

Вы можете сослаться на стандарт C11 , хотя его раздел о приоритете немного сложен для понимания.См. Сек6.5.1.(сноска 85 гласит «Синтаксис определяет приоритет операторов при вычислении выражения, который совпадает с порядком основных подпунктов этого подпункта, причем сначала приоритет самый высокий.» )

По существу, постфиксные операторы имеют более высокий приоритет, чем префиксные, потому что они появляются в этом разделе ранее, 6.5.2.4 по сравнению с 6.5.3.1.Таким образом, K & R является правильным (не удивительно!), Что *ip++ означает *(ip++), что отличается от (*ip)++, однако его точка зрения об этом из-за ассоциативности немного вводит в заблуждение, я бы сказал.И точка № 2 сайта geeksforgeeks также верна.

1 голос
/ 24 июня 2019

@ GaryO ответ на месте! Postfix имеет более высокий приоритет, потому что они приходят раньше.

Вот небольшой тест для проверки работоспособности, чтобы убедить себя. Я сделал два целочисленных массива и указатель на начало каждого массива, затем запустил (* p) ++ и * p ++ по двум указателям. Я распечатал указатель и состояние массива до и после для справки.

#include <stdio.h>

#define PRINT_ARRS printf("a = {%d, %d, %d}\n", a[0], a[1], a[2]); \
printf("b = {%d, %d, %d}\n\n", b[0], b[1], b[2]); 

#define PRINT_PTRS printf("*p1 = a[%ld] = %d\n", p1 - a, *p1); \
printf("*p2 = b[%ld] = %d\n\n", p2 - b, *p2);

int main()
{
int a[3] = {1 , 1, 1}; 
int b[3] = {10,10, 10};

int *p1 = a;
int *p2 = b;


PRINT_ARRS
PRINT_PTRS

printf("(*p1)++: %d\n", (*p1)++);
printf("*p1++  : %d\n\n", *p2++);

PRINT_ARRS
PRINT_PTRS

}

Компиляция с gcc и запуск на моем компьютере приводит к:

a = {1, 1, 1}
b = {10, 10, 10}

*p1 = a[0] = 1
*p2 = b[0] = 10

(*p1)++: 1
*p2++  : 10

a = {2, 1, 1}
b = {10, 10, 10}

*p1 = a[0] = 2
*p2 = b[1] = 10

Вы можете видеть, что (*p1)++ увеличивает значение массива, а *p2++ увеличивает указатель.

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