Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Использование realloc()
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
koluna
Здравствуйте!

WinAVR 20071221.
scmRTOS 3.05.
ATmega48.

Выделяю память в цикле (последовательно добавляю по одному байту).

Код
...
unsigned int* Buffer_Size;
unsigned char* Buffer;
...
// В цикле.
(*Buffer_Size)++;
Buffer = (unsigned char*) realloc((unsigned char*)Buffer, *Buffer_Size);
...


При выделении на третьем байте realloc возвращает 0 почему?
Память кончилась? smile.gif

Благодарю заранее!

Когда делаю, допустим, так:
Код
...
unsigned char* PBuff;
...
PBuff = (unsigned char*) malloc(8);

то всё нормально...
SysRq
Из такого куска кода как-то не ясно начальное значение (*Buffer_Size). Может быть действительно еще пара байт свободных байт остается...
koluna
Цитата(SysRq @ Jun 25 2009, 23:53) *
Из такого куска кода как-то не ясно начальное значение (*Buffer_Size). Может быть действительно еще пара байт свободных байт остается...


Перед началом выделения:

Код
*Buffer_Size = 0;


Код
...
    unsigned char* PBuff;
    unsigned int Size_Buff;
...
    Res = USART.Read(PBuff, &Size_Buff);
    USART.Write(PBuff, Size_Buff);
....
TStatus_Op TUSART_S::Read(unsigned char* Buffer, unsigned int* Buffer_Size)
{
    unsigned char ParityBit; // Временная переменная для хранения значения 9-го бита принятого по USART байта данных.
    unsigned int i;
    unsigned char Event_Result;

    Enable_RXD_Int(); // Разрешение прерывания по окончании передачи байта.
    *Buffer_Size = 0;
    i = 0;
    do
    {
        if (*Buffer_Size == 0) {Event_Result = ByteIsReceived_Event.Wait(0);}
        else {Event_Result = ByteIsReceived_Event.Wait(RD_TimeOut);};

        if (!Event_Result)
        {
// Тайм-аут при приёме байта.
            Disable_RXD_Int(); // Запрещение прерывания по окончании приёма байта.
            return SO_READ_TIME_OUT;
        };
        (*Buffer_Size)++;
        Buffer = (unsigned char*) realloc((unsigned char*)Buffer, *Buffer_Size); // Выделение участка памяти.
// Проверка успешности выделения участка памяти под буфер приёмника.
        if (!Buffer)
        {
// Ошибка выделения участка памяти.
            Disable_RXD_Int(); // Запрещение прерывания по окончании приёма байта.
            return SO_MEMORY_NOT_ALLOCATED;
        };
        ParityBit = Get_Parity_Bit();
// Извлечение очередного байта из регистра данных USART и загрузка его в буфер приёмника.
        *(Buffer + i) = Read_Byte();
        i++;
        Enable_RXD_Int(); // Разрешение прерывания по окончании передачи байта.
    }
    while (*Buffer_Size < 7);
    Disable_RXD_Int(); // Запрещение прерывания по окончании приёма байта.
    return SO_OPERATION_COMPLETE;
...
};


Памяти, я думаю, хватает...
Следующий код работает нормально.

Код
...
    unsigned char* PBuff;
    unsigned int Size_Buff;
...
    Size_Buff = 26;
    PBuff = (unsigned char*) malloc(Size_Buff);
    Res = USART.Read(PBuff, (const unsigned int) Size_Buff);
    USART.Write(PBuff, Size_Buff);
    free(PBuff);
...
TStatus_Op TUSART_S::Read(unsigned char* Buffer, const unsigned int Buffer_Size)
{
    unsigned char Event_Result;

    for (unsigned int i = 0; i < Buffer_Size; i++)
    {
        Enable_RXD_Int(); // Разрешение прерывания по окончании передачи байта.
        if (i == 0) {Event_Result = ByteIsReceived_Event.Wait(0);}
        else {Event_Result = ByteIsReceived_Event.Wait(RD_TimeOut);};
        if (!Event_Result) {return SO_READ_TIME_OUT;}; // Тайм-аут при приёме байта.
// Извлечение очередного байта из регистра данных USART и загрузка его в буфер приёмника.
        *(Buffer + i) = Read_Byte();
    };
    return SO_OPERATION_COMPLETE;
};
...


Смысл-то в том, чтобы менять размер буфера при приёме...
Т. е., конечно, проще и надёжнее - выделить память под буфер на N байт сразу и прочитать эти N байт.
А ещё проще и надёжнее - использовать обычный массив.
А если N неизвестно или известно, что оно не более M?
Выделять память по буфер M байт не хочется... неэкономично как-то и некрасиво smile.gif

