Всем привет Подскажите, пожалуйста, как решить проблему. Есть массив, неизменяемый дамп еепромки
Код:
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.
Если сделать привидение типов ..., (uint8_t *)dump, ... то проблема уходит. Но тогда возникает другая, мы сами говорим, что массив изменяемый, и данные в константном массиве могут быть переписаны.
Чтобы данные были переписаны функция по крайней мере должна пытаться их переписывать, а она из массива только читает, так что приводи тип и не жалуйся или напиши свою функцию которая будет принимать константный указатель
Понял, можно не заморачиваться. Спасибо! Про static еще не подскажете, нужен ли он при объявлении и инициализации массива или нет при размещении во флеш? static const dump[256] = {...}; Не понимаю, какую роль он выполняет в данном случае. На Электрониксе была тема https://electronix.ru/forum/index.php?a ... c&id=79620 там товарищ пишет, что без static константа копируется сначала в стек, и только потом используется, что не совсем правильно.
Последний раз редактировалось compote Вс мар 14, 2021 13:46:01, всего редактировалось 1 раз.
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
Для глобальной переменной static ограничивает область видимости единицей трансляции.
Спасибо, вроде разобрался с этим вопросом. У меня массивы с дампами вынесены в хидер и он подключен к мейну. Соответствено, объявляя в хидере массив со статик, мы ограничиваем его область видимости мейном, а в другом си файле, можно объявить массив с таким же именем и не будет никаких проблем с неопределенностью, правильно?
Спасибо за ссылку на видео, не встречал этот канал, обязательно посмотрю!
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
У меня массивы с дампами вынесены в хидер и он подключен к мейну. Соответствено, объявляя в хидере массив со статик, мы ограничиваем его область видимости мейном, а в другом си файле, можно объявить массив с таким же именем и не будет никаких проблем с неопределенностью, правильно?
Не правильно. Никогда не делайте так. Завтра вы забудете про это и подключиьте директивой #include этот ваш хидер к ещё одному или нескольким файлам проекта. И что тогда будет? Хидеры не предназначены для определений. В них должны быть только объявления. Применительно к вашему случаю, в хидере вы должны объявить ваши константные массивы с квалификатором extern. А определить их в отдельном си-файле, который включить в проект.
Не совсем. В Си встраиваемые функции (inline) должны быть определены в заголовочном файле. Иначе компилятор просто не сможет встроить их код в месте вызова. Он должен видеть "тело", чтобы встроить его. Одного прототипа в этом случае недостаточно. Но в Си это, пожалуй, единственное исключение из общего правила: в хидере никаких определений, только объявления.
По ссылке речь о локальной переменной. Для неё static имеет другой смысл - делает её глобальной.
Область видимости то не меняется. Просто значение локальной переменной сохраняется при повторном входе в функцию, в отличии от обычного использования, когда она каждый раз инициализируется заново. С константой и нормальным компилятором по идее разницы для локальной (внутри функции) переменной не должно быть разницы в итоге.
Область видимости то не меняется. Просто значение локальной переменной сохраняется при повторном входе в функцию
Это следствие. А причина в том, что: 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. Сам он этого не сделает, даже для константы.
...применяется квалификатор auto. Что влечет их размещение в стеке. Даже если они константные... и это не помещается в мои представления о стеке.
...void foo(void){ const char a=10; // создается в стеке... 10 - это менее 12-ти разрядов, мне представляется, что в данном случае она будет просто внутри инструкции, а не ячейкой в какой-либо памяти.
Насколько это жаргон, а насколько общепринятая терминология, не могу судить. Но лично я вкладываю в это понятие такой смысл: это область памяти, которую выделяет компоновщик/линкер во время своей работы (компоновки/линковки) для хранения объектов программы с временем жизни, равным времени работы программы. Применительно к данным, размещаемым там, это глобальные, а также локальные статические переменные и константы. Такие данные: - существуют все время работы программы; - инициализируются до входа в main() явно заданными в программе инициализаторами или, если таковые отсутствуют, нулями; - имеют постоянный адрес размещения в памяти на протяжении всего времени жизни.
10 - это менее 12-ти разрядов, мне представляется, что в данном случае она будет просто внутри инструкции, а не ячейкой в какой-либо памяти.
Именно так может сделать компилятор. Но может и не сделать. Потому, что не обязан. Ожидать от него именно такого поведения, и строить на этом предположении какие-либо выводы нельзя. Стандарт позволяет компиляторам очень вольно обходиться с квалификаторами auto и register, вплоть до их полного игнорирования. Эти моменты отданы на откуп конкретным реализациям компиляторов. Один компилятор может выделить место в стеке. Второй встроить в код инструкции. Третий - поместить в регистр. И все будут формально правы. Чтобы не зависеть от деталей реализации конкретного компилятора, следует явно определить класс хранилища и константность: static const.
Спасибо за уточнение. В целом есть неточности, но смысл понятен. Глобальные данные, вообще говоря, могут быть и неинициализированными. Также могут быть оптимизированы компилятором и линкером.
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();
Всё-равно имхо лучше с глобалками работать, если их надо где-то еще использовать.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 24
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения