Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: IAR 4.41A & C++
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
mungo
Имеем простой классический код:
Код
class    TMenu    {
public:
TMenu();
~TMenu();
int    Show(int);
private:
char    menu[7][17];
int    x,width,len,ptr;
};

TMenu *m=new TMenu();
m->Show(1);
delete m;

Компилируется отлично, без ошибок. Пишем в камень (AT91SAM7XC256), радуемся красивому зависанию. До оператора new все работает, затем просто виснет проц. Объявление в статике все решает, но держать в памяти много объектов не очень здорово. Писать для каждого нового меню отдельную процедуру, чтобы держать все в стеке тоже не очень - тогда с классами нет необходимости возиться.
Думал, что там с heap проблема - никаких. malloc() работает.
help.gif
alexander55
Цитата(mungo @ Sep 21 2007, 12:13) *
TMenu *m=new TMenu();

М.б.
TMenu *m=new Menu();
или
TMenu *m=new Menu;

или м.б.
TMenu Menu;
TMenu *m=&Menu;

PS. Интересно, что Вы делаете наладонник ?
mungo
Цитата(alexander55 @ Sep 21 2007, 12:28) *
М.б.
TMenu *m=new Menu();
или
TMenu *m=new Menu;

или м.б.
TMenu Menu;
TMenu *m=&Menu;

PS. Интересно, что Вы делаете наладонник ?


Нет, всего лишь кассовик...
jorikdima
Цитата(alexander55 @ Sep 21 2007, 13:28) *
М.б.
TMenu *m=new Menu();
или
TMenu *m=new Menu;

или м.б.
TMenu Menu;
TMenu *m=&Menu;

Крутые советы lol.gif lol.gif


mungo Сделайте пошагам. Код вроде нормальный.

А просто динамически какой нибудь массив int[] выделить удается?
mungo
Цитата(jorikdima @ Sep 21 2007, 13:03) *
Крутые советы lol.gif lol.gif
mungo Сделайте пошагам. Код вроде нормальный.

А просто динамически какой нибудь массив int[] выделить удается?


Да, проверил, и точно - при любых раскладах не работает new.
Код
char *s;
s=new char[10];
delete [] s;

Ситуация та же. Доходит до new и тут же умирает.
zhevak
Цитата(mungo @ Sep 21 2007, 16:12) *
Да, проверил, и точно - при любых раскладах не работает new.
Код
char *s;
s=new char[10];
delete [] s;

Ситуация та же. Доходит до new и тут же умирает.

У меня тоже нет готового ответа, но... как вариант:
new -- ведь оператор.
А что если его преопределить, т.е. написать реализацияю своего через sizeof и malloc.

Отпишите здесь обязательно, как удалось побороть/не побороть проблемку.
alexander55
Цитата(mungo @ Sep 21 2007, 14:12) *
Да, проверил, и точно - при любых раскладах не работает new.
Код
char *s;
s=new char[10];
delete [] s;

Ситуация та же. Доходит до new и тут же умирает.

Может Heap как-то не так настроен.
И все-таки не пойму, зачем в кассовом аппарате завязываться с динамической памятью (просветите, серьезно, очень интересно).
mungo
Код
    693          void    xxx()
    694          {
   \                     ??xxx:
   \   00000000   10B5               PUSH     {R4,LR}
    695          TMenu    *m;
    696          m=new TMenu();
   \   00000002   8820               MOVS     R0,#+136
   \   00000004   ........           _BLF     `??operator new`,`??operator new??rT`
   \   00000008   0400               MOVS     R4,R0
   \   0000000A   02D0               BEQ      ??xxx_1
   \   0000000C   ........           _BLF     ??TMenu,??TMenu??rT
   \   00000010   00E0               B        ??xxx_2
   \                     ??xxx_1:
   \   00000012   0024               MOVS     R4,#+0
    697          m->Show(2);
   \                     ??xxx_2:
   \   00000014   0221               MOVS     R1,#+2
   \   00000016   2000               MOVS     R0,R4
   \   00000018   ........           _BLF     ??Show,??Show??rT
    698          delete m;
   \   0000001C   2000               MOVS     R0,R4
   \   0000001E   ........           _BLF     `??delete ~TMenu`,`??delete ~TMenu??rT`
    699          /*char *s;
    700          s=new char[10];
    701          delete [] s;*/
    702          }
   \   00000022   10BC               POP      {R4}
   \   00000024   01BC               POP      {R0}
   \   00000026   0047               BX       R0              ;; return

