|
Возврат структуры, Чисто теоретический вопрос... |
|
|
|
Jun 3 2009, 17:34
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Возник вопросик. Хочу уяснить для себя кое-что. Компилятор: avr-gcc (WinAVR 20090313) 4.3.2. Тест1 - размер структуры 7 байт и компилятор возвращает её через регистры - размер прошивки 60518 байт. Код typedef struct { unsigned char sec; unsigned char min; unsigned char hour; unsigned char sec_div10; // десятые секунды. unsigned char dat; // день месяца. unsigned char month; unsigned char year; // 0 = 2000 } rtc_t; Тест2 - размер структуры 39 байт и компилятор возвращает её через стек??? - размер прошивки 60088 байт (значительно компактней!!!). Код typedef struct { unsigned char sec; unsigned char min; unsigned char hour; unsigned char sec_div10; // десятые секунды. unsigned char dat; // день месяца. unsigned char month; unsigned char year; // 0 = 2000 unsigned char dummy[32]; } rtc_t; Исходник: Код //============================================================================= rtc_t dffs_get_page_start_time(unsigned short page) { rtc_t rtc;
df_read_to(page, DFFS_RTC_OFFSET, sizeof(rtc_t), &rtc);
return (rtc); } Есть два вопроса. Прошу не пинать (я знаю что можно возвращать указатель) вопросы только для самообразования. 1. как работает механизм передачи больших структур (если при выходе из неё я вижу полную раскрутку стека обратно)? 2. как принудить компилятор возвращать структуры через стек (если это так, пока я не понял). Листинг варианта1: Код //============================================================================= rtc_t dffs_get_page_start_time(unsigned short page) { b488: 2f 92 push r2 b48a: 3f 92 push r3 b48c: 4f 92 push r4 b48e: 5f 92 push r5 b490: 6f 92 push r6 b492: 7f 92 push r7 b494: 8f 92 push r8 b496: 9f 92 push r9 b498: af 92 push r10 b49a: bf 92 push r11 b49c: cf 92 push r12 b49e: df 92 push r13 b4a0: ef 92 push r14 b4a2: ff 92 push r15 b4a4: 0f 93 push r16 b4a6: 1f 93 push r17 b4a8: df 93 push r29 b4aa: cf 93 push r28 b4ac: cd b7 in r28, 0x3d; 61 b4ae: de b7 in r29, 0x3e; 62 b4b0: 2e 97 sbiw r28, 0x0e; 14 b4b2: 0f b6 in r0, 0x3f; 63 b4b4: f8 94 cli b4b6: de bf out 0x3e, r29; 62 b4b8: 0f be out 0x3f, r0; 63 b4ba: cd bf out 0x3d, r28; 61 rtc_t rtc;
df_read_to(page, DFFS_RTC_OFFSET, sizeof(rtc_t), &rtc); b4bc: 63 e0 ldi r22, 0x03; 3 b4be: 70 e0 ldi r23, 0x00; 0 b4c0: 47 e0 ldi r20, 0x07; 7 b4c2: 8e 01 movw r16, r28 b4c4: 0f 5f subi r16, 0xFF; 255 b4c6: 1f 4f sbci r17, 0xFF; 255 b4c8: 98 01 movw r18, r16 b4ca: 0e 94 b2 29 call 0x5364; 0x5364 <df_read_to>
return (rtc); b4ce: de 01 movw r26, r28 b4d0: 18 96 adiw r26, 0x08; 8 b4d2: f8 01 movw r30, r16 b4d4: 87 e0 ldi r24, 0x07; 7 b4d6: 01 90 ld r0, Z+ b4d8: 0d 92 st X+, r0 b4da: 81 50 subi r24, 0x01; 1 b4dc: e1 f7 brne .-8; 0xb4d6 <dffs_get_page_start_time+0x4e> b4de: 8e 85 ldd r24, Y+14; 0x0e b4e0: 99 24 eor r9, r9 b4e2: 28 84 ldd r2, Y+8; 0x08 b4e4: 39 84 ldd r3, Y+9; 0x09 b4e6: 4a 84 ldd r4, Y+10; 0x0a b4e8: 5b 84 ldd r5, Y+11; 0x0b b4ea: 6c 84 ldd r6, Y+12; 0x0c b4ec: 7d 84 ldd r7, Y+13; 0x0d b4ee: 51 01 movw r10, r2 b4f0: 62 01 movw r12, r4 b4f2: 73 01 movw r14, r6 } b4f4: 95 01 movw r18, r10 b4f6: a6 01 movw r20, r12 b4f8: b7 01 movw r22, r14 b4fa: 99 2d mov r25, r9 b4fc: 2e 96 adiw r28, 0x0e; 14 b4fe: 0f b6 in r0, 0x3f; 63 b500: f8 94 cli b502: de bf out 0x3e, r29; 62 b504: 0f be out 0x3f, r0; 63 b506: cd bf out 0x3d, r28; 61 b508: cf 91 pop r28 b50a: df 91 pop r29 b50c: 1f 91 pop r17 b50e: 0f 91 pop r16 b510: ff 90 pop r15 b512: ef 90 pop r14 b514: df 90 pop r13 b516: cf 90 pop r12 b518: bf 90 pop r11 b51a: af 90 pop r10 b51c: 9f 90 pop r9 b51e: 8f 90 pop r8 b520: 7f 90 pop r7 b522: 6f 90 pop r6 b524: 5f 90 pop r5 b526: 4f 90 pop r4 b528: 3f 90 pop r3 b52a: 2f 90 pop r2 b52c: 08 95 ret Видно что он резервирует на стеке вдвое больше памяти чем надо (14 байт вместо 7) потом тупо копирует одно в другое (из одной половинки 14-и байтного участка памяти в другую), потом читает вторую область памяти во временные регистры, потом копирует их содержимое в нужные регистры. Короче мрачняк... Листинг варианта2: Код //============================================================================= rtc_t dffs_get_page_start_time(unsigned short page) { b476: ef 92 push r14 b478: ff 92 push r15 b47a: 0f 93 push r16 b47c: 1f 93 push r17 b47e: df 93 push r29 b480: cf 93 push r28 b482: cd b7 in r28, 0x3d; 61 b484: de b7 in r29, 0x3e; 62 b486: a7 97 sbiw r28, 0x27; 39 b488: 0f b6 in r0, 0x3f; 63 b48a: f8 94 cli b48c: de bf out 0x3e, r29; 62 b48e: 0f be out 0x3f, r0; 63 b490: cd bf out 0x3d, r28; 61 b492: 7c 01 movw r14, r24 b494: cb 01 movw r24, r22 rtc_t rtc;
df_read_to(page, DFFS_RTC_OFFSET, sizeof(rtc_t), &rtc); b496: 63 e0 ldi r22, 0x03; 3 b498: 70 e0 ldi r23, 0x00; 0 b49a: 47 e2 ldi r20, 0x27; 39 b49c: 8e 01 movw r16, r28 b49e: 0f 5f subi r16, 0xFF; 255 b4a0: 1f 4f sbci r17, 0xFF; 255 b4a2: 98 01 movw r18, r16 b4a4: 0e 94 b2 29 call 0x5364; 0x5364 <df_read_to>
return (rtc); b4a8: d7 01 movw r26, r14 b4aa: f8 01 movw r30, r16 b4ac: 87 e2 ldi r24, 0x27; 39 b4ae: 01 90 ld r0, Z+ b4b0: 0d 92 st X+, r0 b4b2: 81 50 subi r24, 0x01; 1 b4b4: e1 f7 brne .-8; 0xb4ae <dffs_get_page_start_time+0x38> } b4b6: c7 01 movw r24, r14 b4b8: a7 96 adiw r28, 0x27; 39 b4ba: 0f b6 in r0, 0x3f; 63 b4bc: f8 94 cli b4be: de bf out 0x3e, r29; 62 b4c0: 0f be out 0x3f, r0; 63 b4c2: cd bf out 0x3d, r28; 61 b4c4: cf 91 pop r28 b4c6: df 91 pop r29 b4c8: 1f 91 pop r17 b4ca: 0f 91 pop r16 b4cc: ff 90 pop r15 b4ce: ef 90 pop r14 b4d0: 08 95 ret Тут всё красиво, но не понимаю как оно работает!!! Прошу прощения за длинное сообщение - не понял как создать окошко со скроллером. И ещё, никогда не пробовал, так и не знал, что можно присваивать структуру структуре  Код rtc_t rtc1 = {0}; rtc_t rtc2; .... rtc1 = rtc2; // и без всяких memcpy (здорово, код получается компактный с однобайтным счётчиком цикла!)
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 14)
|
Jun 3 2009, 18:34
|

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

