IAR EC++ - как правильно?

Hi All,

Хочется использовать указатель на функцию - член класса:

class NETWORK { public: void SetGain(u8); void SetPhase(u8); void SetParameter(void (NETWORK::*Set)(u8), u8); };

void NETWORK::SetParameter(void (NETWORK::*Set)(u8), u8 param) { DoSomething();

(this->*Set)(param);

DoSomethingElse(); }

void main(void) { NETWORK network;

network.SetParameter(SetGain, 0); network.SetParameter(SetPhase, 1); }

Проблема в том, что IAR статически (!) расходует RAM (NEAR_Z) на каждый подобный вызов. Можно ли это обойти?

VLV

Reply to
Vladimir Vassilevsky
Loading thread data ...

Tue, 09 Dec 2003 18:00:47 +0300 Vladimir Vassilevsky wrote to All:

VV> Хочется использовать указатель на функцию - член класса:

Такое желание должно быть оправдано - указатели на члены как правило более "толстые" (оверхедные) и работать с ними менее удобно, чем с простыми указателями.

VV> class NETWORK { VV> public: VV> void SetGain(u8); VV> void SetPhase(u8); VV> void SetParameter(void (NETWORK::*Set)(u8), u8); VV> };

VV> void NETWORK::SetParameter(void (NETWORK::*Set)(u8), u8 param) VV> { VV> DoSomething();

VV> (this->*Set)(param);

Зачем так сложно писать? SetParameter ведь является членом класса, поэтому писать this-> совсем необязательно.

VV> DoSomethingElse(); VV> }

VV> void main(void) VV> { VV> NETWORK network;

VV> network.SetParameter(SetGain, 0); VV> network.SetParameter(SetPhase, 1);

Хм, разве SetGain и SetPhase видны в этой области видимости? По-моему такой код не должен компилироваться. Могу спутать синтаксис, но должно выглядеть примерно так:

network.SetParameter(&network.SetGain, 0);

Т.е. нужно передавать полную информацию - и об объекте, и о смещении.

VV> }

VV> Проблема в том, что IAR статически (!) расходует RAM (NEAR_Z) на каждый VV> подобный вызов. Можно ли это обойти?

Не очень понятно, что там получается (вот если б на листинг со сгенеренным кодом посмотреть), но, возможно, тут имеет смысл использовать какое-то другое решение? Повторю - указатели на члены далеко не всегда лучшее решение, и часто проще и эффективнее обойтись без них. В данном случае, например, поскольку между первым и вторым параметрами функции SetParameter какой-то корреляции не просматривается, и в точке вызова функция, вызываемая по указателю, указана явно, то проще и правильнее вызвать функцию SetGain и потом SetParameter с одним аргументом... Конечно, если условия задачи другие, то и решение должно быть другим, но для того, чтобы что-то предложить, нужно быть в курсе условий задачи.

Reply to
Harry Zhurov

Tue Dec 09 2003 20:53, Harry Zhurov wrote to Vladimir Vassilevsky:

VV>> Хочется использовать указатель на функцию - член класса:

HZ> Tакое желание должно быть оправдано - указатели на члены как правило HZ> более "толстые" (оверхедные) и работать с ними менее удобно, чем с HZ> простыми указателями.

Ситуация: есть небольшие похожие функции-члены, но перед их вызовом и после вызова нужно сделать одинаковую вспомогательную работу. Кроме того, cаму функцию-член надо вызывать в цикле несколько раз. Хочется завернуть все это хозяйство в одну универсальную функцию, которой передается указатель на член. Конечно, вместо этого можно просто сделать switch из явных вызовов посередине универсальной функции и передавать параметр для свича, однако так делать некузяво.

VV>> (this->*Set)(param);

HZ> Зачем так сложно писать? SetParameter ведь является членом класса, HZ> поэтому писать this-> совсем необязательно.

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

VV>> network.SetParameter(SetGain, 0); VV>> network.SetParameter(SetPhase, 1);

HZ> Хм, разве SetGain и SetPhase видны в этой области видимости?

Конечно.

VV>> Проблема в том, что IAR статически (!) расходует RAM (NEAR_Z) на каждый VV>> подобный вызов. Можно ли это обойти? HZ> Hе очень понятно, что там получается (вот если б на листинг со HZ> сгенеренным кодом посмотреть),

Посмотрел. В RAM появляется статическая таблица указателей на вызываемые функции-члены класса. Зачем - непонятно. Ведь это константные адреса.

VLV

Reply to
Vladimir Vassilevsky

Dear Vladimir,

