Вопросы по С/С++ (СИ)

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Аватара пользователя
IM1
Грызет канифоль
Сообщения: 268
Зарегистрирован: Вт фев 16, 2010 12:10:38
Откуда: Воронеж, Россия

Re: Вопросы по С/С++ (СИ)

Сообщение IM1 »

Аlex писал(а):Вообще не понятно, почему он обрезает эту строку, хотя бы инкремент оставил бы.
Эт точно. Такое ощущение, что паршивец живет какой-то своей жизнью.
Постоянно слежу за ним по коду и (если требуется) наставляю на путь истинный при помощи volatile.

ПС
Может я и не прав, т.к. Си занимаюсь недавно. Но конечно - это мощь по сравнению с ассемблером, просто бульдозер какой-то :shock:
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: Вопросы по С/С++ (СИ)

Сообщение shads »

ibiza11 писал(а):
Надо еще в 6-ке проверить, как себя вести будет такое построение.....
Можете не проверять, я проверял в Keil MDK ARM - компилятор интерпретирует Вашу запись аналогично 4ой студии.
А меня прям любопытство распирает проверить.... и проверил таки.....
Хотя результат такой же, НО... программеры таки исправились, и теперь компилятор кажет предупреждение: "operation on 'pMassiv' may be undefined"
Когда тыкаеш на варнинг, кажет сюда.....

Изображение



ЗЫ Значит в 4-ке все таки недоработка (нет предупреждения о возможных проблемах).....
Вложения
pg1.png
(6.64 КБ) 690 скачиваний
Последний раз редактировалось shads Вт мар 19, 2013 14:25:07, всего редактировалось 3 раза.
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение ibiza11 »

Аlex писал(а):volatile как раз и нужен для того, что бы сказать компилятору, что он "не прав" и не должен оптимизировать мысли программиста.
согласен, но в данном случае горе-программист, а не горе-компилятор. Я уже писал Выше, как следует делать правильно.
Ставим плюсы: )
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: Вопросы по С/С++ (СИ)

Сообщение Kavka »

IM1 писал(а):
Аlex писал(а):Вообще не понятно, почему он обрезает эту строку, хотя бы инкремент оставил бы.
Эт точно. Такое ощущение, что паршивец живет какой-то своей жизнью.

Я чуть выше ответил про инкремент.
Иначе, компилируйте с отключенной оптимизацией ( -O0 ) и всё будет на своих местах. :))

ibiza11 писал(а):Я уже писал Выше, как следует делать правильно.
Опрередил! :beer:
Последний раз редактировалось Kavka Вт мар 19, 2013 14:19:17, всего редактировалось 1 раз.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: Вопросы по С/С++ (СИ)

Сообщение shads »

ibiza11 писал(а):
shads писал(а):ЗЫЗЫ В общем вывод: нельзя в сравнении использовать один указатель больше одного раза..... правильный вывод?
Неправильный вывод
вот пример, который будет работать:

Код: Выделить всё

if (*pIrNecData == *(pIrNecData-1))
    {.....}  
Это да..... ато я чет на пре\постдекрементах зациклился, а такой вариант от злости даже не вспомнил.....
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение Аlex »

но в данном случае горе-программист
Возможно. Но Ваш пример, который выше, нельзя назвать правильной альтернативой, т.к. pIrNecData-1 не эквивалентно pIrNecData--.

Компилятор это делает потому, что дальше эта переменная нигде не используется.
Тут согласен. Но, это было бы при постинкременте. Всё-таки мне, например, интересно почему он обрезает условие... Либо тут действительно ошибка, которую мы не видим, либо мания оптимизатора, превращённая в глюк.
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: Вопросы по С/С++ (СИ)

Сообщение shads »

Аlex писал(а):Всё-таки мне, например, интересно почему он обрезает условие... Либо тут действительно ошибка, которую мы не видим, либо мания оптимизатора, превращённая в глюк.
Думаю (насчет того что в условии не выполняется четко указанная последовательность пред\пост декрементов) это техническое ограничение реализации алгоритма программы..... Видимо писатели компилятора, посчитали неоправданным, усложнение компилятора за счет реализации всех возможных и невозможных комбинаций текста программы..... Да все их и не возможно предусмотреть за раз. Потом пользователи постепенно выявляют такие глюки, и вот результат, теперь 6-ка хотя бы предупреждение выдает.....

