реклама на сайте
подробности

 
 
2 страниц V  < 1 2  
Reply to this topicStart new topic
> Век живи, век учись..., функции в CodeVision не позволяют возвращать структуры
dxp
сообщение Nov 19 2007, 06:38
Сообщение #16


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(vmp @ Nov 19 2007, 12:32) *
Возврат структуры - довольно неудачное решение. Где должна размещаться эта структура?
Если с простыми типами все понятно (результат передается в регистрах), то структуру (в общем случае произвольного размера) нужно размещать в памяти. Вопрос в какой? Статическая не подойдет (имеем проблемы с рекурсией и прерываниями), остается динамическая, т.е. стек или куча. Т.е. компилятор на входе в функцию должен создать данную структуру, на выходе из функции заполнить ее (скорее всего скопировав содержимое из локальной структуры). Вызывающая функция должна скопировать результат куда-то ещё и не забыть уничтожить временное хранилище.
И оно надо в микроконтроллерной программе? Двойной расход памяти и двойное копирование? Так что либо вообще не использовать структуры для возврата, либо просто передавать указатель в явном виде (всё равно будет оптимальнее).

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


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Nov 19 2007, 07:43
Сообщение #17


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Цитата(vmp @ Nov 19 2007, 08:32) *
Возврат структуры - довольно неудачное решение. Где должна размещаться эта структура?

В общем случае да, согласен, лучше через указатель.
Но существуют и частные случаи, в том числе возврат типа div_t или ldiv_t в функциях div и ldiv соответственно. (Интересно, как эти функции реализованы в CV?)
Случай, приведенный в первом сообщении автора, можно с натяжкой отнести к частным.
Go to the top of the page
 
+Quote Post
vmp
сообщение Nov 19 2007, 08:03
Сообщение #18


Местный
***

Группа: Свой
Сообщений: 426
Регистрация: 20-01-05
Из: Зеленоград
Пользователь №: 2 070



Цитата(dxp @ Nov 19 2007, 09:38) *
Никакого дополнительного копирования и проблем с аллокацией дополнительной памяти тут нет.


Разве?
Итак, чтобы использовать структуру в качестве результата функции, нам в общем случае нужны 3 структуры:
1. Локальная в вызываемой функции. Она заполняется этой функцией и затем её имя используется в операторе return;
2. Неявная переменная на стеке, в которой и будет возвращен результат.
3. Локальная или глобальная переменная в вызывающей функции, которой будет присвоен результат вызова.

Разместить все 3 переменные по одному адресу можно только при очень удачном стечении обстоятельств. При запуске простейшего тестового примера на IAR EWARM 4.41A этого не получилось - компилятор совместил только переменные 1 и 2, достигнув всего лишь двойного, а не тройного расхода памяти. Оптимизация -s9.
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Nov 19 2007, 08:43
Сообщение #19


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Цитата(vmp @ Nov 19 2007, 11:03) *
Разве?


Main.cpp:
Код
struct TTest
{
    int a[100];
};

TTest func();

TTest t;

void main()
{
t = func();
}


func.cpp
Код
struct TTest
{
    int a[100];
};

TTest func()
{
    TTest t;
    t.a[10] = 100;
    return t;
}


После компиляции:
для main имею:
Код
151              t = func();
   \   0000000A   ....               LDI     R16, LOW(t)
   \   0000000C   ....               LDI     R17, (t) >> 8
   \   0000000E   ........           CALL    ??func

