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

В массиве 40 строк, каждая по 6 символов, и плюс /0. Итого 280 байтов. Нигде в другом месте эти строки не повторяются, хотя, хвостики похожие можно найти. В map вижу размер 160 байтов, в RAM.
Не в том ли загадка, что задан массив статических
указателей?
Получается, размер в ОЗУ точно равен размеру указателей!
Может, правильнее двумерный массив использовать?
Если это внутри функции, то, возможно, просто стека не хватает для не-static объявления. Каждый раз, при заходе в функцию, происходит выделение и массива указателей, и массива данных на стеке, и туда копируется содержимое. А в случае static - все статически лежит в .const (или .rodata). Вот и разница.
Правильно, использовать или static объявление, или вне ф-ции (и, тоже static). А вот объявлять такое внутри функции без static - категорически неправильно.
Если задаю const chat *Text, что заставляет компилятор не извлекать строки прямо из flash-памяти? Я же их только читаю.
Цитата(ViKo @ Jan 14 2015, 19:47)

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

Объявление переменной внутри ф-ции без "static" подразумевает, что переменная лежит на стеке, и всем совершенно все равно, только читаете Вы ее, или не только.
Так что, чтобы оно лежало во флеш - или объявляйте ВНЕ функции (тут static будет лишь ограничивать видимость идентификатора внутри файла, поэтому, он желателен, но не обязателен), или внутри функции, но обязательно со static.
Ну-ну...
тут тоже будет на переменная на стеке ?
int Foo(int arg)
{
const int A = 23;
return A+arg;
}
Умный компилятор сам должен разобраться в константах/переменных, а если он глючный и тупой, то придется глядеть в листинг.
Да, в случае с Ц++ статические объекты внутри функций ведут себя по-другому относительно чистого Ц.
Цитата(CrimsonPig @ Jan 14 2015, 22:03)

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

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

Только надо еще проверить, чтобы эта секция на самом деле во флеш попала, по мап-файлу.
Да, я вижу адрес массива указателей в map-файле. И размер 160 байтов. Сами строки - где-то... ну, это как и должно быть.
Ох, наскребу завтра свободного ОЗУ!
CrimsonPig
Jan 14 2015, 23:38
Цитата(ViKo @ Jan 14 2015, 20:12)

Я сделал (?, проверю работоспособность завтра) иначе:
Код
static const char * const Text[]
Теперь массив указателей размещен во flash.
а чему удивляться-то ?
"const char*" это указатель на константу. содержимое по указателю изменять нельзя, а вот сам указатель - можно.
То есть его в теории нельзя пихать в RO - секцию. С другой стороны, умный компилятор мог бы и разобраться, что
эти переменные никогда не меняются и сделать соотв. оптимизацию.
"const char* const" это константрый указатель на константу. ни его, ни значение по его адресу менять нельзя.
ИМХО, комбинировать в разных сочетаниях static & const в надежде, что компилятор запихнет что-то во флэш, это непрофессиональные танцы с бубном.
Завтра выйдет новая версия компилятора, или флаг оптимизации кто поменяет и все развалится.
static const *text[] используется у отцов-основателей K&R, но не объясняется, зачем. Аналогично у Шилдта.
static const * const text описывается в руководстве на компилятор Hi-Tech для PIC.
Пользуюсь Keil, круче компилятора нет, imho.
Проверил. Все работает.
Заодно посмотрел, что получается при const char * const. Вышло, как ожидалось - указатели во флэш, при входе в функцию перекидываются в область стека. Ерунда, одним словом.
Напоследок попытал безумный
static const char * static const Text[]
Получил
error: #40: expected an identifier
error: #20: identifier "Text" is undefined
Ну, все в строгом соответствии с ANSI/IEC. Вывод из этой ветки - KEIL соответствует стандарту
Andrew2000
Jan 15 2015, 18:17
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.