ЗЫ Больше чем на 50% уверен, что на компиляторах большого брата, именно такой проблемы нет.... Как думаете?
Последний раз редактировалось shads Вт мар 19, 2013 14:52:46, всего редактировалось 1 раз.
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение Аlex »

shads писал(а):и теперь компилятор кажет предупреждение: "operation on 'pMassiv' may be undefined"
Когда тыкаеш на варнинг, кажет сюда.....
Изображение
Вообще, это должна быть ошибка. На картинке нет определения pMassiv, как в предыдущих кусках кода.
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: Вопросы по С/С++ (СИ)

Сообщение shads »

Да не, оно определено глобально, до int main (void)..... Это просто я урезал кусок для показа.


ЗЫ Кстати, на картинке четко видно, что компиль указывает на 2-й предекремент.....
Т.е. первый он все таки делает перед выполнением сравнения, а вот второй (на который мы думаем, что он еше раз его должен сделать) он предупреждает что он не сделает так как мы ожидаем..... (т.е. практически извиняется..... что не оправдал наших надежд)
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение ibiza11 »

Kavka писал(а):Думаю, что многие будут удивлены результатами этих строк (например для a=5).
x = (++a) + (++a);
x = (a++) + (a++);
Однако всё строго по стандарту.
:beer:
вот пример специально для неверующих:

Код: Выделить всё

#include <stdio.h>
#include <stdlib.h>

int main() {
   unsigned char x = 0, a = 1;   
   printf
("Execute: x = (++%d) + (++%d)\n", a, a);
   x = (++a) + (++a);
   printf("Result : x = %d, a = %d \n\n", x, a);
   
   x 
= 0;
   a = 1;  
   printf
("Execute: x = (%d++) + (%d++)\n", a, a);
   x = (a++) + (a++);
   printf("Result : x = %d, a = %d \n\n", x, a);   
} 

Проверить можно здесь.
результат компиляции:
stdout:
Execute: x = (++1) + (++1)
Result : x = 6, a = 3

Execute: x = (1++) + (1++)
Result : x = 2, a = 3

Как можно заметить, обе операции пред/пост инкремента выполняются. Но не раздельно, а одновременно. А в примере с указателем shads ожидает последовательного выполнения.

PS "operation on 'pMassiv' may be undefined" - потому что объявили его volatile. Естественно компилятор предупреждает, что операции с volatile будут проводится последовательно (раздельно во времени) и за это время переменная может измениться.
Последний раз редактировалось ibiza11 Вт мар 19, 2013 15:52:03, всего редактировалось 1 раз.
Ставим плюсы: )
HHIMERA
Друг Кота
Сообщения: 4583
Зарегистрирован: Вс дек 05, 2010 06:10:34
Откуда: ЮВ

Re: Вопросы по С/С++ (СИ)

Сообщение HHIMERA »

ibiza11 писал(а)::evil: бред! зачем объявлять указатель на массив volatile? он что, у Вас в прерывании меняется?

А что... volatile применяется только лишь при работе с прерываниями??? :))
Я предложил volatile всего лишь как вариант, а не панацею...
естественно volatile будет работать в этом случае, поскольку при каждом обращении к указателю будет производиться его преддекремент. Но это равносильно отключению оптимизации этого указателя. Так делать нельзя.