для func.cpp
Код
30          TTest func()
   \                     ??func:
    131          {
   \   00000000   97EF               SBIW    R29:R28, 63
   \   00000002   97EF               SBIW    R29:R28, 63
   \   00000004   97EF               SBIW    R29:R28, 63
   \   00000006   972B               SBIW    R29:R28, 11
   \   00000008   01B8               MOVW    R23:R22, R17:R16
    132              TTest t;
    133              t.a[10] = 100;
   \   0000000A   E604               LDI     R16, 100
   \   0000000C   E010               LDI     R17, 0
   \   0000000E   8B0C               STD     Y+20, R16
   \   00000010   8B1D               STD     Y+21, R17
    134              return t;
   \   00000012   018B               MOVW    R17:R16, R23:R22
   \   00000014   01FE               MOVW    R31:R30, R29:R28
   \   00000016   EC48               LDI     R20, 200
   \   00000018   E050               LDI     R21, 0
   \   0000001A   ........           CALL    ?ML_SRAM_SRAM_16_L07
   \   0000001E   96EF               ADIW    R29:R28, 63
   \   00000020   96EF               ADIW    R29:R28, 63
   \   00000022   96EF               ADIW    R29:R28, 63
   \   00000024   962B               ADIW    R29:R28, 11
   \   00000026   9508               RET
    135          }


Если же TTest - небольшая, то получится что-то вроде:
Код
130          TTest func()
   \                     ??func:
    131          {
    132              TTest t = {0};
   \   00000000   ....               LDI     R30, LOW(`?<Constant {{0}}>`)
   \   00000002   ....               LDI     R31, HIGH(`?<Constant {{0}}>`)
   \   00000004   ....               LDI     R19, (`?<Constant {{0}}>`) >> 16
   \   00000006   BF3B               OUT     0x3B, R19
   \   00000008   9147               ELPM    R20, Z+
   \   0000000A   9157               ELPM    R21, Z+
    133              t.a[1] = 100;
    134              return t;
   \   0000000C   018A               MOVW    R17:R16, R21:R20
   \   0000000E   E624               LDI     R18, 100
   \   00000010   E030               LDI     R19, 0
   \   00000012   9508               RET
    135          }


Т.е., небольшие структуры возвращаются через регистры, большие - через неявный указатель.
Никакого дополнительного расхода памяти...

И помоему нет ни одной разумной причины не реализовать возврат структур в компиляторе, если это есть в стандарте языка.

У меня IAR 4.30
Go to the top of the page
 
+Quote Post
zhevak
сообщение Nov 19 2007, 08:50
Сообщение #20


Знающий
****

Группа: Свой
Сообщений: 723
Регистрация: 29-08-05
Из: Березовский
Пользователь №: 8 065



Цитата(vmp @ Nov 19 2007, 13:03) *
Итак, чтобы использовать структуру в качестве результата функции, нам в общем случае нужны 3 структуры:
1. Локальная в вызываемой функции. Она заполняется этой функцией и затем её имя используется в операторе return;
2. Неявная переменная на стеке, в которой и будет возвращен результат.
3. Локальная или глобальная переменная в вызывающей функции, которой будет присвоен результат вызова.

Разместить все 3 переменные по одному адресу можно только при очень удачном стечении обстоятельств. При запуске простейшего тестового примера на IAR EWARM 4.41A этого не получилось - компилятор совместил только переменные 1 и 2, достигнув всего лишь двойного, а не тройного расхода памяти. Оптимизация -s9.


Я прошу участников дискуссии не забывать о прозрачности исходных текств в погоне на экономией одного-двух-трех байт. Кроме того, структура имеет размер немного больший, чем размер скалярной переменной, но и не такой уж большой, что бы уже задумываться о передаче указателей. Т.е. это "пограничный" случай для выбора того или иного решения. Неоднозначности здесь много.

Я посмотрел ИАРовский листинг. Там структура тоже возвращается неявно. Все правильно, так и должно быть. Опрератор return копирует данные локальной стуктуры по адресу, который пришел в функцию неявно. Т.е. код

Код
  MSG msg;

  msg = GetMessage();


в ассемблерном исполнении выглядит как

Код
  MSG msg;

  GetMessage(&msg);


Т.е. компилятор выполнил "черную" работу, а мы имеем читабельность и легкое понимание исходников.
К тому же работа с локальной переменной и возврат ее из GetMessage также выглядят по-человечески:

Код
  MSG local_msg;

  local_msg.code = ...
  local_msg.param = ...

  return local_msg;
}


Заумные тексты программ это не есть высокий уровень профессионализма.

Конечно, все это можно реализовать с помощью указателей на структуры, но при этом немного потеряется читабельность. Чуть-чуть тут, чуть-чуть там, вроде немного. Но когда проектов много, и к ним приходится возвращаться через несколько месяцев, честно говоря -- это уже начинает напрягать.

Или я не прав?


--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
Go to the top of the page
 
+Quote Post
dxp
сообщение Nov 19 2007, 09:17
Сообщение #21


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(zhevak @ Nov 19 2007, 14:50) *
Я прошу участников дискуссии не забывать о прозрачности исходных текств в погоне на экономией одного-двух-трех байт.

А где тут прозрачность страдает? Или что вы подразумеваете под прозрачностью?

Цитата(zhevak @ Nov 19 2007, 14:50) *
Кроме того, структура имеет размер немного больший, чем размер скалярной переменной, но и не такой уж большой, что бы уже задумываться о передаче указателей. Т.е. это "пограничный" случай для выбора того или иного решения. Неоднозначности здесь много.

Вариант с указателем проигрывает (на AVR) только для размера структуры, меньшего размера указателя. В остальных случаях он или не хуже, или лучше.

Цитата(zhevak @ Nov 19 2007, 14:50) *
Заумные тексты программ это не есть высокий уровень профессионализма.

Конечно, все это можно реализовать с помощью указателей на структуры, но при этом немного потеряется читабельность. Чуть-чуть тут, чуть-чуть там, вроде немного. Но когда проектов много, и к ним приходится возвращаться через несколько месяцев, честно говоря -- это уже начинает напрягать.

Или я не прав?

Описанный выше вариант, когда компилятор сам организовывает передачу указателя вполне прозрачен. Для пользователя тут все однозначно - он получает из функции структуру по значению, как и требуется по Стандарту. А как это уже сделал компилятор, это дело третье.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
zhevak
сообщение Nov 19 2007, 09:39
Сообщение #22


Знающий
****

Группа: Свой
Сообщений: 723
Регистрация: 29-08-05
Из: Березовский
Пользователь №: 8 065



Цитата(dxp @ Nov 19 2007, 14:17) *
А где тут прозрачность страдает? Или что вы подразумеваете под прозрачностью?

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

Цитата
Вариант с указателем проигрывает (на AVR) только для размера структуры, меньшего размера указателя. В остальных случаях он или не хуже, или лучше.

Причем здесь AVR? Это у любой платформы.

Цитата
Описанный выше вариант, когда компилятор сам организовывает передачу указателя вполне прозрачен. Для пользователя тут все однозначно - он получает из функции структуру по значению, как и требуется по Стандарту. А как это уже сделал компилятор, это дело третье.

Ага. По-моему, мы говорим об одном и том же, а такое чувство, что стоим по разные стороны.


--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
Go to the top of the page
 
+Quote Post
dxp
сообщение Nov 19 2007, 10:06
Сообщение #23


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(zhevak @ Nov 19 2007, 15:39) *
Прозрачность начинает уменьшаться с появлением звездочек и амперсендов.
Например, в Васике нет этого, поэтому тексты программ на нем более прозрачны, чем на Си. Только не надо передергивать, а то уйдем в бессмысленное словоблудие. (Я, к стати, не адепт Васика.)

Не хочется звездочек и амперсандов, можно использовать ссылки. Это, правда, уже ++ная фича, но большинство доступных компиляторов это умеет без вопросов. Там, правда, тоже есть амперсанд, но только в определении функции, что, имхо, прозрачности не убавляет:

Код
struct TStruct {...};

void f(TStruct& s)
{
    ...;
    s... = ...;
    ...;
}

TStruct S;

f(S);