09 Dec 03 21:39, Vladimir Vassilevsky wrote to Harry Zhurov:

VV> Ситуация: есть небольшие похожие функции-члены, но перед их вызовом и VV> после вызова нужно сделать одинаковую вспомогательную работу. Кроме того, VV> cаму функцию-член надо вызывать в цикле несколько раз. Хочется завернуть VV> все это хозяйство в одну универсальную функцию, которой передается VV> указатель на член. Конечно, вместо этого можно просто сделать switch из VV> явных вызовов посередине универсальной функции и передавать параметр для VV> свича, однако так делать некузяво.

А можно отдельно описать ф-ции DoSomething() и DoSomethingElse(). Далее вызывать твои ф-ции SetSomething() напрямую, из которых вызывать эти стандартные прологи и эпилоги. Ф-цию SetParameter() удалить как лишнюю и вредную.

Sincerely yours, Old Greaser.

Reply to
Serge Bryxin

Tue, 09 Dec 2003 21:39:50 +0300 Vladimir Vassilevsky wrote to Harry Zhurov:

VV>>> Хочется использовать указатель на функцию - член класса:

HZ>> Tакое желание должно быть оправдано - указатели на члены как правило HZ>> более "толстые" (оверхедные) и работать с ними менее удобно, чем с HZ>> простыми указателями.

VV> Ситуация: есть небольшие похожие функции-члены, но перед их вызовом и VV> послевызова нужно сделать одинаковую вспомогательную работу. Кроме того, VV> cаму функцию-член надо вызывать в цикле несколько раз. Хочется VV> завернуть все это хозяйство в одну универсальную функцию, которой VV> передается указатель на член. VV> Конечно, вместо этого можно просто сделать switch из явных вызовов VV> посередине универсальной функции и передавать параметр для свича, VV> однако так делать некузяво.

Да, со свитчем некузяво.

Соображения такие. Всякое такое, что требует одинаковых действий до и действий после, бывает удобно завернуть в "обертку", т.е. написать класс-враппер, где в конструкторе выполняются действия ДО, а в деструкторе - действия ПОСЛЕ. При использовании нужно просто создать объект и работать с ним, а ДО и ПОСЛЕ выполнится автоматически, путем неявного вызова конструктора и деструктора. Например:

class TSlon { public: TSlon() { DoSomthing(); } void SetGain(u8); ...

~TSlon() { DoSomthingElse(); }

private: ... }

void main() { ... TSlon slon;

slon.SetGain(0); }

Еще один вариант - использовать виртуальные функции, там таблица указателей размешается во флеши (специально проверял). При этом нужно каждый параметр будет сделать отдельным классом, производным от одного базового. В этом случае, однако, появляются накладные расходы по памяти - каждый класс будет содержать два байта указателя vptr. Зато есть бОльшая гибкость - можно вызывать по одному указателю разные функции.

Ну, и остается традиционный вариант с помощью обычных указателей. Если не хочется выносить функции в глобальную область видимости, то можно их сделать статическими и работать как с обычными. Этот вариант, имхо, наиболее близок к твоей реализации. Тем более, что все равно приходится явно метать this.

В общем, тут тебе думать/выбирать.

[...]

VV>>> network.SetParameter(SetGain, 0); VV>>> network.SetParameter(SetPhase, 1);

HZ>> Хм, разве SetGain и SetPhase видны в этой области видимости?

VV> Конечно.

Да нет, их область видимости ограничена классом NETWORK, поэтому в таком виде компилятор выдает ошибку:

------------------------------------------------- network.SetParameter(SetGain, 0); ^ "D:\slon\IAR\AVR\VLV\slon.cpp",33 Error[Pe020]: identifier "SetGain" is undefined

-------------------------------------------------

Т.е. не видит он тут такого имени. Чтобы он увидел, нужно написать:

network.SetParameter(NETWORK::SetGain, 0);

VV>>> Проблема в том, что IAR статически (!) расходует RAM (NEAR_Z) на каждый VV>>> подобный вызов. Можно ли это обойти? HZ>> Hе очень понятно, что там получается (вот если б на листинг со HZ>> сгенеренным кодом посмотреть),

VV> Посмотрел. В RAM появляется статическая таблица указателей на вызываемые VV> функции-члены класса. Зачем - непонятно. Ведь это константные адреса.