Возможно, кому-нибудь листинг скажет, что не так...
Как-то побороть невозможно. Куда уходит вызов - абсолютно непонятно. В конструкторе класса только одна инструкция (в листинге) - BX LR... 07.gif
Начёт HEAP... Думал тоже, но, как я сказал, malloc() работает. Тоже использует. Грешу чисто на системные библиотеки, даже триальный IAR-5 скачал, не помогло... Дур дом какой-то!
Динамическая память нужна везде - если ЖК графический вкинуть, то меню рисовать без объектов очень тоскливо. Кассовые тоже нужны людям, чтоб пользоваться, и когда он достаточно сложен, как у меня, то лучше все-же через меню работать, а не кодами, как по старинке принято.
deadman
А в конструкторе что?
mungo
Цитата(deadman @ Sep 21 2007, 14:13) *
А в конструкторе что?


Ничего. Были действия, которые по идее должны экран обновлять, но они не выполнялись. Удалил. Не заработало никак.
Alexey Bishletov
Видимо new и malloc все же различаются в части выделения памяти. Наверное надо искать исходники RT библиотеки и смотреть там. У меня их нет sad.gif, но где-то они есть. Еще один вариант: пошагово зайти внутрь ??operator new и пытаться понять что же там происходит.
mungo
У меня тоже нету исходников. А пошагово зайти не могу - симулятор не работает, стопорится на запуске кварца, через j-tag тож не фурычит, да и асм я армовый не очень. Я до этого на 51-м семействе сидел.
Alechek
Чтобы не стопорился, вызвать функцию до SysInit() или как там еще... Короче в начало main(), для отладки.
mungo
J-Link запустил с горем пополам. Короче нашел где ступор - когда вызывает new, заходит в malloc, после чего в abort где и находит бесконечный branch сам на себя.
alexander55
Цитата(mungo @ Sep 21 2007, 16:07) *
J-Link запустил с горем пополам. Короче нашел где ступор - когда вызывает new, заходит в malloc, после чего в abort где и находит бесконечный branch сам на себя.

Ну теперь дело за малым прошагать malloc, а затем понять, что надо что-то поменять в icf файле.
mungo
Цитата(alexander55 @ Sep 21 2007, 15:28) *
Ну теперь дело за малым прошагать malloc, а затем понять, что надо что-то поменять в icf файле.


В каком файле? Может в .xcl? Так там задано 8000 под HEAP. Статически распределено около 9 кило, 64 всего у камня.

После дебага я нашел, что и malloc не работает. Различия лишь в том, что malloc не входит в ступор, а new входит. Похоже, считает, что нет памяти в куче. Осталось найти, где копать. Однако фигово сделано - ни исключений, ничего. Просто бесконечный цикл, без возможности узнать, что памяти нет.

Разобрался. По непонятной причине в оболочке писал 8000 хипа, а в файле было 100. Явно не хватало. И при этом все остальные параметры показывает правильно.
zhevak
Цитата(mungo @ Sep 21 2007, 19:21) *
Разобрался. По непонятной причине в оболочке писал 8000 хипа, а в файле было 100. Явно не хватало. И при этом все остальные параметры показывает правильно.


По горячим следам.
1. Посмотрел тут ARM® IAR C/C++ Compiler Reference Guide на стр. 13 есть очень короткая глава
Dynamic memory on the heap в ней раздел Potential problems. Сказано только как избежать исчерпания кучи, но не сказано, как ведут себя new. Не хорошо как-то... возникло чувство недоделанности не только руководства, но и самого компилятора. Жаль.

2. Ради спортивного интереса открыл к MSDN (MS VC++ 6.0)
"If there is insufficient memory for the allocation request, by default operator new returns NULL. You can change this default behavior by writing a custom exception-handling routine and calling the _set_new_handler run-time library function with your function name as its argument."
(Перевод мой)
"Если для запроса нехватает памяти, то поумолчанию оператор new возвращает NULL. Вы можете изменить такое поведение путем создания своей подпрограммы-обработчика исключения и вызова библиотечной функции _set_new_handler (имеется ввиду из ран-тайм бибиотеки) с именем Вашей функции в качестве аргумента."

2 mungo -- Спасибо за обозначенные грабли. Будем иметь ввиду.
alexander55
Цитата(mungo @ Sep 21 2007, 17:21) *
В каком файле? Может в .xcl?

