|
Век живи, век учись..., функции в CodeVision не позволяют возвращать структуры |
|
|
|
Nov 17 2007, 15:00
|

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

|
ну, или скорее это удар в поддых... Ситуация такая. Пишу крупный прокт на CodeWizardAVR V1.25.3 Standard для mega2561. Почти ООП. Почти самопальная ОСь. Сообщения, очереди, синхронизация... Проект разрастается быстро. Сегодня пришел к пониманию того, что сообщения нужно сделать не ввиде простох чисел Код typedef BYTE MSG; , а как в виде структур Код typedef struct { BYTE code; WORD param; } MSG; Предвижу Ваши соображения по поводу неизвестных BYTE и WORD. Где-то в хэдерных файлах у меня есть определение Код typedef unsigned char BYTE; typedef unsigned int WORD; так что все здесь срастается и работает. Переделываю исходники на новый лад и ... получаю удар граблями со стороны CodeVision. Угадайте с трех раз, откуда? Подсказка Цитата Error: ... function must return a pointer to structure раньше было красиво msg = GetMessage(); Сейчас это уже не канает. Даже передать указатель на структуру, как это просит уважаемый CV, нельзя. Ну, не в том смысле что компилятор не пропустит, а в том, что на _какую_именно_структуру? -- Т.е. на ту, которая определяется в функции, -- нельзя. Ибо структура прекратит свое существоание в момент выхода из функции. Указатель невалиден. Значит остается, единственное решение -- наоборот, передавать указатель в функцию. Как-то это все не по-людски...  Я уже было усомнился в своих знаниях языка (1) по передаче структур из функций, а потом в самих компиляторах для микроконтроллеров. Но нет! Ни старый добрый Borland Turbo-C 2.0, ни IAR таких ограничений не налагают. Знаит, это есть причуда CV. Читаем в хэлпах КоудВижина Цитата The old Kernighan & Ritchie style of writing function definitions is not supported. и еще тут Цитата Because some AVR devices have a small amount of SRAM, in order to keep the size of the Data Stack small, it is recommended not to pass structures as function parameters and use pointers for this purpose. Правда, про возврат структур тут прямо ничего не сказано. Но видимо, подрадумевается, что программер понимает, что если передавать структуру в функцию -- это вилы, то уж возврат из функции явно крах всей системы! Народ, не наступайте на мои грабли  Больна-а...
--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 25)
|
Nov 17 2007, 15:16
|
Группа: Новичок
Сообщений: 2
Регистрация: 1-09-06
Пользователь №: 20 010

|
Цитата(zhevak @ Nov 17 2007, 16:00)  Значит остается, единственное решение -- наоборот, передавать указатель в функцию. Как-то это все не по-людски...  Прошу прощения, что лезу с советами не в свой огород, но чем Вам не нравится передавать указатель на структуру как параметр функции? Думаю, опыт microsoft в разработке софта оспаривать никто не будет, но они делают именно так. Код BOOL GetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax );
lpMsg [out] Pointer to an MSG structure that receives message information from the thread's message queue. (остальное здесь неважно)
|
|
|
|
|
Nov 17 2007, 15:27
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(zhevak @ Nov 17 2007, 17:00)  ну, или скорее это удар в поддых...
Ситуация такая. Пишу крупный прокт на CodeWizardAVR V1.25.3 Standard для mega2561. Поздравляем! Вы прошли CV до конца  Пора менять компилятор. И лучше это сделать сейчас, пока проект только разрастается, а не "разросся". Ибо это не единтственный тупик в CV. Можно рекомендовать IAR и WinAVR. Цитата(zhevak @ Nov 17 2007, 17:00)  Знаит, это есть причуда CV. Читаем в хэлпах КоудВижина Цитата The old Kernighan & Ritchie style of writing function definitions is not supported. Это не то. Это в первом издании K&R был вариант определения функций void func() int a, int b { } или что-то очень похожее вместо void func (int a, int b ) { }.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Nov 17 2007, 16:08
|

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

|
Я что-то не въезжаю. Цитата Ибо структура прекратит свое существоание в момент выхода из функции. Указатель невалиден. А как иначе? Где по вашему должны продолжать существовать данные структуры после выхода из функции? Причем здесь CV?
--------------------
|
|
|
|
|
Nov 17 2007, 16:29
|

Знающий
   