Именно. Вот он и размещает эти адреса в сегменте const. Просто сегмент const в AVR располагается в ОЗУ, с этим ничего не поделаешь - архитектура такая. Вот если бы у него хватало ума размещать эту таблицу во флеш, то это было бы, наверное, то, что тебе надо. Но пока он не такой "умный" (что в перспективе может составить предмет беседы с иаровцами). Хотя не уверен, можно ли это в принципе сделать - не помню, разрешается ли адресная арифметика с указателями на члены совместно с обычными указателями. Если не разрешается, то тогда принципиальных проблем разместить в флеш нет, а если разрешается, то тады "ой", жить ему в ОЗУ.

Reply to
Harry Zhurov

Tue Dec 09 2003 23:12, Serge Bryxin wrote to Vladimir Vassilevsky:

VV>> Ситуация: есть небольшие похожие функции-члены, но перед их вызовом и VV>> после вызова нужно сделать одинаковую вспомогательную работу. Кроме VV>> того, cаму функцию-член надо вызывать в цикле несколько раз. Хочется VV>> завернуть все это хозяйство в одну универсальную функцию, которой VV>> передается указатель на член. Конечно, вместо этого можно просто VV>> сделать switch из явных вызовов посередине универсальной функции и VV>> передавать параметр для свича, однако так делать некузяво.

SB> А можно отдельно описать ф-ции DoSomething() и DoSomethingElse(). Далее SB> вызывать твои ф-ции SetSomething() напрямую, из которых вызывать эти SB> стандартные прологи и эпилоги. Ф-цию SetParameter() удалить как лишнюю и SB> вредную.

Функций SetSomething() несколько десятков. Они могут вызываться как сами по себе, так и в составе примерно такой процедуры:

DoSomething(); for(ci = 0; ci < number; ci++) SetSomething(ci); DoSomethingElse();

Hачало и конец можно сделать в виде враппера, как предложил Harry Zurov, но с циклом так не расправишься.

SB> Sincerely yours, SB> Old Greaser.

VLV

Reply to
Vladimir Vassilevsky

Wed, 10 Dec 2003 22:35:01 +0300 Vladimir Vassilevsky wrote to Serge Bryxin:

[...]

VV> DoSomething(); VV> for(ci = 0; ci < number; ci++) SetSomething(ci); VV> DoSomethingElse();

VV> Hачало и конец можно сделать в виде враппера, как предложил Harry Zurov, VV> но с циклом так не расправишься.

// -------------------------------------------- class TSlon { public: TSlon() { DoSomething(); } ~TSlon() { DoSomethingElse(); } };

void f() { ... //

{ TSlon sl; for(ci = 0; ci < number; ci++) SetSomething(ci); }

... // }

// --------------------------------------------

Меньше писанины, и не забудешь эпилог вызвать. Таким способом можно оборачивать почти любые фрагменты кода. Если этих пар функций много, то придется написать соответствующее количество врапперов.

Reply to
Harry Zhurov

Dear Vladimir,

10 Dec 03 22:35, Vladimir Vassilevsky wrote to Serge Bryxin:

SB>> можно отдельно описать ф-ции DoSomething() и DoSomethingElse(). SB>> Далее вызывать твои ф-ции SetSomething() напрямую, из которых SB>> вызывать эти стандартные прологи и эпилоги.

VV> Функций SetSomething() несколько десятков. Они могут вызываться как VV> сами по себе, так и в составе примерно такой процедуры:

VV> DoSomething(); VV> for(ci = 0; ci < number; ci++) SetSomething(ci); VV> DoSomethingElse();

VV> Hачало и конец можно сделать в виде враппера, как предложил Harry Zurov, VV> но с циклом так не расправишься.

Так и я, в общем-то, враппер предлагаю. А почему с циклом не расправиться? Hапример:

SetSomething(int start, int number, bool init) { register int i; if( init ) DoSomething(); for( i=start; i<start+number; i++ ) { ActuallySet(i); } if( init ) DoSomethingElse(); }

Hа самом деле по-хорошему ф-цию ActuallySet() описывать не надо. В цикле - собственно алгоритм установки ( i.e. тело твоей текущей SetSomething() ). Ибо каждый лишний CALL в циклах - плохо в принципе. Если скорость вызова ActuallySet() без пролога и эпилога смертельно критична, можно таки ее описать (а параметр init опустить, возожно и параметр start опустить, если цикл всегда от 0), но в общем случае я бы не стал.

До кучи: #define SetSomething1(X) SetSomething((X),1,false)

Блин, насколько все это проще и изящнее на Асме! :-) Флаг T взвел, CALL прямо на метку ActuallySet, BRTC дальше, иначе RET.

Sincerely yours, Old Greaser.

Reply to
Serge Bryxin

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.