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

 
 
> Возврат структуры, Чисто теоретический вопрос...
demiurg_spb
сообщение Jun 3 2009, 17:34
Сообщение #1


неотягощённый злом
******

Группа: Свой
Сообщений: 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

Тут всё красиво, но не понимаю как оно работает!!!
Прошу прощения за длинное сообщение - не понял как создать окошко со скроллером.

И ещё, никогда не пробовал, так и не знал, что можно присваивать структуру структуреsmile.gif
Код
rtc_t rtc1 = {0};
rtc_t rtc2;
....
rtc1 = rtc2; // и без всяких memcpy (здорово, код получается компактный с однобайтным счётчиком цикла!)


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
2 страниц V   1 2 >  
Start new topic
Ответов (1 - 14)
ReAl
сообщение Jun 3 2009, 18:34
Сообщение #2


Нечётный пользователь.
******

Группа: Свой
Сообщений: 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) *
И ещё, никогда не пробовал, так и не знал, что можно присваивать структуру структуреsmile.gif

Например, так
Код
void dffs_get_page_start_time(rtc_t *dst, unsigned short page)
{
    rtc_t rtc;
    // ...
    // заполняем структуру
    // ...
    *dst = rtc;
}


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Jun 3 2009, 19:19
Сообщение #3


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Какие-то "странноватые" задачи вы сами себе придумываете. На кой надо возвращать структуру из функции? Может компилятор и генерит более компактный код, но в целом такое решение крайне неэффективно.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Jun 3 2009, 20:24
Сообщение #4


Нечётный пользователь.
******

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



В первую очередь это более понятный код. Говорим/думаем "функция возвращает структуру" и пишем так же, а не "функция получает указатель на структуру для её заполнения" (при этом помня, что не для модификации или чтения).


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Jun 4 2009, 06:06
Сообщение #5


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Цитата(ReAl @ Jun 3 2009, 23:24) *
В первую очередь это более понятный код. Говорим/думаем "функция возвращает структуру" и пишем так же, а не "функция получает указатель на структуру для её заполнения" (при этом помня, что не для модификации или чтения).


Чем быстрее вы поймете неэффективность такого подхода, тем лучше будет для вашей будущей деятельности. Почитайте про ухищрения современных С++ компиляторов (RVO), оптимизирующих возврат объектов из функции (структура - тоже объект) : http://en.wikipedia.org/wiki/Return_value_optimization.
Go to the top of the page
 
+Quote Post
ukpyr
сообщение Jun 4 2009, 06:34
Сообщение #6


Профессионал
*****

Группа: Участник
Сообщений: 1 264
Регистрация: 17-06-08
Из: бандустан
Пользователь №: 38 347



автор, вы перешли на С с Паскаля, нет ?
почитайте документацию на AVR_GCC, в каких регистрах передаются параметры/результаты.
возвращение результата-структуры через стек - мягко говоря странно и неэффективно для АВР.
чем указатели не угодили ? просто объявите внутреннюю структуру static и возвращайте указатель на нее.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jun 4 2009, 06:59
Сообщение #7


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Возвращать структуры через стек опасно по причине легкой разрушаемости этой самой структуры. Кто даст гарантию, что поля дойдут до обработчега? 
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jun 4 2009, 07:27
Сообщение #8


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jun 4 2009, 07:40
Сообщение #9


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(Сергей Борщ @ Jun 4 2009, 10:27) *
А то в функцию параметры тоже, бывает, на стеке передаются - это не опасно? Они там не испортятся? А локальные переменные?

Не-не-не. При передаче параметров и выделении локальных перем вначале передвинулся указатель стека, и последующие вызовы, например, прерываний, не испортят данных. А здесь что??? Вернули структуру и восстановили стек (как же без этого ?) cranky.gif  Любой взрослый ISR свалит Вам структуру нафиг. Без атомарного доступа к результату функции, ессно.
ЗЫ: и тоже прикол, что обеспечить атомарный доступ придется до вызова функции. Смешно.
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Jun 4 2009, 07:53
Сообщение #10


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



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


Что-то любезный вы в общетеоретические изыски углубились. По вашим рассуждениям ни одна С++ -ая программа с прерываниями работать не будет. Тем не менее - работает. Без всяких "атомарных" прибамбасов.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jun 4 2009, 08:00
Сообщение #11


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(sergeeff @ Jun 4 2009, 10:53) *
Тем не менее - работает. Без всяких "атомарных" прибамбасов.

Дык гляньте листинг вариант №2  из первого поста. Может я чего-то не понимаю, но возвращаемая структура в стеке, I-флаг может быть установлен ранее, указатель стека явно над этой самой структурой. Как оно может работать?? 
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jun 4 2009, 08:08
Сообщение #12


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jun 4 2009, 08:21
Сообщение #13


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(Сергей Борщ @ Jun 4 2009, 11:08) *
 ReAl же объяснил.

Спасибо, разобрался. Листинг ниасилил с первого прохода smile.gif
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Jun 4 2009, 11:32
Сообщение #14


неотягощённый злом
******

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



ukpyr, я же изначально просил не поднимать флейм, а Ваше сообщение абсолютно бессмысленно.
ReAl и Сергей, спасибо за разъяснения! Всё встало на свои местаsmile.gif
Осталось найти и опции компилятора (если они существуют), которые определяют максимальный размер возвращаемого параметра при котором он будет передан не через регистры а через стек. Мне действительно нужна реентерабельность функции и в тоже время логичность и простота...
Тогда получается что во втором варианте компилятор поступает неразумно, опять выделяет место на стеке под локальную переменную, вместо того, чтобы сразу использовать область памяти полученную через указатель скрытым аргументом. Опять обидно... Может есть способ обойти это?


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
sergeeff
сообщение Jun 4 2009, 11:34
Сообщение #15


Профессионал
*****

Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007



Цитата(_Pasha @ Jun 4 2009, 11:21) *
Спасибо, разобрался. Листинг ниасилил с первого прохода smile.gif


Трудно найти черную кошку в темной комнате, особенно, если ее там нет.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 21st July 2025 - 22:16
Рейтинг@Mail.ru


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