Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Cpp check ругается
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2
ViKo
Имею массив из float и указатель на него.

Код
  pSigRe = SigRe;
  for (uint32_t i = FFT_N; i--; ) {
    *pSigRe++ = log2f(*pSigRe) * 15.0515;
  }


При проверке cpp check выдает ошибку.
Кратко: Expression '*pSigRe++=log2f(*pSigRe)*15.0515' depends on order of evaluation of side effects
Сообщение: Expression '*pSigRe++=log2f(*pSigRe)*15.0515' depends on order of evaluation of side effects
Точно, так нельзя писать? w00t.gif
V_G
Цитата(ViKo @ Feb 6 2018, 22:34) *
Точно, так нельзя писать? w00t.gif

Мне непонятно, что Вы хотели сказать выражением *pSigRe++ : инкрементировать адрес переменной или получить адрес (попутно инкрементированной) переменной. Во втором случае непонятно назначение правой части присвоения, ведь Вы уже вычислили новое значение переменной pSigRe в левой части?
Я думаю, компилятор понимает Вас еще меньше. Расставьте скобки, насильно задав приоритет операций, или перепишите выражение в несколько вычислительных строк.
ViKo
Цитата(V_G @ Feb 6 2018, 15:56) *
Мне непонятно, что Вы хотели сказать выражением *pSigRe++ : инкрементировать адрес переменной или получить адрес (попутно инкрементированной) переменной. Во втором случае непонятно назначение правой части присвоения, ведь Вы уже вычислили новое значение переменной pSigRe в левой части?
Я думаю, компилятор понимает Вас еще меньше. Расставьте скобки, насильно задав приоритет операций, или перепишите выражение в несколько вычислительных строк.

Записываю результат по указателю, и инкрементирую его (указатель) для следующей операции.
megajohn
проверьте так
pSigRe = SigRe;
for (uint32_t i = FFT_N; i--; pSigRe++ ) {
*pSigRe = log2f(*pSigRe) * 15.0515;
}
Kabdim
Цитата
олучить адрес (попутно инкрементированной) переменной

Это неправильная интерпретация.
2ВиКо
Цппчек намекает что постинкремент и вызов фукнции (и соответсвенно вычисление её аргументов) имеет одинаковый приоритет и соответсвенно может произойти в любом порядке, в том числе вначале случится постикремент, а потом уже передача аргументов в функцию.

Для общего развития следует прочитать ссылку. Да и в целом сразу бить себя линейкой по пальцам за желание использовать постинкрмент. Его непросто использовать без выстрелов в ногу.
_pv
Цитата(ViKo @ Feb 6 2018, 19:34) *
Сообщение: Expression '*pSigRe++=log2f(*pSigRe)*15.0515' depends on order of evaluation of side effects
Точно, так нельзя писать? w00t.gif

писать-то можно, только вот результат может оказаться не совсем таким как задумано.
Цитата
Записываю результат по указателю, и инкрементирую его (указатель) для следующей операции.

а может всё-таки сначала инкрементируете, потом считаете логарифм уже от следующего элемента, но результат записываете на место предыдущего?

на *pSigRe = log2f(*pSigRe++) * 15.0515; ругаться имхо не должен.
ViKo
Цитата(megajohn @ Feb 6 2018, 16:18) *
проверьте так
pSigRe = SigRe;
for (uint32_t i = FFT_N; i--; pSigRe++ ) {
*pSigRe = log2f(*pSigRe) * 15.0515;
}

Чего уж, сделал, чтобы цеплялся:
Код
    *pSigRe = log2f(*pSigRe) * 15.0515;
    pSigRe++;


Что вы меня все путаете? Сначала справа от = вычисляется, потом присваивается. А инкремент разве не после присваивания должен выполняться?
Э, смотрю приоритеты операций. Так присваивание почти на последнем месте. То есть, сначала инкрементируется указатель??
jcxz
Цитата(ViKo @ Feb 6 2018, 14:34) *
Кратко: Expression '*pSigRe++=log2f(*pSigRe)*15.0515' depends on order of evaluation of side effects
Сообщение: Expression '*pSigRe++=log2f(*pSigRe)*15.0515' depends on order of evaluation of side effects

Это вопрос по существу или викторина? Если первое, то следует указывать типы используемых переменных.

