LINUX.ORG.RU

Приоритет операций разыменования и постфиксного декремента в Си

 


1

3

Добрый день! Есть участок кода:

#include <stdio.h>
int x = 4, y = 2;
int a[5] = { 3, 2, 1 };
int f (int *p, int *q) {
    static int a = 3;

    if (--a)
        return *p-- += *q--;
    return *q++ -= *p++;
}
int main(void)
{
    int x = 2 * a[--y], b = 0;

    for (int y = x; y >= b; --y, ++x)
        b = f (a + y, a + b);
    printf("%d %d %d %d %d\n", a[0], a[1], a[2], a[3], a[4]);
    printf( "%d %d\n", x, y);
}
При первом вызове функции f она вызывается с аргументами (a+4,a), и, как я понял, в строке return *p-- += *q--

*q-- рассматривается как (*q)--, а не как *(q--), во-первых, потому что *(q--), в моём представлении, дал бы a[-1] и сегфолт, во-вторых, потому, что я попробовал добавить перед этой строкой printf(«%d», *q--), и получил вполне себе int, и остальной вывод программы поменялся.

Я не могу понять, почему всё происходит именно так. Я просмотрел несколько разных источников. Одни говорят, что * и постфиксный декремент имеют одинаковый приоритет и ассоциируются справа налево, другие - что постфиксный декремент имеет более высокий приоритет, чем разыменование. В обоих случаях, как я понимаю, должно было бы произойти *(q--), но это не так. Пожалуйста, подскажите, почему так происходит. Заранее спасибо.

★★

Последнее исправление: Norong (всего исправлений: 1)

Ответ на: комментарий от anonymous

Тьфу. Я, кажется, натупил. *(q--) не даст сегфолта, потому что декремент - постфиксный. Но тогда почему от добавления printf("%d", *q--) прямо над этой строкой меняется итоговый вывод программы? Получается, что декремент происходит на аргументом, который передан по значению? Тогда ничего измениться не должно, вроде.

Norong ★★
() автор топика
Последнее исправление: Norong (всего исправлений: 2)
Ответ на: комментарий от Norong

Если не изменяет память, то постфиксные инкремент и декремент возвращают временный объект, который, в таком применении, благополучно исчезает в стране мальборо. А вот разыменовываешь ты уже оригинальное значение р. Ради интереса попробуй такое:
printf(«%d», *q);
printf(«%d», *q--);

baldman88
()
Последнее исправление: baldman88 (всего исправлений: 2)

Эта строка:

return *p-- += *q--;
семантически эквивалентна такому коду:
int *const tmp_p = p;
int *const tmp_q = q;
p -= 1;
q -= 1;
return *tmp_p += *tmp_q;
*q-- разбирается именно как *(q--), но q как бы «раздваивается» в выражении. Значение указанной переменной меняется, но в выражении используется прошлое значение. В этом вся суть пост-операций. Менять локальные переменные тут толку нет.

xaizek ★★★★★
()
Последнее исправление: xaizek (всего исправлений: 1)

*p-- += *q--

Типичное i++ + i++, забавно, что лорОВЦЫ пытаются разбить это на какие-то «элементарные» операции

anonymous
()
Ответ на: комментарий от anonymous

Хотя, не, всё вроде ок, но пишут так только мудаки, ололо

anonymous
()
Ответ на: комментарий от Deleted

Коллоквиум по алгоритмам и алгоритмическим языкам, задание в том, чтобы в голове распарсить, что выдаст этот код. Будь он читаемым - было бы не интересно.

Norong ★★
() автор топика
Последнее исправление: Norong (всего исправлений: 1)

а за локально-глобальный int x вообще убивать надо

ananas ★★★★★
()
Ответ на: комментарий от Aswed

Строчки экономят, вдруг закончатся.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.