Программа работает совместно с scmRTOS.
Так что процесс ждёт эвента ByteIsReceived_Event, свидетельствующего о получении байта по USART.
Эвент сигналится в прерывании по приёму...

Возможно, решение проблемы здесь: http://bytes.com/groups/c/603687-problem-realloc
Надо проверить smile.gif
zltigo
Цитата(n_bogoyavlensky @ Jun 26 2009, 09:00) *
Выделять память по буфер M байт не хочется... неэкономично как-то и некрасиво smile.gif

Вы страшно далеки от представления, что такое realloc о его "'экономичности" и способах (отданных на откуп компилятору/системе) реализации и САМОЙ ВОЗМОЖНОСТИ сколь-нибудь хоть для чего-нибудь пригодной реализации на AVR. То, что Вы накропали с realloc это чистое безумие. Впрочем, все остальное не лучше sad.gif.
Цитата
При выделении на третьем байте realloc возвращает 0 почему?
Память кончилась?

Да, та минимальная порция (очевидно 4 байта в конкретной реализации), которую получили при первом запросе КОНЧИЛАСЬ.
koluna
Цитата(zltigo @ Jun 26 2009, 09:18) *
Вы страшно далеки от представления, что такое realloc о его "'экономичности" и способах (отданных на откуп компилятору/системе) реализации и САМОЙ ВОЗМОЖНОСТИ сколь-нибудь хоть для чего-нибудь пригодной реализации на AVR.


Т. е., для AVRов realloc лучше вообще не использовать?

Цитата
То, что Вы накропали с realloc это чистое безумие.


Ну, вроде всё правильно по книжке... На конкретные ляпы укажите, пожалуйста.

Цитата
Впрочем, все остальное не лучше sad.gif.


Буду благодарен за комментарии и по поводу всего остального...

Цитата
Да, та минимальная порция (очевидно 4 байта в конкретной реализации), которую получили при первом запросе КОНЧИЛАСЬ.


Что за минимальная порция?
Можно немного поподробнее, пожалуйста?
SysRq
Попробуйте инициализировать PBuff (присвоить NULL), а вызов realloc загоните в критическую секцию (в scmRTOS должны быть средства).
koluna
Цитата(SysRq @ Jun 26 2009, 09:44) *
Попробуйте инициализировать PBuff (присвоить NULL), а вызов realloc загоните в критическую секцию (в scmRTOS должны быть средства).


Не помогло.
SysRq
Значит zltigo прав. Разбирайтесь сколько отведено под heap и как он используется у вас в проекте... unsure.gif
koluna
Цитата(SysRq @ Jun 26 2009, 11:45) *
Значит zltigo прав. Разбирайтесь сколько отведено под heap и как он используется у вас в проекте... unsure.gif


Не понимаю.
Ведь malloc работает! Та же самая куча...
Я ей могу выделить сразу гораздо больший объём памяти!
DpInRock
Я в Сях ничего не понимаю, но ради развлечения не увидел, в каком месте перед realloc выделяется начальный буфер.
Realloc насколько я понимаю, просто изменяет размер уже существующего блока...

А так - это не просто безумие. Это даже для нормальных быстрых и замечательных процессорах с огромной памятью - безумие.

В устройствах на всяких мелких процессорах без юзерскго интерфейса наличие ситуаций "нет памяти" просто безумна.
Или если так приспичило "экономить", то проверять наличие памяти надо ДО приема. И соответтсвенно выставлять всякое разное для остановки потока данных (rts, там, DTR и прочая...).
Сергей Борщ
Цитата(n_bogoyavlensky @ Jun 25 2009, 17:05) *
При выделении на третьем байте realloc возвращает 0 почему?
Память кончилась? smile.gif
Весьма вероятно. Сделайте так:
Код
{
    void * a = malloc(0);
    void * b = malloc(0);
    printf("mcb size = %d", (uintptr_t)b - (uintptr_t) b);
    free(a);
    free(b);
}
Увидете, сколько занимает служебная информация (memory control block) в вашем менеджере памяти. Учтите, что каждый realloc() в общем случае выделяет блок нового размера и только после этого уничтожает старый. Т.е. для успешного завершения ему необходимо, чтобы в куче был свободный участок размером (новый размер + размер mcb). Еще один mcb на кучу возможно используется самим менеджером. Сколько вы выделили под кучу?
koluna
Цитата(DpInRock @ Jun 26 2009, 18:16) *
Я в Сях ничего не понимаю, но ради развлечения не увидел, в каком месте перед realloc выделяется начальный буфер.
Realloc насколько я понимаю, просто изменяет размер уже существующего блока...


