Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Массив во флеш памяти, const, ф-ция hal

Сб мар 13, 2021 22:29:29

Всем привет :))
Подскажите, пожалуйста, как решить проблему. Есть массив, неизменяемый дамп еепромки
Код:
static const uint8_t dump[256] = {0, 1, 2, ...};

и халовская ф-ция,
Код:
HAL_I2C_Mem_Write(..., uint8_t *pData, ...)

где pData указатель на неконстантный буфер с данными. При компиляции выходит предупреждение
warning: passing argument 3 of 'AT24C02_Write' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]

Компилятор ругается на несоответствие. Если сделать привидение типов ..., (uint8_t *)dump, ... то проблема уходит. Но тогда возникает другая, мы сами говорим, что массив изменяемый, и данные в константном массиве могут быть переписаны.

Массив определен константным, чтобы размещение было во flash памяти, и действительно, среда показывает, что массив размещен в секции .rodata. По поводу static не знаю, нужен или нет, в листинге дизассемблера код что с ним, что без него один и тот же. Таких массивов 4 штуки по 256 байт. Они и в ОЗУ нормально размещаются, памяти хватает, но все же как правильно выйти из ситуации, чтобы и массивы разместить во флеше и можно было использовать функции HALa.

Спасибо!

Re: Массив во флеш памяти, const, ф-ция hal

Сб мар 13, 2021 23:03:45

Если сделать привидение типов ..., (uint8_t *)dump, ... то проблема уходит. Но тогда возникает другая, мы сами говорим, что массив изменяемый, и данные в константном массиве могут быть переписаны.

Чтобы данные были переписаны функция по крайней мере должна пытаться их переписывать, а она из массива только читает, так что приводи тип и не жалуйся или напиши свою функцию которая будет принимать константный указатель :)

Re: Массив во флеш памяти, const, ф-ция hal

Сб мар 13, 2021 23:28:31

так что приводи тип и не жалуйся

Понял, можно не заморачиваться. Спасибо!
Про static еще не подскажете, нужен ли он при объявлении и инициализации массива или нет при размещении во флеш? static const dump[256] = {...};
Не понимаю, какую роль он выполняет в данном случае. На Электрониксе была тема https://electronix.ru/forum/index.php?a ... c&id=79620
там товарищ пишет, что без static константа копируется сначала в стек, и только потом используется, что не совсем правильно.
Последний раз редактировалось compote Вс мар 14, 2021 13:46:01, всего редактировалось 1 раз.

Re: Массив во флеш памяти, const, ф-ция hal

Вс мар 14, 2021 03:29:20

Для глобальной переменной static ограничивает область видимости единицей трансляции.

По ссылке речь о локальной переменной. Для неё static имеет другой смысл - делает её глобальной.

Как определить константу в С++. Речь про С++, но для понимания как эта кухня работает стоит ознакомиться.

Re: Массив во флеш памяти, const, ф-ция hal

Вс мар 14, 2021 14:07:35

Для глобальной переменной static ограничивает область видимости единицей трансляции.

Спасибо, вроде разобрался с этим вопросом.
У меня массивы с дампами вынесены в хидер и он подключен к мейну. Соответствено, объявляя в хидере массив со статик, мы ограничиваем его область видимости мейном, а в другом си файле, можно объявить массив с таким же именем и не будет никаких проблем с неопределенностью, правильно?

Спасибо за ссылку на видео, не встречал этот канал, обязательно посмотрю!

Re: Массив во флеш памяти, const, ф-ция hal

Вс мар 14, 2021 14:47:37

а в другом си файле, можно объявить массив с таким же именем и не будет никаких проблем с неопределенностью, правильно?
Специально делать разные массивы с одинаковым именем? Ну это ССЗБ. :)

Re: Массив во флеш памяти, const, ф-ция hal

Вс мар 14, 2021 15:04:01

Ну это ССЗБ. :)

Это так, для примера :lol:

Re: Массив во флеш памяти, const, ф-ция hal

Вс мар 21, 2021 11:33:26