Цитата(V_G @ Feb 6 2018, 14:56) *
Мне непонятно, что Вы хотели сказать выражением *pSigRe++

Это называется "пост-инкрементная адресация". Все сишные компиляторы должны понимать её без проблем.
ViKo
Цитата(jcxz @ Feb 6 2018, 16:53) *
Это вопрос по существу или викторина? Если первое, то следует указывать типы используемых переменных.

Вы первые строки в сообщениях принципиально пропускаете? rolleyes.gif Да и какая разница, что за тип?
jcxz
Цитата(_pv @ Feb 6 2018, 15:34) *
на *pSigRe = log2f(*pSigRe++) * 15.0515; ругаться имхо не должен.

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

Цитата(ViKo @ Feb 6 2018, 15:55) *
Вы первые строки в сообщениях принципиально пропускаете? rolleyes.gif Да и какая разница, что за тип?

Из первых строк сообщения можно только сделать вывод что где-то у Вас есть некий массив float и есть некий указатель на него. Больше оттуда нельзя получить никакой информации.
Значит всё-таки викторина....
Видимо Вы и программы так пишете - предоставляете компилятору право гадать, что вы хотели написать. Ну естественно и результат закономерный laughing.gif

Далее включаю экстрасенсорные способности и прикидываю - о каком указателе речь?
Может это: float volatile *pSigRe ?
а может: float *pSigRe ?
а может ещё что...? cool.gif
ViKo
Цитата(jcxz @ Feb 6 2018, 17:00) *
Из первых строк сообщения можно только сделать вывод что где-то у Вас есть некий массив float и есть некий указатель на него. Больше оттуда нельзя получить никакой информации.
Значит всё-таки викторина....

Ну, раз нельзя, тогда пусть викторина. laughing.gif

По существу. У классиков K&R имеется пример, которым, собственно и пользуюсь (руководствуюсь) издавна.
Код
/* strcpy: копирует t в s; версия 3 (с указателями) */
void strcpy(char *s, char *t)
{
    while (*s++ = *t++)
     ;
}

Считаю, CppCheck пугает химерами зря.

jcxz, вам - персонально:
Код
  static float SigRe[FFT_N] __attribute((section("extram")));
  float *pSigRe;
jcxz
Цитата(ViKo @ Feb 6 2018, 16:06) *
По существу. У классиков K&R имеется пример, которым, собственно и пользуюсь издавна.
...

И...?
Каким боком он сюда относится?

Цитата(ViKo @ Feb 6 2018, 16:08) *
jcxz, вам - персонально:

Спасибо rolleyes.gif
ViKo
Цитата(jcxz @ Feb 6 2018, 17:09) *
И...?
Каким боком он сюда относится?

Вы прикалываетесь, что ли? biggrin.gif
jcxz
Цитата(ViKo @ Feb 6 2018, 16:12) *
Вы прикалываетесь, что ли? biggrin.gif

Нет. Не понимаю каким боком относится приведённый пример к Вашему вопросу.
ViKo
Ладно. Значит, нужно найти точное толкование, когда инкрементируется указатель, если он используется справа и слева от оператора присваивания.
x893
Цитата(jcxz @ Feb 6 2018, 17:19) *
Нет. Не понимаю каким боком относится приведённый пример к Вашему вопросу.

Пример никак к теме не относится.
Но судя по высказываниям - ожидается большая дискуссия между гуру программирования.
Начинающие начинают попкорн готовить.
ViKo
Цитата(x893 @ Feb 6 2018, 17:26) *
Пример никак к теме не относится.
Но судя по высказываниям - ожидается большая дискуссия между гуру программирования.
Начинающие начинают попкорн готовить.

Так, жду-с.
Вот здесь чего-то пишут, но не могу понять.
http://en.cppreference.com/w/cpp/language/eval_order
Сергей Борщ
QUOTE (ViKo @ Feb 6 2018, 16:30) *
Так, жду-с.
Вам уже дали правильный и исчерпывающий ответ:
QUOTE (_pv @ Feb 6 2018, 15:34) *
а может всё-таки сначала инкрементируете, потом считаете логарифм уже от следующего элемента, но результат записываете на место предыдущего?
Компилятор имеет на это полное право. Чего еще вы ожидаете услышать?
ViKo
Цитата(Сергей Борщ @ Feb 6 2018, 17:36) *
Вам уже дали правильный и исчерпывающий ответ:
Компилятор имеет на это полное право. Чего еще вы ожидаете услышать?