Was ist das... "нельзя"???
Это одно из применений volatile... указать оптимизатору "это не твоё - не тронь!"...
В данном случае, скорее всего, можно обойтись и без volatile... здесь возможны и варианты...
Но имеются и другие прецеденты... когда пользуются указателями и структурами завязанными на порты и периферию без volatile...
А если "злобный" Code Reordering... что прикажете делать???
Реальный случай переноса рабочего проекта с STM32 на PIC24...
Пакетная передача по SPI... подготовка данных-ожидание флага готовности-передача данных... и так девять раз подряд, чтобы всё успевало... И что делает GCC С30 ??? Он аккуратно складывает по порядку подготовка данных, подготовка данных, подготовка данных... ожидание флага готовности, ожидание флага готовности, ожидание флага готовности... передача данных, передача данных, передача данных... жесть!!! :)))
Порвал строку подготовки данных пополам (а больше там и разорвать было нечего), ввёл дополнительную переменную - подготовка данных-ожидание флага готовности, подготовка данных-ожидание флага готовности, подготовка данных-ожидание флага готовности... передача данных, передача данных, передача данных... :)))
И только когда объявил дополнительную переменную как volatile, всё стало на свои места...
А ведь на STM32 всё работало как надо...
"Я не даю готовых решений, я заставляю думать!"(С)
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: Вопросы по С/С++ (СИ)

Сообщение Kavka »

ibiza11, что-то ты ошибся где-то. Должно быть так.

Код: Выделить всё

Execute: x = (++1) + (++1)
Result : x = 6, a = 3

Execute: x = (1++) + (1++)
Result : x = 2, a = 3
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение ibiza11 »

Kavka, прошу прощения, поправил пост. Видимо copy-paste был из другого варианта кода ( x = (a++) + (++a); ). :oops:
Последний раз редактировалось ibiza11 Вт мар 19, 2013 15:54:15, всего редактировалось 1 раз.
Ставим плюсы: )
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: Вопросы по С/С++ (СИ)

Сообщение shads »

ibiza11 писал(а):"operation on 'pMassiv' may be undefined" - потому что объявили его volatile. Естественно компилятор предупреждает, что операции с volatile будут проводится последовательно (раздельно во времени) и за это время переменная может измениться.

Да нет..... причина в другом, т.к. нет никаких volatile.....
вот из 6-й студии с предупреждением "operation on 'pMassiv' may be undefined" на второй префикс

Код: Выделить всё

#include <avr/io.h>

int main (void)
{
    char massiv [10];
    char* pMassiv = massiv;

    for (char i=0; i<10; i++)
        *pMassiv++ = i;

    if (*(--pMassiv) == *(--pMassiv))
        PORTB = 0xff;
    else
        PORTB 
= 0x00;

    while (1){}
}
 
HHIMERA
Друг Кота
Сообщения: 4583
Зарегистрирован: Вс дек 05, 2010 06:10:34
Откуда: ЮВ

Re: Вопросы по С/С++ (СИ)

Сообщение HHIMERA »

shads писал(а):вот из 6-й студии с предупреждением "operation on 'pMassiv' may be undefined" на второй префикс

Это говорит о том, что результат может быть неопределённым... т. е. содержать "мусор"...
"Я не даю готовых решений, я заставляю думать!"(С)
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: Вопросы по С/С++ (СИ)

Сообщение shads »

Ну чтож, спасибо всем.

В результате 2-х страниц хождения вокруг да около, вроде понял смысл таинственного поведения пре\постфиксов относящихся к одной переменной в одном выражении.....

Теперь надеюсь правильное заключение:
пре\постфиксы касающиеся одной переменной в одном выражении - вычисляются разом до вхождения в это выражение.
Т.е. если вычислить а=1; b = (++a) + (++a) то получается как то так:
вычисление префиксов (обоих) до вхождения в выражение: (a=1) a=a+1 (a=2), a=a+1 (a=3)
вычисление самого выражения: (a=3) a=a+a (a=6).....

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

Только вот интересно..... такое поведение продиктовано какими то законами математики\геометрии\или чего там еще.....
Или это решение каких то дядек о том что "пусть так будет".....
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: Вопросы по С/С++ (СИ)

Сообщение ibiza11 »

shads писал(а):Только вот интересно..... такое поведение продиктовано какими то законами математики\геометрии\или чего там еще.....
Или это решение каких то дядек о том что "пусть так будет".....
Это стандарт C89.
Ставим плюсы: )
Аватара пользователя
IM1
Грызет канифоль
Сообщения: 268
Зарегистрирован: Вт фев 16, 2010 12:10:38
Откуда: Воронеж, Россия