У меня массивы с дампами вынесены в хидер и он подключен к мейну. Соответствено, объявляя в хидере массив со статик, мы ограничиваем его область видимости мейном, а в другом си файле, можно объявить массив с таким же именем и не будет никаких проблем с неопределенностью, правильно?

Не правильно. Никогда не делайте так. Завтра вы забудете про это и подключиьте директивой #include этот ваш хидер к ещё одному или нескольким файлам проекта. И что тогда будет?
Хидеры не предназначены для определений. В них должны быть только объявления. Применительно к вашему случаю, в хидере вы должны объявить ваши константные массивы с квалификатором extern. А определить их в отдельном си-файле, который включить в проект.

Файл dump.h
Код:
#ifndef DUMP_H
  #define DUMP_H
  #include <stdint.h>
  extern const uint8_t dump[];
#endif



Файл dump.c
Код:
#include "dump.h"
const uint8_t dump[8]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};


Теперь во сколько бы файлов проекта вы бы ни подключили свой dump.h, в памяти выделится место лишь под один массив const uint8_t dump[8].

Re: Массив во флеш памяти, const, ф-ция hal

Вс мар 21, 2021 21:27:22

Хидеры не предназначены для определений. В них должны быть только объявления.
Это верно только для Си. На С++ можно в заголовочном файле определить.
Код:
inline constexpr uint8_t dump[]={1,2,3,4,5,6,7,8,9,0};
И подключать куда хочешь. В бинарник данная сущность попадёт один раз.

Re: Массив во флеш памяти, const, ф-ция hal

Вс мар 21, 2021 21:52:43

Это верно только для Си

Не совсем.
В Си встраиваемые функции (inline) должны быть определены в заголовочном файле. Иначе компилятор просто не сможет встроить их код в месте вызова. Он должен видеть "тело", чтобы встроить его. Одного прототипа в этом случае недостаточно.
Но в Си это, пожалуй, единственное исключение из общего правила: в хидере никаких определений, только объявления.

Re: Массив во флеш памяти, const, ф-ция hal

Вс мар 21, 2021 23:06:29

По ссылке речь о локальной переменной. Для неё static имеет другой смысл - делает её глобальной.

Область видимости то не меняется. Просто значение локальной переменной сохраняется при повторном входе в функцию, в отличии от обычного использования, когда она каждый раз инициализируется заново.
С константой и нормальным компилятором по идее разницы для локальной (внутри функции) переменной не должно быть разницы в итоге.

Re: Массив во флеш памяти, const, ф-ция hal

Пн мар 22, 2021 06:57:13

Область видимости то не меняется. Просто значение локальной переменной сохраняется при повторном входе в функцию

Это следствие.
А причина в том, что:
1. Статическим локальным переменным выделяется фиксированный адрес в статической памяти, как и глобальным.
2. В отличии от глобальных переменных, область видимости их ограничивается тем блоком, где они объявлены.

Сохранение значений между вызовами функции - следствие п. 1.
static - квалификатор класса хранилища (хранения, памяти). Ко всем локальным переменным, для которых явно не указан класс хранения применяется квалификатор auto. Что влечет их размещение в стеке. Даже если они константные.

Код:
void foo(void){
  const char a=10; // создается в стеке

}


Код:
void foo(void){
  auto const char a=10; // создается в стеке

}


Код:
void foo(void){
  static const char a=10; // создается в статической памяти,
                                            // имеет постоянный адрес

}

Константность и класс памяти - разные вещи. Хочешь изменить класс памяти локальной переменной с умолчального auto - должен явно сказать это компилятору с помощью квалификатором static. Сам он этого не сделает, даже для константы.

Re: Массив во флеш памяти, const, ф-ция hal

Пн мар 22, 2021 07:04:45

Что такое статическая память?

Re: Массив во флеш памяти, const, ф-ция hal

Пн мар 22, 2021 18:11:50

за статическую память то же не догнал.

...применяется квалификатор auto. Что влечет их размещение в стеке. Даже если они константные...
и это не помещается в мои представления о стеке.

