Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > Borland C++ Builder/Turbo C++ Explorer > Ошибка в изменении адреса


Автор: Славян 21.12.19, 13:39
Есть свой старый код:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    void func( unsigned long *a)
    {
        ...
        ((unsigned short*)a)++; // здесь выдаёт "Lvalue required"
        ...
    }
Раньше (в какой-то BCB2006 или около того) компилировалось, сейчас (RAD-XE8) выдаёт ошибку E2277. Почему? Как поправить?

Автор: Qraizer 21.12.19, 16:11
Потому что операция преобразования unsigned long* в unsigned short* создаёт новый временный объект, не связанный с исходным a. Применение операции постинкремента к временному объекту бессмысленна, т.к. её результатом является новый временный объект с ещё не изменённым значением, а инкремент выполняется на предыдущем объекте, который невозможно никак использовать, на то он и временный.
Если раньше компилировалось, значит компилятор нарушал Стандарт. Возможно, он не создавал временного объекта при касте типа указателя. Возможно, он плевать котел на бессмысленность постинкремента на rvalue вместо lvalue. В любом случае код и ранее был неправилен, а как правильно, надо спросить у его автора. Возможно он имел в виду
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    ++*(unsigned short**)&a;
что всё равно не сильно отличается от бреда.

Автор: Славян 21.12.19, 18:04
1. Не знал, что (unsigned short*) - операция. Считал, что это лишь способ рассказать компилятору, что переменная=указатель указывает на нечто иное, и только то.
2. Да, в принципе ваша строка делает то, что и требовалось, но читаемость, конечно, сильно пострадает от этого. :yes-sad:

А всего лишь хотелось изменить=подвинуть на 2 [байта] указатель... :wall:

Автор: ЫукпШ 21.12.19, 19:49
Цитата Славян @
А всего лишь хотелось изменить=подвинуть на 2 [байта] указатель... :wall:

Так подвинь:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    void func(unsigned long *a)
    {
    //       ...
         unsigned short aa = *((unsigned short*)a+1);
    //
         unsigned short* pa = ((unsigned short*)a+1);
    //       ...
         unsigned short* pa = (unsigned short*)a;
         pa++;
         unsigned short aa = *pa;
    }

Автор: Qraizer 21.12.19, 21:55
Цитата Славян @
А всего лишь хотелось изменить=подвинуть на 2 [байта] указатель...
В таком случае unsiged long* либо был невыровненным, либо стал таковым.

Автор: Славян 22.12.19, 06:27
Цитата ЫукпШ @
Так подвинь:
...
Тут заводится доп. переменная, а хочется компактно, изящно и лаконично, как было раньше... :'(

Цитата Qraizer @
В таком случае unsiged long* либо был невыровненным, либо стал таковым.
Выравнивание - "головная" боль машины/архитектуры. Считаю идеологически неправильным переносить её на компилятор с последующим неким переносом её на программиста. :oops:

Автор: Dushevny 22.12.19, 10:14
Цитата Славян @
А всего лишь хотелось изменить=подвинуть на 2 [байта] указатель...

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    a = (unsigned long *)(void *)((unsigned short *)a + 1);
Приведение к (void *) - чтобы подавить жалобы компилятора на невыровненность получившегося указателя..

Автор: Славян 22.12.19, 11:31
Да, можно и так. Но метод Qraizer'а всё же несколько краше. :blush:

Автор: ЫукпШ 22.12.19, 12:45
Цитата Dushevny @
Цитата Славян @
А всего лишь хотелось изменить=подвинуть на 2 [байта] указатель...

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    a = (unsigned long *)(void *)((unsigned short *)a + 1);
Приведение к (void *) - чтобы подавить жалобы компилятора на невыровненность получившегося указателя..

Если речь идёт об этом, тогда лучше рассмотреть
правильность программы вообще.
Увеличить на 2 байта указатель unsigned long * - это
значит выходить за границы переменной unsigned long.
(Увеличить unsigned short * - это ещё объяснимо.)
---
Подозрительно выглядит сам алгоритм и ругательства
компилятора выглядят совершенно к месту.
Хотя он это делает по другому поводу.

Автор: Qraizer 22.12.19, 15:23
Цитата Славян @
Выравнивание - "головная" боль машины/архитектуры. Считаю идеологически неправильным переносить её на компилятор с последующим неким переносом её на программиста.
Первая фраза абсолютно верна. Компилятор всегда обеспечивает правильное выравнивание для данных ему структур данных. Вторая прямо противоречит первой. Код явным образом насильно заставляет компилятор отойти от его правил. Посему сваливать на него ответственность за нарушение выравнивания... очень мягко говоря, некорректно. Если тебя вытолкнут на красный в спину, виноват будешь ты, да?

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)