|
Цитата(demiurg_spb @ Jun 3 2009, 20:34)  1. как работает механизм передачи больших структур (если при выходе из неё я вижу полную раскрутку стека обратно)? В данном случае - компилятор от себя добавляет первый неявный параметр - адрес той структуры, в которую надо вернуть результат. Т.е. Ваша функция Код rtc_t dffs_get_page_start_time(unsigned short page); на самом деле создаётся как Код void dffs_get_page_start_time_modified(rtc_t *dst, unsigned short page); и при вызове первый аргумент заполняется компилятором "от себя". Код b490: cd bf out 0x3d, r28; 61 b492: 7c 01 movw r14, r24 // -- вот тут этот параметр сохраняется b494: cb 01 movw r24, r22 // -- а вот тут переданный вторым page копируется // на место первого параметра df_read_to Цитата(demiurg_spb @ Jun 3 2009, 20:34)  2. как принудить компилятор возвращать структуры через стек (если это так, пока я не понял). Передавать указатель на получатель явно (бонус - можно возвращать статус операции). В Вашем случае сразу этот указатель и передавать в df_read_to(), не создавать локальной структуры (заодно потребности размера стека уменьшатся). В случае, когда структура не зачитывается тупо откуда-то, а создаётся, причём удобно это сделать локально, то можно воспользоваться Цитата(demiurg_spb @ Jun 3 2009, 20:34)  И ещё, никогда не пробовал, так и не знал, что можно присваивать структуру структуре  Например, так Код void dffs_get_page_start_time(rtc_t *dst, unsigned short page) { rtc_t rtc; // ... // заполняем структуру // ... *dst = rtc; }
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Jun 4 2009, 07:27
|

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