...void foo(void){
const char a=10; // создается в стеке...
10 - это менее 12-ти разрядов, мне представляется, что в данном случае она будет просто внутри инструкции, а не ячейкой в какой-либо памяти.

Re: Массив во флеш памяти, const, ф-ция hal

Пн мар 22, 2021 20:06:56

Что такое статическая память?

Насколько это жаргон, а насколько общепринятая терминология, не могу судить. Но лично я вкладываю в это понятие такой смысл: это область памяти, которую выделяет компоновщик/линкер во время своей работы (компоновки/линковки) для хранения объектов программы с временем жизни, равным времени работы программы.
Применительно к данным, размещаемым там, это глобальные, а также локальные статические переменные и константы.
Такие данные:
- существуют все время работы программы;
- инициализируются до входа в main() явно заданными в программе инициализаторами или, если таковые отсутствуют, нулями;
- имеют постоянный адрес размещения в памяти на протяжении всего времени жизни.

Добавлено after 15 minutes 35 seconds:
10 - это менее 12-ти разрядов, мне представляется, что в данном случае она будет просто внутри инструкции, а не ячейкой в какой-либо памяти.

Именно так может сделать компилятор. Но может и не сделать. Потому, что не обязан. Ожидать от него именно такого поведения, и строить на этом предположении какие-либо выводы нельзя.
Стандарт позволяет компиляторам очень вольно обходиться с квалификаторами auto и register, вплоть до их полного игнорирования. Эти моменты отданы на откуп конкретным реализациям компиляторов.
Один компилятор может выделить место в стеке. Второй встроить в код инструкции. Третий - поместить в регистр. И все будут формально правы.
Чтобы не зависеть от деталей реализации конкретного компилятора, следует явно определить класс хранилища и константность: static const.

Re: Массив во флеш памяти, const, ф-ция hal

Пн мар 22, 2021 20:17:47

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

Re: Массив во флеш памяти, const, ф-ция hal

Вт мар 23, 2021 15:02:28

А такой вопрос:
Код:
void foo(void){
  static char a=10; // не важно где создается
                            // важно имеет постоянный адрес
}
Как узнать этот адрес? Что бы я мог обращаться к этой переменной из вне. Интересуюсь в целях уменьшения размера кода, особенно в прерываниях.

Re: Массив во флеш памяти, const, ф-ция hal

Вт мар 23, 2021 16:17:32

Dimon456, тогда логично будет создать эту переменную как глобальную. Локальные переменные имеют смысл именно в ограничении области видимости. Никаких преимуществ в месте вы не получите, храня её как локальную. Но если хочется извращаться - то сделать на неё указатель и в функции присвоить ему значение &a.
Код:
char *a_ptr;

void foo(void){
  static char a=10; // не важно где создается
                            // важно имеет постоянный адрес
  a_ptr = &a;
}

...
  foo();
  if (a_ptr) ...


Добавлено after 3 minutes 27 seconds:
А, как вариант еще из функции вернуть указатель:
Код:
char * foo(void){
  static char a=10; // не важно где создается
                            // важно имеет постоянный адрес
  ...
  return &a;
}
  a_ptr = foo();


Всё-равно имхо лучше с глобалками работать, если их надо где-то еще использовать.

Re: Массив во флеш памяти, const, ф-ция hal

Вт мар 23, 2021 18:17:48

Спрошу по другому,
вот это
Код:
volatile uint32_t n = 1023;
volatile uint32_t a=0;
    
void foo_IRG(void){
  a += n;
}
Код:
volatile uint32_t n = 1023;
    
void foo_IRG(void){
  static uint32_t a=0;

  a += n;
}
влияет на размер самой функции, вот и вопрос возникает - можно ли еще уменьшить размер функции если использовать так
Код:
void foo_IRG(void){
  static uint32_t a=0;
  static uint32_t n=1023; нужен адрес этой переменной -?
  a += n;
}

Re: Массив во флеш памяти, const, ф-ция hal

Вт мар 23, 2021 18:48:19

последний вариант должен хорошо сократить размер - до нуля ;)
сложить два числа и тут же забыть - компилятор такое может просто выкинуть
Ответить