Здесь тоже сначала инкрементируют, потом записывают?
while (*s++ = *t++)
haker_fox
QUOTE (ViKo @ Feb 6 2018, 20:34) *
Точно, так нельзя писать? w00t.gif

Я бы избегал подобных неоднозначностей. Лучше записать код длинне на пару строк, но так, чтобы его понял любой компилятор/транслятор/синтезатор и статический анализатор. А самое главное - вы сами через пару-тройку лет, или другой коллега))))

Кстати, свои произведения проверяю также CppCheck и встроенным в IAR анализатором. Иногда помогает устранить весьма абсурдные и детские ошибки, допущенные по невнимательности.
jcxz
Цитата(ViKo @ Feb 6 2018, 16:39) *
Здесь тоже сначала инкрементируют, потом записывают?
while (*s++ = *t++)

Здесь у Вас два разных указателя. А значит - нет неопределённости по операциям постинкремента.
Если конечно у Вас в неких "первых строках", которые Вы не посчитали нужным привести здесь, не записано:
#define t s
biggrin.gif
haker_fox
QUOTE (ViKo @ Feb 6 2018, 22:39) *
Здесь тоже сначала инкрементируют, потом записывают?
while (*s++ = *t++)

Здесь всё в порядке, т.к. справа и слева от оператора присвоения у вас разные переменные, и они не зависят от друг друга.
SSerge
Цитата(ViKo @ Feb 6 2018, 21:30) *
Так, жду-с.

Извольте.
Стандарт С явно указывает что порядок вычисления левой и правой частей оператора присваивания не определён.
Цитата
6.5.16 Assignment operators:
4. The order of evaluation of the operands is unspecified.

А в С++ понаписали такого что и с бутылкой не разберёшь.

Так что да, по крайней мере в С, никто не гарантирует что pSigRe во время вычисления правой части не окажется уже инкрементирован в результате случившегося раньше вычисления левой части оператора присваивания.


jcxz
Цитата(ViKo @ Feb 6 2018, 16:22) *
Ладно. Значит, нужно найти точное толкование, когда инкрементируется указатель, если он используется справа и слева от оператора присваивания.

Это - на усмотрение компилятора/оптимизатора. Как ему удобнее.
Вобщем случае он может вообще никак не инкрементироваться в теле цикла, а только в его конце.
Или вообще цикл может быть развёрнут оптимизатором в линейный код. А все инкрементные и декрементные адресации заменены на адресации по указателю с фиксированным смещением.
А при следующей перекомпиляции с другими исходными условиями - не развёрнут, оставлен цикл.
haker_fox
Первый пример я бы записал так:
CODE
  for (uint32_t i = FFT_N; i--; ) {
    VarType_t result = log2f(*pSigRe) * 15.0515;
    *pSigRe++ = result;
  }

Ну для красоты result можно за цикл вынести, чтобы при каждой итерации не вызывать её конструктор (инициализатор).
ViKo
Цитата(SSerge @ Feb 6 2018, 17:44) *
Извольте.
Стандарт С явно указывает что порядок вычисления левой и правой частей оператора присваивания не определён.
А в С++ понаписали такого что и с бутылкой не разберёшь.
Так что да, по крайней мере в С, никто не гарантирует что pSigRe во время вычисления правой части не окажется уже инкрементирован в результате случившегося раньше вычисления левой части оператора присваивания.

Благодарствую! Хотя к чему такая толерантность. Мода laughing.gif
А вот Кейл с --remarks на строку
*pSigRe++ = log2f(*pSigRe) * 15.0515;
даже не заикнулся.

Буду смотреть, что он накомпилировал. Позже. Сейчас покидаю дискуссию.

Цитата(jcxz @ Feb 6 2018, 17:45) *
Вобщем случае он может вообще никак не инкрементироваться в теле цикла, а только в его конце.

Это уж дудки. В каждой операции цикла сделает все, что приказали.
Сергей Борщ
QUOTE (ViKo @ Feb 6 2018, 16:57) *
Это уж дудки. В каждой операции цикла сделает все, что приказали.
Вас ждет еще много открытий в жизни. Посмотрите листинги своих программ повнимательнее.
Arlleex
Довольно интересная тема в Си, связанная с базовым понятием точки следования.
Код
while (*s++ = *t++)

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