Да, в xcl.
Я уже зациклился на 5.10 (здесь icf).
Насчет куч не обольщайтесь. Они имеют свойство ползти.
Старая, старая сказка (Шварц).
Еще лет 20 назад все работали под ДОС и ставили резидентов. Было замечено, что после убирания резидентных программ часть свободной памяти как корова языком слизывала.
Наше время. До бога молитва дошла, БГ и его банда ввела периодически работающий диспетчер оптимизации свободной памяти.
Результаты использования куч.
В универсаме кассирша покупателям : "Подождите компьютер перезагружается". (Наблюдаю постоянно).
PS.
Не все йогурты одинаковы (реклама).
Навозну кучу разгребая ... (Крылов)
... не верь глазам своим. (К.Прутков).
Alexey Bishletov
Цитата(zhevak @ Sep 24 2007, 08:35) *
Сказано только как избежать исчерпания кучи, но не сказано, как ведут себя new. Не хорошо как-то... возникло чувство недоделанности не только руководства, но и самого компилятора. Жаль.

При исчерпании кучи new должен возвращать NULL. Так у всех, поэтому в руководстве про это и не писали. Можно добавить в программу проверку на NULL после new и вывод ошибки. Поможет избежать "загадочного" поведения.
zltigo
Цитата(Alexey Bishletov @ Sep 24 2007, 09:12) *
При исчерпании кучи new должен возвращать NULL.

Это malloc() должен, а new, за просто так, никому ничего не должен.
Читаем здесь http://electronix.ru/forum/index.php?showt...hl=new&st=0
zhevak
Цитата(Alexey Bishletov @ Sep 24 2007, 12:12) *
При исчерпании кучи new должен возвращать NULL. Так у всех, поэтому в руководстве про это и не писали. Можно добавить в программу проверку на NULL после new и вывод ошибки. Поможет избежать "загадочного" поведения.


Чуть выше
Цитата
Короче нашел где ступор - когда вызывает new, заходит в malloc, после чего в abort где и находит бесконечный branch сам на себя.


А в самом первом посту
Цитата
До оператора new все работает, затем просто виснет проц.


Я так понял, что new вообще не возвращает управление. Правда, это все со слов автора темы. Что там генерит ИАР-компайлер я не проверял -- нет под руками изделия, где бы можно было проверить отход опрератора new от всемирно принятых правил игры.

Добавлять проверку на NULL нужно обязательно!. Для коммерческих программ для компов я это делаю в обязательном порядке, хотя там памяти -- умотаться. Но кто его знает, а вдруг при длительной эксплуатации (несколько недель, месяцев) память исчерпается, и что тогда? Позорный BSOD?
А вот для АРМов проврека на NULL -- ну это просто жизненно необходимо!
alexander55
Я завелся (значит не прав), но проделал полезную работу в рамках тестирования IAR 5.10.
Привожу тексты.
Это тестовые классы.
#ifndef Class_TestH
#define Class_TestH

void Test_Classes(void);

// проверка С++ 5.10

class TZero {
protected:
unsigned char var_char;
public:
TZero(void) {var_char=0; cout << "Created class TZero\n";};
~TZero(){cout<<"Delete TZero\n";};
void Show(void) { cout <<"var_char=" << (int)var_char <<"\n";};
};

class TOne : public TZero
{
protected:
unsigned short var_short;
unsigned int var_int;
public:
TOne(void) {var_char=5;};
TOne (char i) {
var_char=i;
var_short=0; var_int=0;
cout << "Created class TOne" << (int)var_char << "\n";
};
~TOne(){cout<<"Delete TOne\n";};
void Show(void) {
cout << "var_char="<< (int)var_char <<" var_short="\
<<var_short <<" var_int="<<var_int <<"\n";
};
void Inc_Short(void) {var_short++;};
void Inc_Int(void) {var_int++;};
};

class TAdd {
public:
TAdd(void) {cout << "Created TAdd\n";};
~TAdd(){cout<<"Delete TAdd\n";};
};

