Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: static const vs const
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
ViKo
Добавил к программе еще немного вывода текстовых строк, задал их в виде массива, условно:
const char *Text[] = { "text1", "text2", "text3" };
И функцию, естественно, для вывода, аналогичную другим таким же.
И - завалил программу! Улетает при старте в HardFault, как понял, из недр RTOS (Keil CMSIS-RTOS RTX), пытаясь выделить некую память из пула. Я и размер кучи изменял, и стек задач, и ничего не помогает.
Стал с прошлым вариантом сравнивать (вот где пришлись кстати TortoiseHg c Total Commander). Делаю небольшие изменения, компилирую, запускаю. Дошел до этого массива. И как только добавил static const char *Text.... все заработало.
Поможите люди добрые, объясните, как такое могёт быть? Проект выложить не могу, он великий и коммерческий. Хотелось бы понять принцип.
Файлов в проекте - штук 20. И память используется сильно, не могу сказать, вся / не вся. Если компилируется, значит, есть куда пихать?
SM
а это сильно зависит от того, где определены эти строки (внутри ф-ции, или снаружи). В результате модификатора "static" может менятся секция, где размещены сами данные, а также может добавляться/убираться процес копирования этих данных в стек. Еще может быть, что в нескольких модулях определен символ с именем Text (и, при этом, вовсе не обязательно того же типа), и при объявлении без static (и вне ф-ции), объявление этого символа глобальным убивает что-то еще, совсем не тут.
ViKo
Массив - внутри функции. Имя - уникальное (реально - иное), проверил поиском по всем исходникам, удостоверился.
Глянул в map файл. Это имя нашлось в RAM. Как это? w00t.gif
В массиве 40 строк, каждая по 6 символов, и плюс /0. Итого 280 байтов. Нигде в другом месте эти строки не повторяются, хотя, хвостики похожие можно найти. В map вижу размер 160 байтов, в RAM.
Не в том ли загадка, что задан массив статических указателей?
Получается, размер в ОЗУ точно равен размеру указателей!
Может, правильнее двумерный массив использовать?
SM
Если это внутри функции, то, возможно, просто стека не хватает для не-static объявления. Каждый раз, при заходе в функцию, происходит выделение и массива указателей, и массива данных на стеке, и туда копируется содержимое. А в случае static - все статически лежит в .const (или .rodata). Вот и разница.

Правильно, использовать или static объявление, или вне ф-ции (и, тоже static). А вот объявлять такое внутри функции без static - категорически неправильно.
ViKo
Если задаю const chat *Text, что заставляет компилятор не извлекать строки прямо из flash-памяти? Я же их только читаю.
SM
Цитата(ViKo @ Jan 14 2015, 19:47) *
Если задаю const chat *Text, что заставляет компилятор не извлекать строки прямо из flash-памяти? Я же их только читаю.

Объявление переменной внутри ф-ции без "static" подразумевает, что переменная лежит на стеке, и всем совершенно все равно, только читаете Вы ее, или не только.
Так что, чтобы оно лежало во флеш - или объявляйте ВНЕ функции (тут static будет лишь ограничивать видимость идентификатора внутри файла, поэтому, он желателен, но не обязателен), или внутри функции, но обязательно со static.
CrimsonPig
Цитата(SM @ Jan 14 2015, 16:59) *
Объявление переменной внутри ф-ции без "static" подразумевает, что переменная лежит на стеке, и всем совершенно все равно, только читаете Вы ее, или не только.
Так что, чтобы оно лежало во флеш - или объявляйте ВНЕ функции (тут static будет лишь ограничивать видимость идентификатора внутри файла, поэтому, он желателен, но не обязателен), или внутри функции, но обязательно со static.


Ну-ну...
тут тоже будет на переменная на стеке ?

int Foo(int arg)
{
const int A = 23;

return A+arg;
}