нет ни одной точки следования, кроме завершающей точки с запятой, поэтому результат не определен, выполнение приводит к undefined behavior.

Гуглите "sequence ponts in C". Например, тут.
jcxz
Цитата(ViKo @ Feb 6 2018, 16:57) *
Это уж дудки. В каждой операции цикла сделает все, что приказали.

Он может даже количество итераций сделать не такое как Вы указали - например: объединить каждую чётную и нечётную итерации в одну, уменьшив их число в 2 раза. Может разбить цикл на два: в одном цикле объединить итерации попарно, в другом - выполнять по одной.
И ещё много чего может. Попробуйте как-нить включить максимальную оптимизацию.

Цитата(Сергей Борщ @ Feb 6 2018, 17:48) *
Вас ждет еще много открытий в жизни. Посмотрите листинги своих программ повнимательнее.

Я думаю, что ViKo никогда ещё не включал оптимизацию. И не заглядывал при этом в асм biggrin.gif
Den64
Цитата(ViKo @ Feb 6 2018, 15:34) *
Имею массив из float и указатель на него.

Код
  pSigRe = SigRe;
    *pSigRe++ = log2f(*pSigRe) * 15.0515;

Точно, так нельзя писать? w00t.gif

Должно выполняться по порядку:
1. (*pSigRe)
2. log2f()
3. pSigRe++
4. *pSigRe
5. умножение
6. присвоение.
ИМХО так делать можно, компилятор не должен ругаться.
x893
А если вдруг запустит на двух- и более процессорном кристалле ?
Arlleex
Цитата(Den64 @ Feb 6 2018, 20:41) *
Должно выполняться по порядку:
1. (*pSigRe)
2. log2f()
3. pSigRe++
4. *pSigRe
5. умножение
6. присвоение.
ИМХО так делать можно, компилятор не должен ругаться.

Компилятор может и не будет ругаться (а зря), однако так делать нельзя. Причины озвучены выше.
DASM
Хорошо вас тут читать.. но.. мое мнение если можно "«Бывает ли у вас такие ситуации, когда слово, идиома или грамматическая конструкция иностранного языка никак не могут удержаться в голове, несмотря на то, что вы встречали её уже много раз и даже специально учили? А сколько процентов иностранных слов вы помните спустя месяц после их изучения? А спустя полгода? Сложно ли вам мотивировать себя на занятия иностранным языком?»
У меня на эти вопросы возникает только другой вопрос: А так ли оно мне надо, если я пользуюсь этими словами раз в пол года? Я лично против забивания мозга тем, что мне не сильно то и нужно."
как-то так примерно. Давно перестал запоминать все эти правила и стараться " типа красиво, в одну строку все". Мой код стал похож на "новичка" - разделяю все на строки не длиннее 80 символов (исключение - список инициализации конструктора), ставлю скобки где и не нужны. Зато не надо вспоминать 14 приоритетов и думать о sequnce point. Ну кто как хочет, только потом обычно с кодом разбираться самому и придется, и материть тоже самого себя. С cppreferencr.com тоже могу "офигенно красиво" написать, только вот потом подзабывается все это. Ну ладно, сорри что встрял в ученую беседу
jcxz
Цитата(DASM @ Feb 6 2018, 19:23) *
Я лично против забивания мозга тем, что мне не сильно то и нужно."
как-то так примерно. Давно перестал запоминать все эти правила и стараться " типа красиво, в одну строку все".

Трудно Вам придётся когда надо будет поработать в команде с другими программёрами. ...у которых свои понятия.
Arlleex
Цитата(DASM @ Feb 6 2018, 20:23) *
Хорошо вас тут читать.. но.. мое мнение если можно "«Бывает ли у вас такие ситуации, когда слово, идиома или грамматическая конструкция иностранного языка никак не могут удержаться в голове, несмотря на то, что вы встречали её уже много раз и даже специально учили? А сколько процентов иностранных слов вы помните спустя месяц после их изучения? А спустя полгода? Сложно ли вам мотивировать себя на занятия иностранным языком?»
У меня на эти вопросы возникает только другой вопрос: А так ли оно мне надо, если я пользуюсь этими словами раз в пол года? Я лично против забивания мозга тем, что мне не сильно то и нужно."
как-то так примерно. Давно перестал запоминать все эти правила и стараться " типа красиво, в одну строку все". Мой код стал похож на "новичка" - разделяю все на строки не длиннее 80 символов (исключение - список инициализации конструктора), ставлю скобки где и не нужны. Зато не надо вспоминать 14 приоритетов и думать о sequnce point. Ну кто как хочет, только потом обычно с кодом разбираться самому и придется, и материть тоже самого себя. С cppreferencr.com тоже могу "офигенно красиво" написать, только вот потом подзабывается все это. Ну ладно, сорри что встрял в ученую беседу