Группа: Свой
Сообщений: 902
Регистрация: 2-01-06
Из: Краснодар
Пользователь №: 12 768

|
Цитата(VDG @ Nov 17 2007, 19:08)  Я что-то не въезжаю.
А как иначе? Где по вашему должны продолжать существовать данные структуры после выхода из функции? Причем здесь CV? там-же,где и возвращаемые локальные переменные из фукции-в стеке.т.е не проходит return MSG; Но имхо,это не не причина отказываться от компилятора.сделайте вашу структуру MSG глобальной или работайте с ней динамически-создавйте-удаляйте в куче в планировщике и возвращайте через указатель-чуть проиграите в обьеме свободного озу,выиграете в размере стека. господин Хайдук вполне внятно обьяснил-озу в авр кот наплакал.и это ваша структура крохотная, а бывают и байт на 100 и больше-зачем ее всю в стек пихать.
--------------------
"Hello, word!" - 17 errors 56 warnings
|
|
|
|
|
Nov 17 2007, 16:54
|

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

|
Цитата(Yason @ Nov 17 2007, 20:16)  Прошу прощения, что лезу с советами не в свой огород, но чем Вам не нравится передавать указатель на структуру как параметр функции? Думаю, опыт microsoft в разработке софта оспаривать никто не будет, но они делают именно так. Код BOOL GetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax );
lpMsg [out] Pointer to an MSG structure that receives message information from the thread's message queue. (остальное здесь неважно) Не надо прость прощения, все нормально. Ну это как яблоки -- "ну почему вам не нравятся зеленые яблоки?". Не нравится потому, что придется сейчас переделывать еще и вызовы функций (PutMessage, GetMessage, может еще какие) и далее преретрехать проект. Ну, нравится - не нравится, а прийдется... Разница между МС и моим ГетМессэйджем в том, что я не обрабатываю сообщений об окончании работы приложения, и следовательно, мне не нужно возвращать BOOL. У меня их просто как таковых нет. Зачем, собственно? Т.е. это как раз тот момент, чем отличается программы для микроконтроллеров от программ для компов. Цитата(Сергей Борщ @ Nov 17 2007, 20:27)  Поздравляем! Вы прошли CV до конца  Пора менять компилятор. И лучше это сделать сейчас, пока проект только разрастается, а не "разросся". Спасибо. Я тоже склоняюсь этой мысли... Давно было пора. А оно вот когда выстрелило. В самый не подходящий момент. Цитата Это не то. Это в первом издании K&R был вариант определения функций void func() int a, int b { } или что-то очень похожее вместо void func (int a, int b ) { }. ах, да! Точно.  Цитата(WHALE @ Nov 17 2007, 21:29)  там-же,где и возвращаемые локальные переменные из фукции-в стеке.т.е не проходит return MSG; Но имхо,это не не причина отказываться от компилятора.сделайте вашу структуру MSG глобальной или работайте с ней динамически-создавйте-удаляйте в куче в планировщике и возвращайте через указатель-чуть проиграите в обьеме свободного озу,выиграете в размере стека. господин Хайдук вполне внятно обьяснил-озу в авр кот наплакал.и это ваша структура крохотная, а бывают и байт на 100 и больше-зачем ее всю в стек пихать. Глобальная структура? Ну, я не знаю... по моему перебор! Я итак огребаю сложности из-за отсутствия ни пространств имен и классов, так ту еще одна глобальная бестия появится. Нет, конечно, это можно сделать. Более того работать оно будет. Но каков будет код! И все это ради сохранеия религии CV? Динамическое выделение памяти тоже не метод. Сильно проиграю в скорости. Не говоря уже про фрагментацию памяти и прочие возможные проблемы, которые сейчас не видны. Нет, господа, разговор идет не о том, как мне сохранить проект в CV. При желании я и сам смогу обойти эти грабли. Проблема вынесена в название топика: речь о другом -- о фичах CV, которые не были видны по началу. И я думаю, что я не один такой, кто сначала обрадовался легкости CV и сориентировался на него, как на средство разработки. Цитата(WHALE @ Nov 17 2007, 21:29)  господин Хайдук вполне внятно обьяснил-озу в авр кот наплакал.и это ваша структура крохотная, а бывают и байт на 100 и больше-зачем ее всю в стек пихать. да-да, именно! Структура крохотная. С опломбом влезет в регистры, которые CV традиционно использует при возврате из функции. Нам ничего не мешает возвращать эту крохотную структуру из функции по значению, а не, наоборот, передавать в функцию указатель на нее (чтоб функция по указатель произвела присвоение нужным элементам структуры). Ничего, кроме самого компилятора. В этом-то и проблема.
--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
|
|
|
|
|
Nov 17 2007, 17:24
|

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