class TTwo : public TOne, public TAdd
{
public:
TTwo (void) { cout << "Created class TTwo" << "\n";};
~TTwo(){cout<<"Delete TTwo\n";};
void Show(void) {
cout << "var_char="<< (int)var_char <<" var_short="<<var_short\
<<" var_int="<<var_int <<"\n";
};
};
//------------------------------------------------------------------------
//#define Variant
void Test_Classes(void) {
#ifdef Variant
TZero *ptr_0=new TZero();
TOne *ptr_1=new TOne(1);
TOne *ptr_2=new TOne(2);
TTwo *ptr_3=new TTwo();
ptr_1->Inc_Short();
ptr_2->Inc_Int();
ptr_0->Show(); //TZero
ptr_1->Show(); //TZero>TOne
ptr_2->Show(); //TZero>TOne
ptr_3->Show(); //TZero>TOne+TAdd >TTwo
cout<<"ptr_0="<<ptr_0 \
<<" ptr_1="<<ptr_1 \
<<" ptr_2="<<ptr_2 \
<<" ptr_3="<<ptr_3 <<"\n";
delete ptr_2;
delete ptr_1;
delete ptr_0;
delete ptr_3;
#else
TZero Zero;
TZero *ptr_0=&Zero;
TOne One1(1);
TOne *ptr_1=&One1;
TOne One2(2);
TOne *ptr_2=&One2;
TTwo Two;
TTwo *ptr_3=&Two;

ptr_1->Inc_Short();
ptr_2->Inc_Int();
ptr_0->Show(); //TZero
ptr_1->Show(); //TZero<TOne
ptr_2->Show(); //TZero<TOne
ptr_3->Show(); //TZero<TOne+TAdd <TTwo
cout<<"ptr_0="<<ptr_0 \
<<" ptr_1="<<ptr_1 \
<<" ptr_2="<<ptr_2 \
<<" ptr_3="<<ptr_3 <<"\n"\
<<" SizeOf Zero="<<sizeof(Zero) <<"\n"\
<<" SizeOf One1="<<sizeof(One1) <<"\n"\
<<" SizeOf One2="<<sizeof(One2) <<"\n"\
<<" SizeOf Two="<<sizeof(Two) <<"\n";
#endif
}

#endif
и кусок main тестирующий
//---------
while (TRUE) {
Test_Classes();
for(unsigned int a=0;a<0x100000;a++);
}
}
Результаты: ptr не ползут нигде.

Created class TZero
Created class TOne1
Created class TZero
Created class TOne2
Created class TZero
Created TAdd
Created class TTwo
var_char=0
var_char=1 var_short=1 var_int=0
var_char=2 var_short=0 var_int=1
var_char=5 var_short=0 var_int=1073763204
ptr_0=40001fc0 ptr_1=40001fd4 ptr_2=40001fcc ptr_3=40001fc4
SizeOf Zero=1
SizeOf One1=8
SizeOf One2=8
SizeOf Two=8
Delete TTwo
Delete TAdd
Delete TOne
Delete TZero
Delete TOne
Delete TZero
Delete TOne
Delete TZero
Delete TZero
и т.д.

Created class TZero
Created class TZero
Created class TOne1
Created class TZero
Created class TOne2
Created class TZero
Created TAdd
Created class TTwo
var_char=0
var_char=1 var_short=1 var_int=0
var_char=2 var_short=0 var_int=1
var_char=5 var_short=0 var_int=0
ptr_0=40002068 ptr_1=40002078 ptr_2=40002088 ptr_3=40002098
Delete TOne
Delete TZero
Delete TOne
Delete TZero
Delete TZero
Delete TTwo
Delete TAdd
Delete TOne
Delete TZero
и т.д.

PS. Я менял delete местами - не придраться, все ОК.
Все логично. P.J.P. молодец.
Но к кучам я все равно отношусь с недоверием.
Да, множественное наследование работает в eec++
zltigo
Цитата(zhevak @ Sep 24 2007, 09:34) *
Добавлять проверку на NULL нужно обязательно!.

Только перед этом нужно убедится в наличии лифта убедится, что установленный Вами или по умолчанию обработчик исключения по нехватке памяти этот самый NULL возвращает а не делает что-либо другое.
Сергей Борщ
Цитата(zhevak @ Sep 24 2007, 09:34) *
Я так понял, что new вообще не возвращает управление. Правда, это все со слов автора темы. Что там генерит ИАР-компайлер я не проверял -- нет под руками изделия, где бы можно было проверить отход опрератора new от всемирно принятых правил игры.
Простой вызов new в случае нехватки памяти вызывает функцию, установленную при помощи set_new_handler(). После чего пытается выделить память снова. В варианте int a= new(nothrow) int[1000]; new при нехватке памяти возвращает 0.
zhevak
Цитата(zltigo @ Sep 24 2007, 13:06) *
Только перед этом нужно убедится в наличии лифта убедится, что установленный Вами или по умолчанию обработчик исключения по нехватке памяти этот самый NULL возвращает а не делает что-либо другое.