Я тоже пишу максимально просто и без лишней головной боли.
Просто понимаю, какие конструкции к чему могут привести с точки зрения стандарта языка. А чтобы это начать понимать, пришлось не одну ложку дегтя съесть в других проекта)))
AnatolyT
Имеем следующее

pSigRe = SigRe;
for (uint32_t i = FFT_N; i--; ) {
*pSigRe++ = log2f(*pSigRe) * 15.0515;
}

Если SigRe это массив, может следует к нему обращаться как к массиву.

// pSigRe = SigRe;
j=0;
for (uint32_t i = FFT_N; i--; ) {
SigRe[j] = log2f(SigRe[j]) * 15.0515;
j++;
}

Стараюсь глубоко не разбираться в идиомах различных компиляторов.
ViKo
Не считайте упрямством, хочу разобраться. Постинкремент переменной работает после того, как ее использовали. Следовательно, после того, как будет записано вычисленное выражение. Логично?

Цитата(AnatolyT @ Feb 6 2018, 21:41) *
Если SigRe это массив, может следует к нему обращаться как к массиву.

Можно и к массиву. Предполагаю, что для ARM это будет работать так же легко и быстро, как и по указателю. Но я люблю указатели. Деды так завещали.

Цитата(jcxz @ Feb 6 2018, 19:33) *
Я думаю, что ViKo никогда ещё не включал оптимизацию. И не заглядывал при этом в асм biggrin.gif

Первое высказывание исключает второе. Если учесть, что оба неверные, следует, jcxz = трепач. biggrin.gif
Arlleex
Цитата(ViKo @ Feb 6 2018, 23:00) *
Не считайте упрямством, хочу разобраться. Постинкремент переменной работает после того, как ее использовали. Следовательно, после того, как будет записано вычисленное выражение. Логично?

Нет, не так.
Постинкремент переменной не определён внутри выражения.
Рассмотрим пример:
Код
int m[10];
int i = 0;
m[i++] = i; // неопределенное поведение
m[i] = i++; // неопределенное поведение

По стандарту операция присваивания не является точкой следования, соответственно неизвестно, в каком порядке будут вычислены стороны выражения.
Рассмотрим первый пример. Для него порядок вычисления может быть одним из следующих:
Код
1) m[0] = 0; // i == 1
2) m[0] = 1; // i == 1


Аналогично и в Вашем случае.
ViKo
Компилятор использовал следующую команду для записи вычисленного выражения
*pSigRe++ = log2f(*pSigRe) * 15.0515;

STR r0,[r4],#4
Постинкремент
Arlleex
Цитата(ViKo @ Feb 6 2018, 23:49) *
Компилятор использовал следующую команду для записи вычисленного выражения
*pSigRe++ = log2f(*pSigRe) * 15.0515;

STR r0,[r4],#4
Постинкремент

А окружение этой команды можно привести? До и после... Можно сказать, Вам повезло sm.gif
jcxz
Цитата(ViKo @ Feb 6 2018, 22:00) *
Не считайте упрямством, хочу разобраться. Постинкремент переменной работает после того, как ее использовали. Следовательно, после того, как будет записано вычисленное выражение. Логично?

После того как была выполнена конкретная операция, а не всё выражение. Постинкремент же относится к операции, а не ко всему выражению. Логично? biggrin.gif

Цитата(ViKo @ Feb 6 2018, 22:49) *
Компилятор использовал следующую команду для записи вычисленного выражения
*pSigRe++ = log2f(*pSigRe) * 15.0515;
STR r0,[r4],#4
Постинкремент

