Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить

Re: О volatile замолвлю я слово

Пн янв 24, 2022 17:16:51

Охохо, а хотите ещё масла в огонь подолью? Volatile можно ещё на функции применять!

Re: О volatile замолвлю я слово

Пн янв 24, 2022 17:20:42

И это правильно и логично.

Re: О volatile замолвлю я слово

Пн янв 24, 2022 17:50:27

>TEHb<, только что проверил и на gcc, и на clang пример отсюда. Не работает volatile применительно к функции в языке С!

Re: О volatile замолвлю я слово

Пн янв 24, 2022 18:14:55

Eddy_Em, всё верно говоришь. volatile можно только к методам класса (тобишь C++) применять и влияет он на доступ к this. Compiler Exploer

Re: О volatile замолвлю я слово

Пн янв 24, 2022 18:59:26

да.... а старые компиляторы могли, по крайней мере, мне попадались такое в коде. Странно. Вроде же вполне логично: возвращаемое значение функции может быть бессмысленным с точки зрения оптимизатора, притом вызов как есть функции важен по каким либо-причинам.
Впрочем, это можно легко реализовать, но запись получится длиньше и страньше.

Re: О volatile замолвлю я слово

Пн янв 24, 2022 20:36:31

Давно пора привыкнуть, что программа не то что вы о ней думаете, а то что о ней думает компилятор.

Кто объяснит, как сущность размером в 1 байт хранит значения явно большей разрядности?
Compiler Exploer

Естественно, никакая другая память нигде не используется, если что. Скажу больше, там даже байта нет, просто компилятор не может признаться, что у него объект размером меньше байта :)

Добавлено after 49 minutes 27 seconds:
Вроде же вполне логично: возвращаемое значение функции может быть бессмысленным с точки зрения оптимизатора, притом вызов как есть функции важен по каким либо-причинам.
Это называется побочный эффект. Вот именно там где он создаётся и должна стоять volatile. Функции это даром не надо. Компилятор может этот эффект просчитать и воспроизвести без лишней шелухи.

Re: О volatile замолвлю я слово

Вт янв 25, 2022 10:02:34

Eddy_Em, как конкретно писали? У меня GCC принимает объявление функции
Код:
void volatile init()
{
};

и работает с ней так, как я того и ожидаю. Фактически ничего не оптимизируя внутри этой функции.

Re: О volatile замолвлю я слово

Вт янв 25, 2022 10:52:55

Брехня! :)
Изображение
volatile.png
(29.12 KiB) Скачиваний: 331
Как в самой функции пусто, так и её вызова вообще нет. volatile перед функцией относится к типу возвращаемого ей результата. Ко всему что происходит внутри это не имеет отношения.

Re: О volatile замолвлю я слово

Вт янв 25, 2022 11:03:23

>TEHb<, какая версия gcc? Я проверял на 10 и 11 — не работает volatile, да и не должен. Не помню я такого, чтобы в стандарте С были бы волатильные функции!

Re: О volatile замолвлю я слово

Вт янв 25, 2022 11:22:32

8.3 , если не ошибаюсь. Наверно, стоило сразу уточнить, что речь про компиляцию под ARM, а конкретно Cortex-M4 ядро. Короче, ситуация такая: программа под СТМку и в этом самом ините как раз и идёт настройка всего и вся оборудования. Некоторые узлы требуют или ожидание готовности флага или некоторую фиксированную задержку. Без volatile порядок записи в регистры периферии сохранялся, а вот время "оптимизировалось". Ну и привет, ничего не работает. Добавил волшебное слово и вуаля! Все времена сохранятся как просил. Иначе, делал через прагму с конкретным указанием уровня оптимизации, но это как-то криво показалось.

Re: О volatile замолвлю я слово

Вт янв 25, 2022 11:29:19

Изображение

Re: О volatile замолвлю я слово

Ср янв 26, 2022 18:22:03

