Микроконтроллеры

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Микроконтроллеры » RA » HardFault_Handler/ sprintf/ stm32f103


HardFault_Handler/ sprintf/ stm32f103

Сообщений 31 страница 38 из 38

31

Eddy_Em написал(а):

Не могу на эти malloc'и без слез смотреть! Это ж микроконтроллер! Там маллок нафиг не сдался вообще!!!

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

32

RA написал(а):

значит, лучше вообще через calloc, он занулит выделеную память, а уж копировать не копировать конец строки - не важно, место выделено и занулено.

Долго. То ли один байт записать, то ли в цикле кучу байт писать. Причем заметь, сначала весь массив обнуляем, потом копируем. Или сначала копируем и потом один байт обнуляем. Ну тут дело вкуса, как грится.

33

MasterAlexei написал(а):

Долго. То ли один байт записать, то ли в цикле кучу байт писать. Причем заметь, сначала весь массив обнуляем, потом копируем. Или сначала копируем и потом один байт обнуляем. Ну тут дело вкуса, как грится.

на данном этапе, для меня это не имеет значения. два раза пройти буфер или один раз + 1 char. важно чтоб работало предсказуемо и читалось легко.

34

люди добрые может кто пояснит работу этой конструкции.

Код:
if(flag_tx){free(str_temp++);}//очистить строку

освобождение памяти, это понятно, но саму строку оно не уничтожает(зануляет),  то есть если я обращусь по указателю то данные там останутся, а вот если  (str_temp++) то чисто. Как так?  o.O тупо изменяет указатель, который случайным образом указывает на ноль?

35

RA написал(а):

освобождение памяти, это понятно, но саму строку оно не уничтожает(зануляет),  то есть если я обращусь по указателю то данные там останутся, а вот если  (str_temp++) то чисто. Как так?  o.O тупо изменяет указатель, который случайным образом указывает на ноль?

видимо это зависит от реализации кучи. С моей реализацией такого финта не прокатит ;-) данные останутся на своем месте.

36

MasterAlexei написал(а):

видимо это зависит от реализации кучи. С моей реализацией такого финта не прокатит  данные останутся на своем месте.

а можно вкратце в чем суть вашей реализации? только как говорится "на пальцах", я что такое куча узнал совершенно недавно, а понял, что это такое и для чего она, можно сказать, вчера... и наступил диссонанс, с какого перепуга я ей пользуюсь используя си, а не с++...  :tired:   :D может конечно еще по-полочкам все не встало...

37

RA написал(а):

а можно вкратце в чем суть вашей реализации?

Ой. Ну если в кратце, то....
есть массив памяти, определяется в линкер скрипте, как размер так и положение, хотя размер задать в GCC шном линкерскрипте то еще упражнение. Ну не суть.
В общем, при запросе памяти смотрим, сколько ее у нас есть. Для ускорения работы - это просто переменная глобальная. И так же есть у нас переменная, где хранится стартовый адрес первого свободного блока. Отсчитываем от старта блока нужное количество байт, округляем до выравнивания в 32 бита, прибавляем еще 4 байта и еще 4 байта, и это будет наш новый адрес первого свободного блока, а 4 байта назад от этого места пишем какой нить приметный флаг, указывающий на конец выделенного блока (для отладки). Адрес свободного блока сохраняем в глобальную переменную, а по этому адресу записываем его размер. По адресу старта выделенного блока пишем его размер, и возвращяем программе адрес на 4 байта больше, чтоб размер не затерся.
При последующем выделении процедуру повторяем.
При возвращении памяти мы получаем от программы адрес возвращаемого блока, 4 байта назад стоит его реальный размер (об этом позже). Смотрим, где он находится, до или после старта первого свободного, если до, поправляем старт первого свободного. в освобожденный блок в его начало пишем его размер, как говорил выше, и адрес следующего свободного блока. Таким образом у нас строится связный список свободных блоков. В последнем блоке стоит его размер и адрес следующего равен 0.
Про реальный размер выделенного блока: чтоб избежать сильной дефрагментации желательно задать минимально возможный выделяемый размер блока. Например программа запрашивает 10 байт, а мы выделяем 32 байта. И тогда при возвращении этого блока и выделении уже 20 ти байт, будет выделен тот же блок памяти опять, а не больший дробиться будет.
Естественно, при выделении будет искаться свободный блок. в который влезет запрашиваемый размер с учетом минимально допустимого. Если память сильно дефрагментирована, то может так статься, что при "свободной" памяти в 40 кб, но сильно дефрагментированной, выделение 10 кб уже не прокатит.  Потому и надо минимальный размер определить, с учетом общего размера, т.е. сугубо индивидуально.

Кстати, интересный момент. Как выяснил для себя (в долгих спорах на форуме изиэлектроник) оператор new разворачивается компилятором в процедуру выделения памяти через malloc на весь нужный размер, а потом вызываются конструкторы в цикле. Например надо выделить память под массив из 10 объектов класса А, компилятор подсчитывает размер данных класса А, умножает на 10 и вызывает malloc(sizeof(A) * 10) и потом ставит цикл вызова конструкторов. Это "развертка" оператора new.

Еще момент - по умолчанию и по стандарту C++, если в этом месте malloc вернул NULL, то программа выпадает в эксепшн. Это по стандарту!
По этому контсрукция типа:

char * a = new char[10];
if(a != NULL )
..
не имеет смысла :). Программа, в случае отсутствия свободной памяти, не дойдет до оператора if, а вывалится в осадок.
Чтобы этого избежать, надо писать так:

char * a = new(std::nothrow) char[10];
if(a != NULL )
..

только тогда можно проверить возвращаемое значение.

Ну и напоследок - плюсы своей реализации кучи против стандартной от компилятора:
- Вы знаете, ЧТО там происходит.
- Вы знаете, ГДЕ это происходит.
- Вы знаете, КАК и КОГДА это происходит.
- Вы можете точно сказать, сколько памяти еще есть.
- Массив кучи можно разнести от стека, чтоб если что, стек даже не имел теоретической возможности затереть кучу. Тут правда надо будет переписать функцию _sbrk_r() (она как раз осуществляет проверку "набегания" стека на кучу)
- Ну и самый важный пункт - у вас есть исходники и вы можете все эти пункты подтвердить, чего не скажешь про библиотечные функции компилятора.

Все эти пункты очень важны при разработке и последующей сертификации железки в медицине.
Без этого вам сертификат не надуть :)

ЗЫ. Добалю еще один пункт в плюсы, из опыта, так сказать.
Как то мы тут для одной из железок прикупили USB стек (там много чего надо было с этим USB уметь, и самим его писать не было ни ресурсов человеков, ни времени).
А у них (фирма хорошая, знают свое дело) весь этот стек написан как раз на динамической памяти, и переписывать его ради наших 500 штук в год смысла они не видели.
А у нас железка медицинская класса С (это когда если она остановится, пациент умирает), в которой все желательно быть статическим.
Ну и было принято решение, что "вот вам кусок памяти, в нем хоть завыделяйтесь, но за пределы - ни-ни" ;-)
Для FDA это было приемлемым решением.
И, все предыдущие пункты были соблюдены

Отредактировано MasterAlexei (2018-11-09 09:07:55)

38

MasterAlexei спасибо за развернутый ответ. хоть что-то начинает раскладываться по полочкам... по чуть чуть...


Вы здесь » Микроконтроллеры » RA » HardFault_Handler/ sprintf/ stm32f103