И что? какая разница какой командой он записал?
Он Вам написал что Ваше выражение можно понимать как:
pSigRe[0] = log2f(pSigRe[0]) * 15.0515;
pSigRe++;

так и:
pSigRe[0] = log2f(pSigRe[1]) * 15.0515;
pSigRe++;

И в результат компиляции выдал первый вариант. Хотя вполне справедливо мог и второй - это как ему удобнее.
ViKo
Мог бы... Но не сделал. А сделал так, как мне и было нужно. Это я констатирую факт.
Переписать, чтобы инкрементировался указатель отдельным выражением, легко. Выше уже давно сделал.
Вопрос, почему CppCheck ругается, а Keil молча делает, как было задумано. Кто из них тупит?

Цитата(Arlleex @ Feb 7 2018, 00:01) *
А окружение этой команды можно привести? До и после... Можно сказать, Вам повезло sm.gif

Покажу оба варианта, ближе к обеду. santa2.gif И оптимизацию разную проверю.
V_G
Я думаю, если ассемблер данного конкретного контроллера поддерживает постинкремент указателей, и компилятор использует это свойство, то результат будет всегда один. Если же перейти на проц, где нет этой фичи (или уже не хватает регистров для указателей), результаты компиляции могут быть неоднозначными.
Как радиоинженер и непрофессиональный программист, я тоже предпочитаю не вспоминать приоритеты и не жалеть скобок.
Arlleex
Цитата(ViKo @ Feb 7 2018, 08:10) *
Вопрос, почему CppCheck ругается, а Keil молча делает, как было задумано. Кто из них тупит?

Не знаю что за CppCheck, но он тут молодец, что предупредил. А Keil не молодец. Хотя может и молодец, что схавал, полагаясь на компетентность программиста (а иногда так и хочется наорать на компилятор "я знаю что я делаю, тварь!" biggrin.gif ). Хотя и не молодец, хотя бы warning бы кинул...

Цитата(V_G @ Feb 7 2018, 08:22) *
Я думаю, если ассемблер данного конкретного контроллера поддерживает постинкремент указателей, и компилятор использует это свойство, то результат будет всегда один. Если же перейти на проц, где нет этой фичи (или уже не хватает регистров для указателей), результаты компиляции могут быть неоднозначными.
Как радиоинженер и непрофессиональный программист, я тоже предпочитаю не вспоминать приоритеты и не жалеть скобок.

Ассемблер тут совершенно ни при чем. Это полностью зависит от компилятора. Реализовано ли в системе команд постинкремент или нет, совершенно не важно, компилятор может спокойно разбить постинкремент на несколько инструкций.
Я не понимаю одного - если в стандарте четко написано о таких вещах, зачем намеренно создавать себе проблему "кодированием через пробы и ошибки"? Ведь даже элементарное включение оптимизации может привести совершенно к другому порядку инструкций, и гарантировать равнозначное поведение в данном случае невозможно.
x893
А еще правильнее написать авторам cppcheck и задать вопрос напрямую.
mcheb
Решил проверить в GCC
Код
    uint16_t i;
    float SigRe[16],*pSigRe;
    pSigRe = SigRe;
    for(i=0; i<16; i++) SigRe[i] = 2.*(i+1);
    for(i=0; i<16; i++) *pSigRe++ = log2f(*pSigRe) * 15.0515;
    for(i=0; i<16; i++) printf("i = %u SigRe[%u] = %f12.5\n",i,i,SigRe[i]);

    for(i=0; i<16; i++) SigRe[i] = 2.*(i+1);
    for(i=0; i<16; i++) SigRe[i] = log2f(SigRe[i]) * 15.0515;
    for(i=0; i<16; i++) printf("i = %u SigRe[%u] = %f12.5\n",i,i,SigRe[i]);