avr-libc:
Цитата
It is acceptable to pass ptr as NULL, in which case realloc() will behave identical to malloc().

Т. е., если память изначально не выделена, то realloc() выделяет её подобно malloc().
Только вот указатель realloc() я передаю ненулевой... может в этом ещё дело...

А так - это не просто безумие. Это даже для нормальных быстрых и замечательных процессорах с огромной памятью - безумие.

Цитата
В устройствах на всяких мелких процессорах без юзерскго интерфейса наличие ситуаций "нет памяти" просто безумна.
Или если так приспичило "экономить", то проверять наличие памяти надо ДО приема. И соответтсвенно выставлять всякое разное для остановки потока данных (rts, там, DTR и прочая...).


У меня функция ошибку возвращает, если памяти не хватило smile.gif

Цитата(Сергей Борщ @ Jun 26 2009, 18:44) *
Сколько вы выделили под кучу?


Затрудняюсь ответить... sad.gif
Кроме вызова realloc(), free() я ничего с памятью не делал...
Нужно ещё как-то память под кучу выделить?
sergeeff
Цитата(n_bogoyavlensky @ Jun 29 2009, 10:08) *
У меня функция ошибку возвращает, если памяти не хватило smile.gif


1. Вы же не сидите внутри вашего устройства. Кто (что) и каким образом будет реагировать на этот код ошибки?
2. Realloc - большое зло. Чем быстрее вы его изгоните из своей программы, тем лучше.
3. Если уж совсем в лом разбираться с размером heap (хотя, скорее всего в startup модуле есть соответствующий параметр) напишите простенький цикл с malloc(1), и быстро поймете размер кучи. Не забывайте про этом, что вам уже писали коллеги - у каждого выделенного блока есть еще накладные расходы в виде доп. байт на модуль.
Сергей Борщ
Цитата(n_bogoyavlensky @ Jun 29 2009, 09:08) *
Только вот указатель realloc() я передаю ненулевой... может в этом ещё дело...
Интересный подход. realloc() принимает указатель, который указывает на блок, выделенный при помощи malloc/realloc. Или NULL, тогда он действует как malloc. Если вы ему передаете указатель, содержащий что-либо другое - результат может быть любым, но только не выделением памяти. Вы поступаете как суровые русские мужики с японской лесопилкой.
Цитата(n_bogoyavlensky @ Jun 29 2009, 09:08) *
Затрудняюсь ответить... sad.gif
Кроме вызова realloc(), free() я ничего с памятью не делал...
Нужно ещё как-то память под кучу выделить?
Уже не смешно. "Если уже ничего не помогает - прочтите, наконец, инструкцию". WinAVR\DOC\avr-libc\avr-libc-user-manual\malloc.html
SysRq
Гм. Я ж выше вам написал, что указатель проинициализировать надо, присвоив NULL.
Вы отрапортавали что:
Цитата(n_bogoyavlensky @ Jun 26 2009, 11:33) *
Не помогло.

Теперь же:
Цитата(n_bogoyavlensky @ Jun 29 2009, 10:08) *
Только вот указатель realloc() я передаю ненулевой... может в этом ещё дело...


Не понятно, кроме того что не смешно cranky.gif
koluna
Цитата(SysRq @ Jun 29 2009, 11:30) *
Гм. Я ж выше вам написал, что указатель проинициализировать надо, присвоив NULL.
Вы отрапортавали что:
Теперь же:
Не понятно, кроме того что не смешно cranky.gif


Обнулял, обнулял! Не туда посмотрел sad.gif
Точно не помогло.

Цитата(sergeeff @ Jun 29 2009, 09:57) *
1. Вы же не сидите внутри вашего устройства. Кто (что) и каким образом будет реагировать на этот код ошибки?


В порт выдать что-нибудь... проиндицировать...

Цитата
2. Realloc - большое зло. Чем быстрее вы его изгоните из своей программы, тем лучше.


Изгнал уже...

Цитата
3. Если уж совсем в лом разбираться с размером heap (хотя, скорее всего в startup модуле есть соответствующий параметр) напишите простенький цикл с malloc(1), и быстро поймете размер кучи. Не забывайте про этом, что вам уже писали коллеги - у каждого выделенного блока есть еще накладные расходы в виде доп. байт на модуль.


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