Ну да, вы правы. Секрет заблуждения оказался в том, что, видимо, дописал квалификатор к одной переменной одновременно с функцией. Ну и получил, конечно же, желаемый эффект. Компилятор при оптимизации на скорость по сравнению с выключенной, всё-таки немного корёжит порядок (собирает LDR-ы паровозиком), но побочки оставляет как его и попросили. Короче, крутил, вертел, и что с volatile на функции, что без, получал одинаковый выхлоп.

P.S.: ну не брехня, но точно ошибка

Re: О volatile замолвлю я слово

Ср янв 26, 2022 19:22:14

Тоже полазил, и где-то промелькнуло, что когда-то давно функции волатилили чтобы что-то там с возвратом void было корректно. Как говорится, уже забыл, а что вспомнил переврал, но примерно так :)) Похоже, решалась какая-то особенность компилятора и достойно теперь лишь археологов

Re: О volatile замолвлю я слово

Чт янв 27, 2022 09:21:43

ох какая тема живучая)

Re: О volatile замолвлю я слово

Сб янв 29, 2022 19:22:51

А вот, если не влом поясните, как понимать... если переменная используется не явно. вот пример кода:
Код:
uint32_t fram_log_decode (instance_t *instance, int *none) {
    static data_buffer_t log_buffer;
    unsigned int record_count = 0, ii, jj, mask;

    FRAM_dma_read_Start(0x00000));
    FRAM_dma_log_read((uint8_t*)&record_count, sizeof(record_count)));
    FRAM_dma_wait_EOT();

    for (ii = 0; ii < record_count; ii++) {
        FRAM_dma_log_read((uint8_t*)&log_buffer, sizeof(log_buffer)));
итд... 
В коде читается SPI FRAM в первых четырёх ячейках хранится 32 битное число записей, которое надо прочитать в переменную record_count, которая тут же используется в цикле for для считывания этих записей, которые идут дальше. проблема в том, что явно я туда не пишу - передаю только указатель на эту переменную. И внутри функции FRAM_dma_log_read там тоже нет явной записи. Как следует из названия, там программируется DMA, который и сделает (а может и не сделает) эту запись. Тогда получается, что формально, я эту переменную обязан обозвать волатильной? И структуру log_buffer тоже?

Re: О volatile замолвлю я слово

Сб янв 29, 2022 19:39:46

Да, конечно. Если данные в переменной появляются в результате работы прерывания или dma, то она должна быть volatile. В случае с указателями и массивами компилятору тяжело проследить, что вообще нигде нет обращений и чаще всего всё будет работать. Ваш код с FRAM скорее всего тоже. Но это недоработка компилятора и нет никаких гарантий, что завтра он не станет настолько умным, что всё почикает. Так что, действуйте формально - всё что может поменяться из DMA пусть будет volatile. Спать будете спокойней точно.

Re: О volatile замолвлю я слово

Сб янв 29, 2022 21:35:50

А вот не получается спокойно спать. Проблема в том, что есть только одна операция, которая требует чтобы структура log_buffer был волатильной - это чтение из FRAM, а потом идёт разбор этих данных с выводом. И вот там уже волатильность крайне вредна, потому как данные после того как считались поменяться никак не могут до следующей итерации. Нельзя ли как-нибудь этот момент корректно обойти. Может каким хитрым приведением типов? Например, указать что функции FRAM_dma_log_read передаётся указатель на волатильную переменную, а подсунуть обычную, приведенную к волатильному типу (как сейчас привожу к байтовому типу)

Re: О volatile замолвлю я слово

Сб янв 29, 2022 22:41:06

Проблема в том, что есть только одна операция, которая требует чтобы структура log_buffer был волатильной - это чтение из FRAM,
Вот тут это как раз до одного места. DMA передаётся тупо адрес, что там по нему лежит ему неинтересно.