|
Цитата(_Pasha @ Jun 4 2009, 09:59)  Возвращать структуры через стек опасно по причине легкой разрушаемости этой самой структуры. Это только для структуры справедливо или для обычных типов тоже? А то в функцию параметры тоже, бывает, на стеке передаются - это не опасно? Они там не испортятся? А локальные переменные? Цитата(ukpyr @ Jun 4 2009, 09:34)  чем указатели не угодили ? просто объявите внутреннюю структуру static и возвращайте указатель на нее. И напрочь забудьте о реентерабельности. После чего забыв о нереентерабельности этой функции используйте ее некорректно и получите удивительные грабли.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jun 4 2009, 07:40
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(Сергей Борщ @ Jun 4 2009, 10:27)  А то в функцию параметры тоже, бывает, на стеке передаются - это не опасно? Они там не испортятся? А локальные переменные? Не-не-не. При передаче параметров и выделении локальных перем вначале передвинулся указатель стека, и последующие вызовы, например, прерываний, не испортят данных. А здесь что??? Вернули структуру и восстановили стек (как же без этого ?)  Любой взрослый ISR свалит Вам структуру нафиг. Без атомарного доступа к результату функции, ессно. ЗЫ: и тоже прикол, что обеспечить атомарный доступ придется до вызова функции. Смешно.
|
|
|
|
|
Jun 4 2009, 08:08
|

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

|
Цитата(_Pasha @ Jun 4 2009, 11:00)  Может я чего-то не понимаю, но возвращаемая структура в стеке, I-флаг может быть установлен ранее, указатель стека явно над этой самой структурой. Как оно может работать?? Так ведь структура возвращается не внутри фрейма функции. Вызывающая функция резервирует на стеке место под возвращаемое значение, после чего передает указатель на это место в вызываемую. ReAl же объяснил. P.S. неужели вы думаете, что в язык была специально заложена некая возможность (возврат структуры), которая может работать или не работать в зависимости от положения звезд на небе?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Jun 4 2009, 11:32
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
ukpyr, я же изначально просил не поднимать флейм, а Ваше сообщение абсолютно бессмысленно. ReAl и Сергей, спасибо за разъяснения! Всё встало на свои места Осталось найти и опции компилятора (если они существуют), которые определяют максимальный размер возвращаемого параметра при котором он будет передан не через регистры а через стек. Мне действительно нужна реентерабельность функции и в тоже время логичность и простота... Тогда получается что во втором варианте компилятор поступает неразумно, опять выделяет место на стеке под локальную переменную, вместо того, чтобы сразу использовать область памяти полученную через указатель скрытым аргументом. Опять обидно... Может есть способ обойти это?
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|