Получил
Код
i = 0 SigRe[0] = 30.10300112.5
i = 1 SigRe[1] = 38.90756212.5
i = 2 SigRe[2] = 45.15449912.5
i = 3 SigRe[3] = 50.00000012.5
i = 4 SigRe[4] = 53.95906412.5
i = 5 SigRe[5] = 57.30640412.5
i = 6 SigRe[6] = 60.20600112.5
i = 7 SigRe[7] = 62.76362612.5
i = 8 SigRe[8] = 65.05149812.5
i = 9 SigRe[9] = 67.12113212.5
i = 10 SigRe[10] = 69.01056712.5
i = 11 SigRe[11] = 70.74866512.5
i = 12 SigRe[12] = 72.35790312.5
i = 13 SigRe[13] = 73.85606412.5
i = 14 SigRe[14] = 75.25750012.5
i = 15 SigRe[15] = -1913.32995612.5
i = 0 SigRe[0] = 15.05150012.5
i = 1 SigRe[1] = 30.10300112.5
i = 2 SigRe[2] = 38.90756212.5
i = 3 SigRe[3] = 45.15449912.5
i = 4 SigRe[4] = 50.00000012.5
i = 5 SigRe[5] = 53.95906412.5
i = 6 SigRe[6] = 57.30640412.5
i = 7 SigRe[7] = 60.20600112.5
i = 8 SigRe[8] = 62.76362612.5
i = 9 SigRe[9] = 65.05149812.5
i = 10 SigRe[10] = 67.12113212.5
i = 11 SigRe[11] = 69.01056712.5
i = 12 SigRe[12] = 70.74866512.5
i = 13 SigRe[13] = 72.35790312.5
i = 14 SigRe[14] = 73.85606412.5
i = 15 SigRe[15] = 75.25750012.5
Hello world!


Ругается на
Prj\Hello\main.c:12:32: warning: operation on 'pSigRe' may be undefined [-Wsequence-point]
for(i=0; i<16; i++) *pSigRe++ = log2f(*pSigRe) * 15.0515;
Выходит, что нельзя так.
Сергей Борщ
QUOTE (x893 @ Feb 7 2018, 08:03) *
А еще правильнее написать авторам cppcheck и задать вопрос напрямую.
Какой вопрос??? Еще на первой странице выяснили: все описано в Стандарте, cppcheck ругается правильно. Но некоторые уже четвертую страницу бубнят "Я переходил дорогу на красный свет и меня не сбили. Нафига в правилах написали, что переходить на красный нельзя?". А некторые еще и переходят на красный, чтобы убедиться.
ViKo
CODE
**********************************************************************
-O0