а потом идёт разбор этих данных с выводом. И вот там уже волатильность крайне вредна,
Тут надо смотреть что такое data_buffer_t. А то ведь в зависимости от этого вредность может варьироваться от нулевой до вредной. В крайне вредную я не верю, не ходите же вы по ней туда-сюда-обратно. Покажите определение data_buffer_t.

Re: О volatile замолвлю я слово

Вс янв 30, 2022 12:11:20

VladislavS писал(а):Тут надо смотреть что такое data_buffer_t.
А там не на что смотреть - просто 23 байта:
Код:
    typedef struct data_buffer {
        uint32_t Time;              // 4
        union{
            struct{
                int16_t setspeedLeft;       // 2
                int16_t setspeedRight;      // 2
                int16_t RealSpeedLeft;      // 2
                int16_t RealSpeedRight;     // 2
                int32_t StepsLeft;          // 4
                int32_t StepsRight;         // 4
                uint8_t vbat;
                uint8_t sensors;
            };
            struct{
                int coordX;                 // 4
                int coordY;                 // 4
                unsigned int segmentLength; // 4
                int nodeNum;                // 4
            };
        };
        uint8_t whereami;
    }  __attribute__((packed)) data_buffer_t;
И пока их интерпретация довольно проста - числа выводятся в обычном представлении. Ну, чуть поразвесистей работа с полем sensors и whereami:
Конечно, тут я уже не спешу - считавание лог-файла это не realtime задача - это уже постфактум и тут оптимизация мне не требуется.
Просто сама мысль, как писать правильно?

Вот, допустим, у меня была функция чтения FRAM сделанная по-тупому:
Код:
unsigned int FRAM_log_read(uint8_t *rd_data_ptr, unsigned int wr_data_size) {
    while (wr_data_size--) {
        *rd_data_ptr++ = get_byte_from_fram();
    }
}
Вроде, там явное присваивание и волатильность совсем не требуется. Но со временем я хочу улучшить работу и делаю это или через прерывания, или ПДП, но сохраняя интерфес вызова этих функций, чтобы не переписывать те куски, где она вызывалась.
Но тут уже всё, явного присваивания нет и компилятор и/или линкер берут и просто выкидывают эти куски кода. Тогда получается, что надо теперь бегать по всем исходникам искать эти вызовы и расставлять модификаторы?

Re: О volatile замолвлю я слово

Вс янв 30, 2022 12:50:38

Что-то вы всё усложняете. Функции копирования (не важно циклом, memcpy или DMA) не надо передавать информацию о том что место куда вы копируете volatile. Вы передаёте просто адрес (указатель) и функция по нему скопирует, у неё нет выбора. Для функции копирования volatile сущностью будет ваша FRAM. Всё, забыли про функцию чтения FRAM.

Переходим к log_buffer. Он должен быть volatile. Потому что при копироапнии в него данных через DMA логика компилятора будет такая: о, смотри ка, глобальный буфер, инициализирован нулями, понятно же что при любом чтении из него будет ноль, ну и буду везде его подставлять без чтения, а там глядишь и половину кода можно даже не компилировать, а выкинуть - красота! Нет, говорим мы, там будет лежать для тебя сюрприз, будь добр взять его и честно отработать.

Теперь давай подумаем, ухудшит ли volatile быстродействие? Конечно, по сравнению с полностью выкинутым кодом да. Но по сравнению с правильно работающей программой нет! У вас развесистая структура, доступ к её полям по адресу этой структуры. Если вы все поля будете читать по одному разу - ничего не изменится. Если какие-то поля стоят в выражениях несколько раз, то будут лишние чтения. Но это легко парировать, прочитали поле в локальную временную переменную и подставляйте куда надо. Так часто делают со статусными регистрами в прерываниях, когда надо от наличия разных битов сделать разные действия. Вошли в прерывание, прочитали регистр статуса в локальную переменную и дальше проверяйте её сколько угодно раз, она будет в регистре процессора лежать. Да, вы должны держать в голове, что работаете с volatile сущностью и тогда штраф за её использование можно свести к нулю.
Ответить