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

Do you have a question? Post it now! No Registration Necessary

Threaded View
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


IAR EC++ - как правильно?
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 с
одним аргументом... Конечно, если условия задачи другие, то и решение должно
быть другим, но для того, чтобы что-то предложить, нужно быть в курсе условий
задачи.


--
H.Z.

harry.zhurov<antispam::at>ngs<antispam::period>ru

We've slightly trimmed the long signature. Click to see the full one.
IAR EC++ - как правильно?
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


IAR EC++ - как правильно?
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.


IAR EC++ - как правильно?
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


IAR EC++ - как правильно?
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); }

    ... //
}

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

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

--
H.Z.

harry.zhurov<antispam::at>ngs<antispam::period>ru

We've slightly trimmed the long signature. Click to see the full one.
IAR EC++ - как правильно?
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.


IAR EC++ - как правильно?
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 располагается в ОЗУ, с этим ничего не поделаешь - архитектура
такая. Вот если бы у него хватало ума размещать эту таблицу во флеш, то это
было бы, наверное, то, что тебе надо. Но пока он не такой "умный" (что в
перспективе может составить предмет беседы с иаровцами). Хотя не уверен, можно
ли это в принципе сделать - не помню, разрешается ли адресная арифметика с
указателями на члены совместно с обычными указателями. Если не разрешается, то
тогда принципиальных проблем разместить в флеш нет, а если разрешается, то тады
"ой", жить ему в ОЗУ.

--
H.Z.

harry.zhurov<antispam::at>ngs<antispam::period>ru

We've slightly trimmed the long signature. Click to see the full one.

Site Timeline