000320 490e LDR r1,|L8.860|
000322 6008 STR r0,[r1,#0] ; SigRe
;;;3771 pSigRe = SigRe;
000324 460c MOV r4,r1
;;;3772 for (uint32_t i = FFT_N; i--; ) {
000326 f44f6680 MOV r6,#0x400
00032a e00f B |L8.844|
|L8.812|
;;;3775 *pSigRe++ = log2f(*pSigRe) * 15.0515;
00032c 6820 LDR r0,[r4,#0]
00032e f7fffffe BL log2f
000332 900b STR r0,[sp,#0x2c]
000334 f7fffffe BL __aeabi_f2d
000338 4680 MOV r8,r0
00033a 4a14 LDR r2,|L8.908|
00033c 4b14 LDR r3,|L8.912|
00033e f7fffffe BL __aeabi_dmul
000342 e9cd010c STRD r0,r1,[sp,#0x30]
000346 f7fffffe BL __aeabi_d2f
00034a c401 STM r4!,{r0}
|L8.844|
00034c 1e30 SUBS r0,r6,#0 ;3772
00034e f1a60601 SUB r6,r6,#1 ;3772
000352 d1eb BNE |L8.812|
|L8.860|
DCD SigRe
|L8.908|
DCD 0x353f7cee
|L8.912|
DCD 0x402e1a5e

********************************************************************************
-O0

000320 490e LDR r1,|L8.860|
000322 6008 STR r0,[r1,#0] ; SigRe
;;;3771 pSigRe = SigRe;
000324 460c MOV r4,r1
;;;3772 for (uint32_t i = FFT_N; i--; ) {
000326 f44f6680 MOV r6,#0x400
00032a e010 B |L8.846|
|L8.812|
;;;3775 *pSigRe = log2f(*pSigRe) * 15.0515;
00032c 6820 LDR r0,[r4,#0]
00032e f7fffffe BL log2f
000332 900b STR r0,[sp,#0x2c]
000334 f7fffffe BL __aeabi_f2d
000338 4680 MOV r8,r0
00033a 4a14 LDR r2,|L8.908|
00033c 4b14 LDR r3,|L8.912|
00033e f7fffffe BL __aeabi_dmul
000342 e9cd010c STRD r0,r1,[sp,#0x30]
000346 f7fffffe BL __aeabi_d2f
00034a 6020 STR r0,[r4,#0]
;;;3776 pSigRe++;
00034c 1d24 ADDS r4,r4,#4
|L8.846|
00034e 1e30 SUBS r0,r6,#0 ;3772
000350 f1a60601 SUB r6,r6,#1 ;3772
000354 d1ea BNE |L8.812|
|L8.860|
DCD SigRe
|L8.908|
DCD 0x353f7cee
|L8.912|
DCD 0x402e1a5e

********************************************************************************
-O3 -Otime

;;;3775 *pSigRe++ = log2f(*pSigRe) * 15.0515;

000264 f24038ff MOV r8,#0x3ff ;3722

0002d8 4c0a LDR r4,|L8.772|
0002da 4d17 LDR r5,|L8.824|
0002dc 4e17 LDR r6,|L8.828|
|L8.734|
0002de 6820 LDR r0,[r4,#0] ;3775
0002e0 f7fffffe BL log2f
0002e4 f7fffffe BL __aeabi_f2d
0002e8 462a MOV r2,r5 ;3775
0002ea 4633 MOV r3,r6 ;3775
0002ec f7fffffe BL __aeabi_dmul
0002f0 f7fffffe BL __aeabi_d2f
0002f4 f8440b04 STR r0,[r4],#4 ;3775
0002f8 f1b80801 SUBS r8,r8,#1 ;3775
0002fc d2ef BCS |L8.734|

|L8.772|
DCD extram
|L8.824|
DCD 0x353f7cee
|L8.828|
DCD 0x402e1a5e


********************************************************************************
-O3 -Otime

;;;3771 pSigRe = SigRe;
;;;3772 for (uint32_t i = FFT_N; i--; ) {
;;;3775 *pSigRe = log2f(*pSigRe) * 15.0515;
;;;3776 pSigRe++;
;;;3777 }
000264 f24038ff MOV r8,#0x3ff ;3722

0002d8 4c0a LDR r4,|L8.772|
0002da 4d17 LDR r5,|L8.824|
0002dc 4e17 LDR r6,|L8.828|
|L8.734|
0002de 6820 LDR r0,[r4,#0] ;3775
0002e0 f7fffffe BL log2f
0002e4 f7fffffe BL __aeabi_f2d
0002e8 462a MOV r2,r5 ;3775
0002ea 4633 MOV r3,r6 ;3775
0002ec f7fffffe BL __aeabi_dmul
0002f0 f7fffffe BL __aeabi_d2f
0002f4 f8440b04 STR r0,[r4],#4 ;3775
0002f8 f1b80801 SUBS r8,r8,#1 ;3775
0002fc d2ef BCS |L8.734|

|L8.772|
DCD extram
|L8.824|
DCD 0x353f7cee
|L8.828|
DCD 0x402e1a5e


В общем, для Keil нет разницы. Как нет и никакого преимущества писать сразу *SigRe++ = ...
Учту замечание CppCheck. Но, чтобы снизошло озарение и просветление, так нет.

CODE
***********************************************************************
-O3
;;;3775 *pSigRe++ = log2f(*pSigRe) * 15.0515;

000208 f24035ff MOV r5,#0x3ff

000280 4c09 LDR r4,|L8.680|
000282 4e12 LDR r6,|L8.716|
000284 4f12 LDR r7,|L8.720|
|L8.646|
000286 6820 LDR r0,[r4,#0] ;3775
000288 f7fffffe BL log2f
00028c f7fffffe BL __aeabi_f2d
000290 4632 MOV r2,r6 ;3775
000292 463b MOV r3,r7 ;3775
000294 f7fffffe BL __aeabi_dmul
000298 f7fffffe BL __aeabi_d2f
00029c c401 STM r4!,{r0} ;3775
00029e 1e6d SUBS r5,r5,#1 ;3775
0002a0 d2f1 BCS |L8.646|

|L8.680|
DCD extram
|L8.716|
DCD 0x353f7cee
|L8.720|
DCD 0x402e1a5e
Arlleex
Привел код. Скомпилировал на C++ Builder 2010 и в DevC++.
Думаю, пояснения не нужны laughing.gif
ViKo
Усё, таперича проникся. Просвещен. Спасибо всем неравнодушным!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.