|
|
  |
Cpp check ругается, можно ли так писать? |
|
|
|
Feb 6 2018, 12:34
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Имею массив из 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 Точно, так нельзя писать?
|
|
|
|
|
Feb 6 2018, 13:30
|
Знающий
   
Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842

|
Цитата олучить адрес (попутно инкрементированной) переменной Это неправильная интерпретация. 2ВиКо Цппчек намекает что постинкремент и вызов фукнции (и соответсвенно вычисление её аргументов) имеет одинаковый приоритет и соответсвенно может произойти в любом порядке, в том числе вначале случится постикремент, а потом уже передача аргументов в функцию. Для общего развития следует прочитать ссылку. Да и в целом сразу бить себя линейкой по пальцам за желание использовать постинкрмент. Его непросто использовать без выстрелов в ногу.
|
|
|
|
|
Feb 6 2018, 13:34
|
Гуру
     
Группа: Свой
Сообщений: 2 563
Регистрация: 8-04-05
Из: Nsk
Пользователь №: 3 954

|
Цитата(ViKo @ Feb 6 2018, 19:34)  Сообщение: Expression '*pSigRe++=log2f(*pSigRe)*15.0515' depends on order of evaluation of side effects Точно, так нельзя писать?  писать-то можно, только вот результат может оказаться не совсем таким как задумано. Цитата Записываю результат по указателю, и инкрементирую его (указатель) для следующей операции. а может всё-таки сначала инкрементируете, потом считаете логарифм уже от следующего элемента, но результат записываете на место предыдущего? на *pSigRe = log2f(*pSigRe++) * 15.0515; ругаться имхо не должен.
|
|
|
|
|
Feb 6 2018, 13:35
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(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++; Что вы меня все путаете? Сначала справа от = вычисляется, потом присваивается. А инкремент разве не после присваивания должен выполняться? Э, смотрю приоритеты операций. Так присваивание почти на последнем месте. То есть, сначала инкрементируется указатель??
|
|
|
|
|
Feb 6 2018, 13:53
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(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++ Это называется "пост-инкрементная адресация". Все сишные компиляторы должны понимать её без проблем.
|
|
|
|
|
Feb 6 2018, 14:00
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(_pv @ Feb 6 2018, 15:34)  на *pSigRe = log2f(*pSigRe++) * 15.0515; ругаться имхо не должен. Нет, необязательно. Вообще нужно просто взять за правило, что если в пределах одного выражения разыменование указателя встречается более одного раза, то никакие пре- или пост- инкрементные или декрементные адресации использовать нельзя. Цитата(ViKo @ Feb 6 2018, 15:55)  Вы первые строки в сообщениях принципиально пропускаете?  Да и какая разница, что за тип? Из первых строк сообщения можно только сделать вывод что где-то у Вас есть некий массив float и есть некий указатель на него. Больше оттуда нельзя получить никакой информации. Значит всё-таки викторина.... Видимо Вы и программы так пишете - предоставляете компилятору право гадать, что вы хотели написать. Ну естественно и результат закономерный Далее включаю экстрасенсорные способности и прикидываю - о каком указателе речь? Может это: float volatile *pSigRe ? а может: float *pSigRe ? а может ещё что...?
|
|
|
|
|
Feb 6 2018, 14:08
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(jcxz @ Feb 6 2018, 17:00)  Из первых строк сообщения можно только сделать вывод что где-то у Вас есть некий массив float и есть некий указатель на него. Больше оттуда нельзя получить никакой информации. Значит всё-таки викторина.... Ну, раз нельзя, тогда пусть викторина. По существу. У классиков 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;
|
|
|
|
|
Feb 6 2018, 14:09
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(ViKo @ Feb 6 2018, 16:06)  По существу. У классиков K&R имеется пример, которым, собственно и пользуюсь издавна. ... И...? Каким боком он сюда относится? Цитата(ViKo @ Feb 6 2018, 16:08)  jcxz, вам - персонально: Спасибо
|
|
|
|
|
Feb 6 2018, 14:36
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (ViKo @ Feb 6 2018, 16:30)  Так, жду-с. Вам уже дали правильный и исчерпывающий ответ: QUOTE (_pv @ Feb 6 2018, 15:34)  а может всё-таки сначала инкрементируете, потом считаете логарифм уже от следующего элемента, но результат записываете на место предыдущего? Компилятор имеет на это полное право. Чего еще вы ожидаете услышать?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Feb 6 2018, 14:43
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(ViKo @ Feb 6 2018, 16:39)  Здесь тоже сначала инкрементируют, потом записывают? while (*s++ = *t++) Здесь у Вас два разных указателя. А значит - нет неопределённости по операциям постинкремента. Если конечно у Вас в неких "первых строках", которые Вы не посчитали нужным привести здесь, не записано: #define t s
|
|
|
|
|
Feb 6 2018, 14:44
|
Профессионал
    
Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528

|
Цитата(ViKo @ Feb 6 2018, 21:30)  Так, жду-с. Извольте. Стандарт С явно указывает что порядок вычисления левой и правой частей оператора присваивания не определён. Цитата 6.5.16 Assignment operators: 4. The order of evaluation of the operands is unspecified. А в С++ понаписали такого что и с бутылкой не разберёшь. Так что да, по крайней мере в С, никто не гарантирует что pSigRe во время вычисления правой части не окажется уже инкрементирован в результате случившегося раньше вычисления левой части оператора присваивания.
--------------------
Russia est omnis divisa in partes octo.
|
|
|
|
|
Feb 6 2018, 14:45
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(ViKo @ Feb 6 2018, 16:22)  Ладно. Значит, нужно найти точное толкование, когда инкрементируется указатель, если он используется справа и слева от оператора присваивания. Это - на усмотрение компилятора/оптимизатора. Как ему удобнее. Вобщем случае он может вообще никак не инкрементироваться в теле цикла, а только в его конце. Или вообще цикл может быть развёрнут оптимизатором в линейный код. А все инкрементные и декрементные адресации заменены на адресации по указателю с фиксированным смещением. А при следующей перекомпиляции с другими исходными условиями - не развёрнут, оставлен цикл.
|
|
|
|
|
Feb 6 2018, 14:57
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(SSerge @ Feb 6 2018, 17:44)  Извольте. Стандарт С явно указывает что порядок вычисления левой и правой частей оператора присваивания не определён. А в С++ понаписали такого что и с бутылкой не разберёшь. Так что да, по крайней мере в С, никто не гарантирует что pSigRe во время вычисления правой части не окажется уже инкрементирован в результате случившегося раньше вычисления левой части оператора присваивания. Благодарствую! Хотя к чему такая толерантность. Мода А вот Кейл с --remarks на строку *pSigRe++ = log2f(*pSigRe) * 15.0515; даже не заикнулся. Буду смотреть, что он накомпилировал. Позже. Сейчас покидаю дискуссию. Цитата(jcxz @ Feb 6 2018, 17:45)  Вобщем случае он может вообще никак не инкрементироваться в теле цикла, а только в его конце. Это уж дудки. В каждой операции цикла сделает все, что приказали.
|
|
|
|
|
Feb 6 2018, 15:54
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Довольно интересная тема в Си, связанная с базовым понятием точки следования. Код while (*s++ = *t++) В конце условия стоит точка следования, а тем более, переменные разные, результат будет всегда одинаковым. В конструкциях Код i = i++; нет ни одной точки следования, кроме завершающей точки с запятой, поэтому результат не определен, выполнение приводит к undefined behavior. Гуглите "sequence ponts in C". Например, тут.
|
|
|
|
|
Feb 6 2018, 16:33
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(ViKo @ Feb 6 2018, 16:57)  Это уж дудки. В каждой операции цикла сделает все, что приказали. Он может даже количество итераций сделать не такое как Вы указали - например: объединить каждую чётную и нечётную итерации в одну, уменьшив их число в 2 раза. Может разбить цикл на два: в одном цикле объединить итерации попарно, в другом - выполнять по одной. И ещё много чего может. Попробуйте как-нить включить максимальную оптимизацию. Цитата(Сергей Борщ @ Feb 6 2018, 17:48)  Вас ждет еще много открытий в жизни. Посмотрите листинги своих программ повнимательнее. Я думаю, что ViKo никогда ещё не включал оптимизацию. И не заглядывал при этом в асм
|
|
|
|
|
Feb 6 2018, 16:41
|

Знающий
   
Группа: Свой
Сообщений: 584
Регистрация: 22-11-07
Из: Курская область
Пользователь №: 32 571

|
Цитата(ViKo @ Feb 6 2018, 15:34)  Имею массив из float и указатель на него. Код pSigRe = SigRe; *pSigRe++ = log2f(*pSigRe) * 15.0515; Точно, так нельзя писать?  Должно выполняться по порядку: 1. (*pSigRe) 2. log2f() 3. pSigRe++ 4. *pSigRe 5. умножение 6. присвоение. ИМХО так делать можно, компилятор не должен ругаться.
|
|
|
|
|
Feb 6 2018, 17:23
|
Гуру
     
Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493

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

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

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

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Не считайте упрямством, хочу разобраться. Постинкремент переменной работает после того, как ее использовали. Следовательно, после того, как будет записано вычисленное выражение. Логично? Цитата(AnatolyT @ Feb 6 2018, 21:41)  Если SigRe это массив, может следует к нему обращаться как к массиву. Можно и к массиву. Предполагаю, что для ARM это будет работать так же легко и быстро, как и по указателю. Но я люблю указатели. Деды так завещали. Цитата(jcxz @ Feb 6 2018, 19:33)  Я думаю, что ViKo никогда ещё не включал оптимизацию. И не заглядывал при этом в асм  Первое высказывание исключает второе. Если учесть, что оба неверные, следует, jcxz = трепач.
|
|
|
|
|
Feb 6 2018, 20:24
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата(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 Аналогично и в Вашем случае.
Сообщение отредактировал Arlleex - Feb 6 2018, 20:47
|
|
|
|
|
Feb 6 2018, 21:37
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(ViKo @ Feb 6 2018, 22:00)  Не считайте упрямством, хочу разобраться. Постинкремент переменной работает после того, как ее использовали. Следовательно, после того, как будет записано вычисленное выражение. Логично? После того как была выполнена конкретная операция, а не всё выражение. Постинкремент же относится к операции, а не ко всему выражению. Логично?  Цитата(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++;И в результат компиляции выдал первый вариант. Хотя вполне справедливо мог и второй - это как ему удобнее.
|
|
|
|
|
Feb 7 2018, 05:10
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Мог бы... Но не сделал. А сделал так, как мне и было нужно. Это я констатирую факт. Переписать, чтобы инкрементировался указатель отдельным выражением, легко. Выше уже давно сделал. Вопрос, почему CppCheck ругается, а Keil молча делает, как было задумано. Кто из них тупит? Цитата(Arlleex @ Feb 7 2018, 00:01)  А окружение этой команды можно привести? До и после... Можно сказать, Вам повезло  Покажу оба варианта, ближе к обеду.  И оптимизацию разную проверю.
|
|
|
|
|
Feb 7 2018, 05:41
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата(ViKo @ Feb 7 2018, 08:10)  Вопрос, почему CppCheck ругается, а Keil молча делает, как было задумано. Кто из них тупит? Не знаю что за CppCheck, но он тут молодец, что предупредил. А Keil не молодец. Хотя может и молодец, что схавал, полагаясь на компетентность программиста (а иногда так и хочется наорать на компилятор "я знаю что я делаю, тварь!"  ). Хотя и не молодец, хотя бы warning бы кинул... Цитата(V_G @ Feb 7 2018, 08:22)  Я думаю, если ассемблер данного конкретного контроллера поддерживает постинкремент указателей, и компилятор использует это свойство, то результат будет всегда один. Если же перейти на проц, где нет этой фичи (или уже не хватает регистров для указателей), результаты компиляции могут быть неоднозначными. Как радиоинженер и непрофессиональный программист, я тоже предпочитаю не вспоминать приоритеты и не жалеть скобок. Ассемблер тут совершенно ни при чем. Это полностью зависит от компилятора. Реализовано ли в системе команд постинкремент или нет, совершенно не важно, компилятор может спокойно разбить постинкремент на несколько инструкций. Я не понимаю одного - если в стандарте четко написано о таких вещах, зачем намеренно создавать себе проблему "кодированием через пробы и ошибки"? Ведь даже элементарное включение оптимизации может привести совершенно к другому порядку инструкций, и гарантировать равнозначное поведение в данном случае невозможно.
|
|
|
|
|
Feb 7 2018, 06:16
|
Местный
  
Группа: Участник
Сообщений: 326
Регистрация: 30-05-06
Пользователь №: 17 602

|
Решил проверить в 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; Выходит, что нельзя так.
|
|
|
|
|
Feb 7 2018, 09:53
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
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
|
|
|
|
|
Feb 7 2018, 11:43
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(V_G @ Feb 7 2018, 07:22)  Я думаю, если ассемблер данного конкретного контроллера поддерживает постинкремент указателей, и компилятор использует это свойство, то результат будет всегда один. Нет, это не так. Это только означает что в данном конкретном случае оптимизатору выгоднее было использовать такой набор команд. Если вдруг окажется, что эта команда находится в цикле со множеством постинкрементных адресаций в пределах одной итерации цикла: Код p = &array[0]; do { i0 = *p++; ... i1 = *p++; ... i2 = *p++; ... i3 = *p++; } while (); то оптимизирующий компилятор сделает: Код p = &array[0] - 4; do { LDR R1, [R0, #16]! ... LDR R2, [R0, #4] ... LDR R3, [R0, #8] ... LDR R4, [R0, #12] } while (); потому что все эти команды внутри цикла в сумме по размеру будут == 4+2+2+2 байт - это меньше, чем: Код do { LDR R1, [R0], #4 ... LDR R2, [R0], #4 ... LDR R3, [R0], #4 ... LDR R4, [R0], #4 } while (); итого == 4+4+4+4 байт. В таких случаях выгоднее (в системе команд Cortex-M) сделать один раз приращение указателя в теле цикла, чем в каждой точке *p++.
|
|
|
|
|
Feb 7 2018, 13:20
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Цитата(Kabdim @ Feb 7 2018, 16:22)  Удивляет что половина вроде как "опытных" "своих" не знают причин почему так получается. Для этого и существует форум, ИМХО, для обмена опытом и т.д. Между прочим, такие вещи в книгах особо и не описываются, поэтому даже грамотные специалисты могут и не знать не помнить каких-то подводных камней... Отдельное спасибо jcxz за пример оптимизирующего решения. Я же все никак до ассемблера кортексов не доберусь...
Сообщение отредактировал Arlleex - Feb 7 2018, 13:33
|
|
|
|
|
Feb 7 2018, 14:14
|
Гуру
     
Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493

|
Цитата(Kabdim @ Feb 7 2018, 15:22)  Удивляет что половина вроде как "опытных" "своих" не знают причин почему так получается. Просто не пользуются и все такими конструкциями. Код template<class... Ts> struct overloaded : Ts... {};
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
// usage
overloaded {[](auto arg) {}, [](double arg) {}}; Многие опытные скажут как это работает? Не пользуешься и не знаешь, ничего стыдного
|
|
|
|
|
  |
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|