Тут уж все однозначно. Хотя синтаксис немного другой. smile.gif


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
defunct
сообщение Nov 19 2007, 10:49
Сообщение #24


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(zhevak @ Nov 19 2007, 12:39) *
Прозрачность начинает уменьшаться с появлением звездочек и амперсендов.

Ну так создайте тип - "указатель на структуру" и перестаньте использовать звездочки:

Код
typedef struct tagMESSAGE
{
    U8 id
    U8 ...
    ...
} TMessage, *PMessage;


U8 GetMessage( PMessage pMsg)
{
     if (!pMsg)
         return FALSE;
     else
     {
         pMsg->id = xxx
         ...
         return TRUE;
     }
}


ну а дальше уже как будет удобней, или автоматическую переменную создать, но тогда придется использовать аперсанд

Код
    TMessage Msg;

или динамическое выделение памяти:
Код
    PMessage pMsg = heap_alloc( ... );
  
    if (GetMessage( pMsg ) )
    {
         обработка
    }


Можно heap_alloc вставить прямо внутрь GetMessage поменяв функцию так:

Код
PMessage GetMessage( void )
{
      PMessage pMsg = heap_alloc(...);
      if ( pMsg )
      {
           pMsg->id = ...;
           ...
      }
      return pMsg;
}


и пользовать так
Код
if ( !(pMsg = GetMessage()) )
    ALERT NO MEMORY
else
{
    обработка
    ...
    heap_free( pMsg );

}
Go to the top of the page
 
+Quote Post
zhevak
сообщение Nov 21 2007, 20:18
Сообщение #25


Знающий
****

Группа: Свой
Сообщений: 723
Регистрация: 29-08-05
Из: Березовский
Пользователь №: 8 065



я там где-то ранее обещал опубликовать результаты перенеса кода из CV в IAR.

Ну что сказать? Код перешел легко и непринужденно. Изменения произошли только в вызовах прерываний (немного другой синтаксис) и в переменных типа bit. Последние я тупо заменил на BYTE, их немного, штук пять, поэтому практически они ни на что не лияют.

Попутно, что мне понравилось, так это когда IAR указал варнингами на мои ошибки. Самая страшная, это когда беззнаковой переменной я присваивал минус единицу. CV просто проглатывал.

Иногда, там, где действительно есть ошибки и он CV видит их, он дает не совсем корректную диагностику. Этого мало, он может отправить вас вообще не туда, где лежит ошибка =8-[

Да много чего хорошего можно сказать про IAR против CV. Только мне хотелось бы озвучить результаты.

Размер флешь-кода, полученного в CV составляет 4030 слов (или 8060 байт). У IAR код получился размером 7086 байт. Могу сказать только то, что в IAR была устновлена максимальная оптимизация.
(К стати, в текстах для IAR, и в текстах для CV (т.е. -- везде) я заменил bit на BYTE.)

Но вот есть еще один, неприятный для CV факт. У меня в коде присутствует кусок размером 1536 байт, который является растром шрифта. По идее это кусок надо бы вычесть из размера флешь-кода, поскольку это не команды. Т.е. соотношение откомпилированного кода явно в пользу IAR.

Но самое забавное, что я вошел в азарт и перенес в IAR старый проект для tiny2313. Там CV создал код в 890 слов (1980 байт), а вот IAR перестарался -- 2012 байт. До кучи, IAR не смог создать отладочную версию, т.к. вылелел за 2048 байт.

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


--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
Go to the top of the page
 
+Quote Post
VDG
сообщение Nov 21 2007, 23:02
Сообщение #26


Знающий
****

Группа: Участник
Сообщений: 845
Регистрация: 10-02-06
Пользователь №: 14 193



12-ти %-ная разница в объёме сгенерировнного кода. Компиляторы равны в своих прямых функциях - генерации кода. Разница между ними только в IDE.


--------------------
Go to the top of the page
 
+Quote Post

2 страниц V  < 1 2
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 19:00
Рейтинг@Mail.ru


Страница сгенерированна за 0.01464 секунд с 7
ELECTRONIX ©2004-2016