статическая константа и константная декларация - PullRequest
0 голосов
/ 05 февраля 2019

Допустим, у меня есть таблица поиска, массив из 256 элементов, определенных и объявленных в заголовке с именем lut.h.Массив будет доступен несколько раз за время существования программы.

Насколько я понимаю, если он определен и объявлен как статический, он останется в памяти до завершения программы, т. Е. Если это задача, выполняемая в uC, массив находится в памяти все время.

Где, как без статического, он будет загружен в память при доступе.

В lut.h

    static const float array[256] = {1.342, 14.21, 42.312, ...}

против

    const float array[256] = {1.342, 14.21, 42.312, ...}

Учитывая, что в uC ограничены spiflash и psram, какой подход был бы наиболее ориентирован на производительность?

Ответы [ 2 ]

0 голосов
/ 05 февраля 2019

У вас есть некоторые заблуждения, поскольку MCU не является ПК.Все в памяти в MCU будет сохраняться до тех пор, пока MCU имеет питание.Программы не заканчиваются и не возвращают ресурсы хост-ОС.

«Задачи» на MCU означают, что у вас есть ОСРВ.Они используют свой собственный стек, и это отдельная тема, совершенно не связанная с вашим вопросом.Это нормально, что все задачи в ОСРВ выполняются вечно, а не распределяются / освобождаются во время выполнения процессов, подобных ПК.

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


Где, как без статического, он будет загружен в память при доступе.

Только если загружаемый массив объявлен локально.То есть:

void func (void)
{
  int my_local_array[] = {1,2,3};
  ...
}

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

  • Фактическое копирование с флэш-памяти в ОЗУ составляет медленно .Прежде всего, копирование чего-либо всегда происходит медленно, независимо от ситуации.Но в конкретном случае копирования из ОЗУ на флэш-память это может быть очень медленным, в зависимости от MCU.

    Это будет очень медленно на высокопроизводительных MCU с состояниями ожидания флэш-памяти, которые не используют кэш данных для копии.Это будет очень медленным на странных микроконтроллерах Гарвардской архитектуры, которые не могут обращаться к данным напрямую.И т. Д.

    Естественно, если вы выполняете эту копию каждый раз, когда вызывается функция, а не один раз, ваша программа будет работать намного медленнее.

  • Большие локальные объектыпривести к необходимости увеличения размера стека.Стек должен быть достаточно большим, чтобы справиться с наихудшим сценарием.Если у вас есть большие локальные объекты, размер стека нужно будет установить намного выше, чтобы предотвратить переполнение стека.Это означает, что на самом деле это может привести к менее эффективному использованию памяти.

Так что нетрудно определить, сохраняете ли вы память или теряете ее, делая объект локальным.

Общая рекомендация по проектированию в программировании встроенных систем состоит в том, чтобы не выделять большие объекты в стеке, поскольку они делают обработку стека намного более детальной и увеличивает вероятность переполнения стека.Такие объекты должны быть объявлены как static в области видимости файла.Особенно, если важна скорость.


static const float array против const float array

Еще одно заблуждение здесь.Создание чего-то const в системе MCU, в то же время помещая его в область видимости файла («глобальный»), скорее всего означает, что переменная окажется во флэш-ПЗУ, а не в ОЗУ.Независимо от static.

В большинстве случаев это предпочтительнее, поскольку в целом ОЗУ является более ценным ресурсом, чем флэш-память.Роль static здесь играет просто хороший дизайн программы, поскольку он ограничивает доступ к переменной локальным модулем перевода, а не загромождает глобальное пространство имен.


В lut.h

Вы никогда не должны определять переменные в заголовочных файлах.

Это плохо с точки зрения разработки программы, поскольку вы выставляете переменную повсеместно («программирование спагетти»), и плохо с точки зрения компоновщика, если несколько исходных файлов включаюттот же заголовочный файл - что весьма вероятно.

Правильно спроектированные программы помещают переменную в файл .c и ограничивают доступ, объявляя ее static.Доступ извне, если необходимо, осуществляется через сеттеры / геттеры.


Он имеет ограниченный spiflash

Что такое "spiflash"?Внешняя последовательная флэш-память доступна через SPI?Тогда ничего из этого не имеет смысла, так как такая флэш-память не отображена в памяти и обычно компилятор не может ее использовать.Доступ к таким воспоминаниям должен осуществляться вашим приложением вручную.

0 голосов
/ 05 февраля 2019

Если ваши массивы определены на уровне файлов (вы упомянули lut.h), и оба имеют квалификаторы const, они не будут загружены в ОЗУ¹.Ключевое слово static только ограничивает область действия массива, оно никак не изменяет его время жизни.Если вы проверите сборку для своего кода, вы увидите, что оба массива при компиляции выглядят одинаково :

static const int static_array[] = { 1, 2, 3 };
const int extern_array[] = { 1, 2, 3};

extern void do_something(const int * a);
int main(void)
{
    do_something(static_array);
    do_something(extern_array);
    return 0;
}

Результирующая сборка:

main:
        sub     rsp, 8
        mov     edi, OFFSET FLAT:static_array
        call    do_something
        mov     edi, OFFSET FLAT:extern_array
        call    do_something
        xor     eax, eax
        add     rsp, 8
        ret

extern_array:
        .long   1
        .long   2
        .long   3

static_array:
        .long   1
        .long   2
        .long   3

Вкл.с другой стороны, если вы объявите массивы внутри функции, то массив будет скопирован во временное хранилище (стек) на время действия функции, если вы не добавите квалификатор static:

extern void do_something(const int * a);
int main(void)
{
    static const int static_local_array[] = { 1, 2, 3 };
    const int local_array[] = { 1, 2, 3 };

    do_something(static_local_array);
    do_something(local_array);

    return 0;
}

Результирующая сборка:

main:
        sub     rsp, 24
        mov     edi, OFFSET FLAT:static_local_array
        movabs  rax, 8589934593
        mov     QWORD PTR [rsp+4], rax
        mov     DWORD PTR [rsp+12], 3
        call    do_something
        lea     rdi, [rsp+4]
        call    do_something
        xor     eax, eax
        add     rsp, 24
        ret

static_local_array:
        .long   1
        .long   2
        .long   3

¹ Точнее, это зависит от компилятора.Некоторым компиляторам понадобятся дополнительные пользовательские атрибуты, чтобы точно определить, где вы хотите хранить данные.Некоторые компиляторы пытаются разместить массив в ОЗУ, когда достаточно свободного места, чтобы обеспечить более быстрое чтение.

...