|
Цитата(WHALE @ Nov 17 2007, 22:08)  ну и при чем здесь CV?Если вам надо ООП,пространства имен и прочие прелести-это другое дело и С компилятор тут ни в чем не виновват.Тогда да,адназначна или IAR или WINAVR.  По началу казалось, что задачу можно поднять на чистом С (не С++). Это уже потом сложности пришли. До кучи, предыдущий программер (который был до меня) писал на CV, и заказчик хотел бы видеть CV. Если бы я сразу заявил про IAR, то скорее всего не получил бы заказ. Зачем Вам мои оправдания? Жизнь сложная шткука. Цитата(WHALE @ Nov 17 2007, 22:08)  пока писал-вы добавили.Имхо,Паша Хайдук принял достаточно мудрое решение и в хэлпе обьяснил почему он решил не поддерживать в качестве возвращаемого параметра из фукцию структуру. А представьте обратную ситуацию-все поддерживается и большая структура пихается в стек.В резуль- тате выход за пределы стека и крах программы или абсолютно непредсказуемые глюки. Я к сожалению не так близко знаком с Пашей Хайдуком... Возможно у него были какие-то еще соображения, которые он предпочел Вам не говорить. Иначе как объяснить, что _это_ реализовано в IAR-е (другие компиляторы для AVR не проверял), и не реализовано в CV?
--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
|
|
|
|
|
Nov 17 2007, 17:32
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(WHALE @ Nov 17 2007, 19:08)  Паша Хайдук принял достаточно мудрое решение и в хэлпе обьяснил почему он решил не поддерживать в качестве возвращаемого параметра из фукцию структуру. А представьте обратную ситуацию-все поддерживается и большая структура пихается в стек.В результате выход за пределы стека и крах программы или абсолютно непредсказуемые глюки. В маленькой тиньке мало памяти. В м128 ее уже 4К, и можно навешать внешней по самое нехочу. Это "мало"? А вот когда все рушится, потому что горе-программист положил огромную структуру в стек - тут уж точно компилятор виноватым быть не может. Для начала - если использовать метод передачи указателя на структуру, то структуру, на которую передается уазатель тоже надо где-то размещать. Где? Создавать локально в вызывающей функции. На стеке. Ровно в том же самом месте стека, где она бы разместилась если бы возвращалась из функции. При возврате структуры из функции указатель на нее передается неявно через указатель стека - а мы вынуждены передавать его явно в одном из параметров. Очень "мудрое" решение. Программист может точно также завести внутри функции локальный массив из 1000 элементов - и все навернется аналогично. И что, компилятор сразу станет плохим, что позволил массивы? Хорошо, запретитм массивы. Насоздаем локальных переменных - структур или просто много-много переменных встроенных типов. Сдуру можно и х.. сломать. Цитата(zhevak @ Nov 17 2007, 19:24)  и заказчик хотел бы видеть CV. Сочувствую. Возможно пора начинать убеждать его, что WinAVR не сложнее, стоит дешевле (ноль), и не имеет тупиков. Тем более что реальный аргумент у вас есть.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Nov 17 2007, 18:03
|

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