Лифт -- О-о, эта аллегория мне нравитсяsmile.gif
Продолжим нашу священную "религиозную" войну.

Я только одного не могу понять. Почему разработчики ИАР-компилятора сделали поведение new несколько отличное от стандарта и при этом никак не удосужились описать его? Может я не там читал?

Почему архитекторы спроектировали такуй странный лифт, каждый раз входя в который нужно всегда убеждаться том, что он вообще является лифтом, а не сортиром -- "вошел и провалился". Что до меня, так после таких дел я вообще не хочу пользоваться в ИАРе этим лифтом (new).
alexander55
Цитата(zhevak @ Sep 24 2007, 11:51) *
я вообще не хочу пользоваться в ИАРе этим лифтом (new).

Я стараюсь не пользоваться им везде.
Я говорил ему, чтобы не мешал водку с портвейном. А он....у-у-у хипи волосатый. (Осенний марофон).
zltigo
Цитата(zhevak @ Sep 24 2007, 10:51) *
Я только одного не могу понять. Почему разработчики ИАР-компилятора сделали поведение new несколько отличное от стандарта и при этом никак не удосужились описать его? Может я не там читал?

Стандарт читали? Ну и что там вычитали? Там все отдано на откуп программисту.
Цитата
Почему архитекторы спроектировали такуй странный лифт, каждый раз входя в который нужно всегда убеждаться том, что он вообще является лифтом

Архитекторы предоставили прекрасную возможность все гибко настраивать, ибо существует, как минимум, три логичных варианта поведения:
- ждать, пока память освободиться в другом процессе и возможно инициализировать процесс освобождения;
- повесить общий обработчик этой исключительной ситуации (именно с целью дабы каждый раз не проверять наличия лифта);
- возвратить, например, NULL, как это принято в malloc();
Цитата
Что до меня, так после таких дел я вообще не хочу пользоваться в ИАРе этим лифтом (new).

Я честно говоря не знаю, как он в IAR по умолчанию устроен, но set_new_handler() всегда позволит сделать, то, что Вам надо, да и new(nothrow) поддерживается.
Проблемы возникают, только тогда, когда кто-то считает, что new кому-то чего-то должен сделать только по той причине, что так, например, VC++ так сделано.
zhevak
Цитата(Сергей Борщ @ Sep 24 2007, 13:14) *
Простой вызов new в случае нехватки памяти вызывает функцию, установленную при помощи set_new_handler(). После чего пытается выделить память снова. В варианте int a= new(nothrow) int[1000]; new при нехватке памяти возвращает 0.

Да. Это как раз ожидаемое поведение new.
Но, получается, ИАР работает немного по-другому: если обработчик указан -- вызываю, если не указан -- висю. Так?
zltigo
Цитата(zhevak @ Sep 24 2007, 11:30) *
Да. Это как раз ожидаемое поведение new.

Почуствуйте разницу между new и new( nothrow ) smile.gif
Сергей Борщ
Цитата(zhevak @ Sep 24 2007, 11:30) *
Да. Это как раз ожидаемое поведение new.
Но, получается, ИАР работает немного по-другому: если обработчик указан -- вызываю, если не указан -- висю. Так?
Нет, получается именно так, как ожидается. Выделяем - памяти нет - вызываем функцию new_handler() (по умолчанию там пустышка) - пытаемся снова выделить память. Поскольку new_handler() ничего не сделал, памяти взяться не откуда, снова получаем "памяти нет" и ку.
2 zltigo: new_handler() возвращает void, поэтому через него нельзя заставить new вернуть 0.
zltigo
Цитата(Сергей Борщ @ Sep 24 2007, 13:34) *
2 zltigo: new_handler() возвращает void, поэтому через него нельзя заставить new вернуть 0.

Таки, да sad.gif, забыл за давностью лет. Например, одна из реализаций new:
Код
void *operator new( size_t size )
{
    void * p;
        size = size ? size : 1;
    while ( (p = malloc(size)) == NULL && _new_handler != NULL)
        _new_handler();
    return p;
}

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