Умный компилятор сам должен разобраться в константах/переменных, а если он глючный и тупой, то придется глядеть в листинг.
Да, в случае с Ц++ статические объекты внутри функций ведут себя по-другому относительно чистого Ц.
SM
Цитата(CrimsonPig @ Jan 14 2015, 22:03) *
тут тоже будет на переменная на стеке ?

Если отключите все оптимизации, то должна быть именно там. Если включите, скорее всего этой переменной вообще не будет. Но не надо путать такой простой случай с массивом строк. Его в непосредственную константу не соптимизируешь. Разумеется, речь про С, без плюсов. С плюсами я не знаю, как оно обязано быть.
ViKo
Посмотрел листинги со static и без.
Для const при входе в функцию указатель стека опускается на 164, в R2 заносится 160, в R1 заносится адрес из области .constdata, затем SP копируется в R0 и вызывается __aeabi_memcpy4. В-общем, копируются указатели. Дальше идут манипуляции относительно указателя стека, а в конце он восстанавливается. В map-файле текстовый массив не упоминается.
Для static const указатель загружается из ОЗУ. В map-файле есть конкретное расположение массива указателей.
SM
Ну, о чем я и говорил. Скорее всего у Вас стека маловато, и он переполняется.
А чтобы расположить константы сразу во флеш, без копирования в ОЗУ, вероятно, надо с линкером помудрить, чтобы секция констант там оказалась (но флеш медленная, в отличие от ОЗУ, поэтому не факт, что всем константам там место). Кстати, в какой секции оказываются константы со static?
ViKo
Я сделал (?, проверю работоспособность завтра) иначе:
Код
static const char * const Text[]

Теперь массив указателей размещен во flash.
Вижу, что размер RO-data увеличился на 160 байтов, а RW-data на столько же уменьшился.
yeah.gif
SM
Цитата(ViKo @ Jan 14 2015, 23:12) *
Теперь массив указателей размещен во flash.

Только надо еще проверить, чтобы эта секция на самом деле во флеш попала, по мап-файлу.
ViKo
Цитата(SM @ Jan 14 2015, 23:15) *
Только надо еще проверить, чтобы эта секция на самом деле во флеш попала, по мап-файлу.

Да, я вижу адрес массива указателей в map-файле. И размер 160 байтов. Сами строки - где-то... ну, это как и должно быть.
Ох, наскребу завтра свободного ОЗУ!
CrimsonPig
Цитата(ViKo @ Jan 14 2015, 20:12) *
Я сделал (?, проверю работоспособность завтра) иначе:
Код
static const char * const Text[]

Теперь массив указателей размещен во flash.


а чему удивляться-то ?

"const char*" это указатель на константу. содержимое по указателю изменять нельзя, а вот сам указатель - можно.
То есть его в теории нельзя пихать в RO - секцию. С другой стороны, умный компилятор мог бы и разобраться, что
эти переменные никогда не меняются и сделать соотв. оптимизацию.

"const char* const" это константрый указатель на константу. ни его, ни значение по его адресу менять нельзя.

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

ViKo
static const *text[] используется у отцов-основателей K&R, но не объясняется, зачем. Аналогично у Шилдта.
static const * const text описывается в руководстве на компилятор Hi-Tech для PIC.
Пользуюсь Keil, круче компилятора нет, imho.
ViKo
Проверил. Все работает.
Заодно посмотрел, что получается при const char * const. Вышло, как ожидалось - указатели во флэш, при входе в функцию перекидываются в область стека. Ерунда, одним словом.
Напоследок попытал безумный
static const char * static const Text[]
Получил
error: #40: expected an identifier
error: #20: identifier "Text" is undefined
SM
Ну, все в строгом соответствии с ANSI/IEC. Вывод из этой ветки - KEIL соответствует стандарту sm.gif
Andrew2000
на эту тему:

http://rus-linux.net/MyLDP/algol/Shared-Li...ries-2.4.1.html

от 2.4.1 до 2.4.4
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.