|
Цитата(VDG @ Nov 17 2007, 21:08)  Я что-то не въезжаю.
А как иначе? Где по вашему должны продолжать существовать данные структуры после выхода из функции? Причем здесь CV? "данные структуры продолжают существовать..." -- не совсем корректное понимание сути. При возвращении маленькой структуры ее данные возвращаются в регистрах. Здесь вопросов нет. При возвращении из функции больших структур, вызовы функций выглядят совершенно иначе. Перед вызовом функции, а точнее на языке ассеблера -- подпрограммы -- сначала в стек помещаются фактические параметры, а потом неявно (т.е. в Си-шном коде этого мы не видим и знать не знаем!) помещается адрес структуры, которой присвоится возвращаемое из функции значение. Т.е. для нашего примера перед вызовом GetMessage в стеке будет присутствовать адрес msg Код MSG msg;
msg = GetMessage(); Функция же как таковой возврат не производит, она просто напрямую работает с переданным ей адресом структуры. После возврата из функции происходи обычная очистка стека, точно такая же как если бы функция принимала какие-то парметры. Если что не понятно, попробуйте посмотреть ассемблерный код. Хотя это звучит очень агрессивно с моей стороны, за что приношу свои извинения. Цитата(Сергей Борщ @ Nov 17 2007, 22:32)  Создавать локально в вызывающей функции. На стеке. Ровно в том же самом месте стека, где она бы разместилась если бы возвращалась из функции. При возврате структуры из функции указатель на нее передается неявно через указатель стека - а мы вынуждены передавать его явно в одном из параметров. Фигасе! Насколько одновременно и параллельно мысли бывает приходят! Поскольку я позже приклеил свой пост, с мой стороны выглядит почти как плагиат. Цитата Сочувствую. Возможно пора начинать убеждать его, что WinAVR не сложнее, стоит дешевле (ноль), и не имеет тупиков. Тем более что реальный аргумент у вас есть. Плановая встреча с заказчиком у меня намечена на Понедельник. У меня еще есть время попытаться перенести проект в IAR (WinAVR я не знаю), а в случае неудачи пытаться сохранить проект в CV. Тем более, что проект далеко еще не окончен. Еще много предстоит сделать. Как минимум наполнить кодом обработчики событий. А что касаемо "убедить заказчика", то по ходу работы на проектом, у меня уже приобретен солидный кредит доверия. Думаю, что сейчас это как раз не проблема.
--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
|
|
|
|
|
Nov 17 2007, 18:30
|
Группа: Участник
Сообщений: 11
Регистрация: 14-07-06
Из: Кишинёв
Пользователь №: 18 825

|
Можно попробовать сделать так: Код typedef union { DWORD val_dword; struct { BYTE code; WORD param; }; } MSG;
DWORD GetMessage() { MSG msg; msg.code = ...; msg.param = ...; return msg.val_dword; }
...
// один вариант
MSG msg; msg.val_dword = GetMessage();
// другой вариант
MSG msg = {GetMessage()}; ...
|
|
|
|
|
Nov 17 2007, 19:21
|

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

|
Цитата(SlavaG @ Nov 17 2007, 23:30)  Можно попробовать сделать так: ... Слава, спасибо. Но это как вариант. Реально не проканает по однйо причине -- изврат. Код желательно писать прозрачно, а тут без объяснений сложно просечь что к чему, т.е. зачем так сделали. Это мы сейчас понимаем, потому как в курсе проблемы, а пройдет полгода? Или кто-нибудь после меня будет рагребать мой текст? Я уже начал преносить проект в IAR. (За что программисты получают много денег? Гы-гы!)
--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
|
|
|
|
|
Nov 17 2007, 21:35
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(WHALE @ Nov 17 2007, 19:08)  почему он решил не поддерживать в качестве возвращаемого параметра из фукцию структуру. А представьте обратную ситуацию-все поддерживается и большая структура пихается в стек.В резуль- тате выход за пределы стека и крах программы или абсолютно непредсказуемые глюки. ИМХО, возврат структуры напрямую путем копирования ее в стек а не через указатель дурной тон. Какой такой павлин-шмавлин стек? Я ещё не видел С-компилятора, который возвращал бы что-то на стеке, это ведь не Форт :-) Способ реализации возврата структуры может зависеть от реализации, но я пока не видел ничего кроме 1) в функцию передаётся неявный первый пареметр - указатель на ту переменную, где вызывающая функция хочет видеть результат 2) если компилятор поумнее, то если размер структуры не более какого-то предела, то вся структура возвращается на регистрах. Для AVR-GCC - порог 8 байт. В данном случае структура сообщения будет возвращена на регистрах. Только не надо говорить "ага, он сам передаёт этот указатель, так что же меняется?" Меняется уровень абстракции и удобства написания. Можно и присвоение одной структуры другой писать через memcpy, а можно написать a = b; Цитата(SlavaG @ Nov 17 2007, 20:30)  Можно попробовать сделать так: И как аргумент "за" - "а так в Windows уже было сделано, поэтому так хорошо!" :-) (только там наоборот - в функцию в DWORD lparam передавались два склеенных WORD)
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 17 2007, 22:46
|

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