Re: Вопросы по С/С++ (СИ)

Сообщение IM1 »

shads писал(а):Т.е. если вычислить а=1; b = (++a) + (++a) то получается как то так:
вычисление префиксов (обоих) до вхождения в выражение: (a=1) a=a+1 (a=2), a=a+1 (a=3)
вычисление самого выражения: (a=3) a=a+a (a=6).....
Уважаемые знатоки, что-то я совсем запутался. Да, Visual Studio 2012 дает именно так:

Код: Выделить всё

Execute: x = (++1) + (++1)
Result : x = 6, a = 3
Execute: x = (1++) + (1++)
Result : x = 2, a = 3
а Atmel Studio 6 выдает:

Код: Выделить всё

x = 5, a = 3
x = 2, a = 2
Для преинкремента вроде логично: первая скобка а=2, вторая а=3, сумма=5;
а для случая постинкремента вообще темный лес.
Где же правда? Поясните пожалуйста.
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: Вопросы по С/С++ (СИ)

Сообщение Kavka »

По русски нашёл вот это http://www.opennet.ru/docs/RUS/ansi-c/a ... html#ss5.5
По приоритету получается, что все пре-инкременты должны производиться перед бинарными математическими операциями и операциями присвоения.
Раньше не рекомендовалось использовать более одной ++/-- операции для одной переменной в одном выражении. В старых стандартах не было чётких рекомендаций на этот счёт. На сколько давние то были стандарты - не помню.
Сейчас, что-то не могу найти про современные стандарты.

Добавил:
Покопавшись в закромах интернета нашёл вот что.
СпойлерДокумент "WG14/N1256 Committee Draft — Septermber 7, 2007 ISO/IEC 9899:TC3"
Рездел "6.5 Expressions", пункт 2:
Between the previous and next sequence point an object shall have its stored value
modified at most once by the evaluation of an expression. 72) Furthermore, the prior value
shall be read only to determine the value to be stored. 73)

73) This paragraph renders undefined statement expressions such as
i = ++i + 1;
a[i++] = i;
while allowing
i = i + 1;
a[i] = i;

Ещё вот
http://www.parashift.com/c++-faq-lite/d ... eq-pt.html
http://stackoverflow.com/questions/3457 ... 42#3458842

http://stackoverflow.com/questions/4638 ... s-reloaded
http://stackoverflow.com/questions/4176 ... nce-points
http://stackoverflow.com/questions/2397 ... d-behavior
В итоге, перефразируя и слегка упрощая, можно рекомендовать как написано в стандарте: между двумя точками с запятой значение переменной можно менять максимум 1 раз. Иначе, в общем случае, поведение можно считать не определённым, зависящим от компилятора, уровня оптимизации и т.п. и т.д.

В новых стандартах C++ (образца 2000 года и новее), вроде как, стало чуть лучше, но далеко не всё. Так что ранее приведённая рекомендация остаётся в силе.

В качестве заметки: в C# (Си шарп) и Java такой синтаксис допускается, а поведение определено досконально и оно отличается от gcc.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Аватара пользователя
shads
Опытный кот
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Re: Вопросы по С/С++ (СИ)

Сообщение shads »

IM1 писал(а):что-то я совсем запутался.
Atmel Studio 6 выдает:

Код: Выделить всё

x = 5, a = 3
x = 2, a = 2

Ха.... дастиш фантастиш.....
У меня 6-ка выдает

Код: Выделить всё

x = 6, a = 3 (как и в 4-ке. IM1 проверь еще раз у себя, скорее всего у тебя ошибка)
x = 2, a = 2 (в 4-ке было 2 и 3)

И что интересно, компиль на эти примеры тоже ругается: "operation on 'a' may be undefined"
что говорит о том что эти примеры - тоже не нормальная ситуация.... и что разные компиляторы могут давать разный результат.....
Ответить

Вернуться в «Разные вопросы по МК»