|
Цитата Разница между МС и моим ГетМессэйджем в том, что я не обрабатываю сообщений об окончании работы приложения, и следовательно, мне не нужно возвращать BOOL. У меня их просто как таковых нет. Зачем, собственно? Т.е. это как раз тот момент, чем отличается программы для микроконтроллеров от программ для компов. У меня например не отличаются. Я делаю окна в МК аналогично как в Win32. Т.е. мои окна также "закрываются". Когда Ваш код также разрастётся, то Вам эту функцию придётся также ввести. Лучше сейчас, чем потом опять переписывать уже второй раз. Цитата Функция же как таковой возврат не производит, она просто напрямую работает с переданным ей адресом структуры. Наверняка это возможно только в момент возврата. Цитата Если что не понятно, попробуйте посмотреть ассемблерный код. Хотя это звучит очень агрессивно с моей стороны, за что приношу свои извинения. Не агрессивно. В скомпиллированном коде CV я много копаюсь, и как он возвращает результат знаю, поэтому мне интересно как другие компиляторы возвращают объёмные данные.
--------------------
|
|
|
|
|
Nov 19 2007, 06:38
|

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

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

Местный
  
Группа: Свой
Сообщений: 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.
|
|
|
|
|
Nov 19 2007, 08:43
|
Знающий
   
Группа: Свой
Сообщений: 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
|
|
|
|
|
Nov 19 2007, 08:50
|

Знающий
   
Группа: Свой
Сообщений: 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; } Заумные тексты программ это не есть высокий уровень профессионализма. Конечно, все это можно реализовать с помощью указателей на структуры, но при этом немного потеряется читабельность. Чуть-чуть тут, чуть-чуть там, вроде немного. Но когда проектов много, и к ним приходится возвращаться через несколько месяцев, честно говоря -- это уже начинает напрягать. Или я не прав?
--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
|
|
|
|
|
Nov 19 2007, 09:17
|

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)  Заумные тексты программ это не есть высокий уровень профессионализма.
Конечно, все это можно реализовать с помощью указателей на структуры, но при этом немного потеряется читабельность. Чуть-чуть тут, чуть-чуть там, вроде немного. Но когда проектов много, и к ним приходится возвращаться через несколько месяцев, честно говоря -- это уже начинает напрягать.
Или я не прав? Описанный выше вариант, когда компилятор сам организовывает передачу указателя вполне прозрачен. Для пользователя тут все однозначно - он получает из функции структуру по значению, как и требуется по Стандарту. А как это уже сделал компилятор, это дело третье.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Nov 19 2007, 09:39
|

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

|
Цитата(dxp @ Nov 19 2007, 14:17)  А где тут прозрачность страдает? Или что вы подразумеваете под прозрачностью? Прозрачность начинает уменьшаться с появлением звездочек и амперсендов. Например, в Васике нет этого, поэтому тексты программ на нем более прозрачны, чем на Си. Только не надо передергивать, а то уйдем в бессмысленное словоблудие. (Я, к стати, не адепт Васика.) Понятно, что без указателей будет язык -- неязык. Но там где можно обойтись без указателей, зачем их пихать почем зря? Вообще-то речь идет о том, что моя структура могла бы легко быть возвращена по значению даже в регистрах, но компилятор не предоставил такой возможности вообще! Цитата Вариант с указателем проигрывает (на AVR) только для размера структуры, меньшего размера указателя. В остальных случаях он или не хуже, или лучше. Причем здесь AVR? Это у любой платформы. Цитата Описанный выше вариант, когда компилятор сам организовывает передачу указателя вполне прозрачен. Для пользователя тут все однозначно - он получает из функции структуру по значению, как и требуется по Стандарту. А как это уже сделал компилятор, это дело третье. Ага. По-моему, мы говорим об одном и том же, а такое чувство, что стоим по разные стороны.
--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
|
|
|
|
|
Nov 19 2007, 10:06
|

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); Тут уж все однозначно. Хотя синтаксис немного другой.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Nov 19 2007, 10:49
|

кекс
     
Группа: Свой
Сообщений: 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 );
}
|
|
|
|
|
Nov 21 2007, 20:18
|

Знающий
   
Группа: Свой
Сообщений: 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 байт.
Выводы делать не буду, комментировать цифры тоже. "Исходники в студию не принесу", авторство, разумеется, -- мое, но вот исходники (собственность) принадлежат фирме.
--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|