Перейти к содержимому

Как вернуть структуру из функции c

  • автор:

Как вернуть структуру из функции c

Подскажите пожалуйста новичку, как на СИ возвратить структуру из функции

struct myStruct < UINT16 Param1; UINT16 Param2; >;
VOID. myFunc() < struct myStruct *myStruct; myStruct->Param1 = 10; myStruct->Param2 = 20; // Как сдесь написать return что бы вернуть структуру myStruct . Подскажите новичку пожалуйста return . ; >;

По форуму искал но так и ничего толком не понял, можно ожалуйста наглядный пример, большое спасибо

Re: Возврат структуры из функции на СИ

От: gandjustas http://blog.gandjustas.ru/
Дата: 11.08.07 12:45
Оценка:

Мжет лучше еще раз перечитать книжку по С ?
Столько ошибок в одной тривиальной функции я еще не видел.

Re: Возврат структуры из функции на СИ

От: Аноним
Дата: 11.08.07 12:49
Оценка: 3 (1)

Здравствуйте, AlexBosen, Вы писали:

AB>Подскажите пожалуйста новичку, как на СИ возвратить структуру из функции

AB>Имеем структуру:

AB>

AB>struct myStruct AB> < AB>UINT16 Param1; AB> UINT16 Param2; AB>>; AB>

AB>Имеем функцию:

AB>

AB>VOID. myFunc() AB> < AB>struct myStruct *myStruct; AB> myStruct->Param1 = 10; AB> myStruct->Param2 = 20; AB> // Как сдесь написать return что бы вернуть структуру myStruct . Подскажите новичку пожалуйста AB> return . ; AB>>; AB>

AB>По форуму искал но так и ничего толком не понял, можно ожалуйста наглядный пример, большое спасибо

void* myFunc() < struct myStruct *myStruct; myStruct->Param1 = 10; myStruct->Param2 = 20; return ( (void*)(myStruct) ); >;

но это не совсем красиво
ИМХО лучше так:

// . myStruct *pStruct = new myStruct; myFunc( *pStruct ); // . void myFunc(myStruct& aStruct) < aStruct.Param1 = 10; aStruct.Param2 = 20; >;

Re[2]: Возврат структуры из функции на СИ

От: AlexBosen
Дата: 11.08.07 12:52
Оценка:

Здравствуйте, gandjustas, Вы писали:

G>Мжет лучше еще раз перечитать книжку по С ?
G>Столько ошибок в одной тривиальной функции я еще не видел.

Спасибо за совет, но я же новичек и только учусь

Re: Возврат структуры из функции на СИ

От: Аноним
Дата: 11.08.07 12:52
Оценка: 6 (2)

Здравствуйте, AlexBosen, Вы писали:

AB>Подскажите пожалуйста новичку, как на СИ возвратить структуру из функции

AB>Имеем структуру:

AB>

AB>struct myStruct AB> < AB>UINT16 Param1; AB> UINT16 Param2; AB>>; AB>

AB>Имеем функцию:

AB>

AB>VOID. myFunc() AB> < AB>struct myStruct *myStruct; AB> myStruct->Param1 = 10; AB> myStruct->Param2 = 20;

Так нельзя. Для структуры надо выделить память
1. статически

struct myStruct s;

2. либо динамически

struct myStruct* ps = (myStruct*)malloc(sizeof(myStruct));

Во втором случае не забудь освободить память (free(. )).

 AB> // Как сдесь написать return что бы вернуть структуру myStruct . Подскажите новичку пожалуйста AB> return . ; AB>>; AB>
struct myStruct myFunc()
struct myStruct* myFunc()

AB>По форуму искал но так и ничего толком не понял, можно ожалуйста наглядный пример, большое спасибо

Re[2]: Возврат структуры из функции на СИ

От: Awaken
Дата: 11.08.07 12:56
Оценка: 2 (1)

А>myStruct *pStruct = new myStruct;

забыли вы Си совсем
в C нет new/delete. по значению тоже не передашь т.к. нет конструкторов копирования
единственный вариант тут это calloc/malloс . или объявить ее глобальной переменной

Re[3]: Возврат структуры из функции на СИ

От: Аноним
Дата: 11.08.07 13:06
Оценка: 3 (2)

Здравствуйте, Awaken, Вы писали:

А>>myStruct *pStruct = new myStruct;

A>забыли вы Си совсем
A>в C нет new/delete. по значению тоже не передашь т.к. нет конструкторов копирования
Чего? Comeau в режиме С99 компилит нормально.

Re[3]: Возврат структуры из функции на СИ

От: Аноним
Дата: 11.08.07 13:10
Оценка: 3 (1)

Здравствуйте, Awaken, Вы писали:

А>>myStruct *pStruct = new myStruct;

A>забыли вы Си совсем
A>в C нет new/delete. по значению тоже не передашь т.к. нет конструкторов копирования
A>единственный вариант тут это calloc/malloс . или объявить ее глобальной переменной

Все правильно, это ++ вариант.
плюсы съели остатки моего мозга

Re[4]: Возврат структуры из функции на СИ

От: Awaken
Дата: 11.08.07 14:09
Оценка:

А>Чего? Comeau в режиме С99 компилит нормально.

за С99 не слежу. ты прав, там это стало стандартной фичей.

Re[5]: Возврат структуры из функции на СИ

От: Аноним
Дата: 11.08.07 14:29
Оценка:

Здравствуйте, Awaken, Вы писали:

А>>Чего? Comeau в режиме С99 компилит нормально.

A>за С99 не слежу. ты прав, там это стало стандартной фичей.
А какой Си Вы имели в виду? С89/С90 тоже поддерживает передачу и возврат структур по значению. Разве в K&R C было по другому?

Re[2]: Возврат структуры из функции на СИ

От: AlexBosen
Дата: 11.08.07 14:55
Оценка:

Здравствуйте, Аноним, Вы писали:

struct myStruct s; struct myStruct myFunc()

Огромное спасибо Все получилось!

Передача структур в функции и возврат структур из функций

Замечаем, что функция main выделяет в стеке 16 байт, но при выравнивании стека освобождаются только 8 байт. Остальные 8 байт заняты структурой. Функция makepoint :

 0x080483bb : push ebp 0x080483bc : mov ebp,esp 0x080483be : sub esp,0x10 0x080483c1 : mov eax,DWORD PTR [ebp+0xc] 0x080483c4 : mov DWORD PTR [ebp-0x8],eax 0x080483c7 : mov eax,DWORD PTR [ebp+0x10] 0x080483ca : mov DWORD PTR [ebp-0x4],eax 0x080483cd : mov ecx,DWORD PTR [ebp+0x8] 0x080483d0 : mov eax,DWORD PTR [ebp-0x8] 0x080483d3 : mov edx,DWORD PTR [ebp-0x4] 0x080483d6 : mov DWORD PTR [ecx],eax 0x080483d8 : mov DWORD PTR [ecx+0x4],edx 0x080483db : mov eax,DWORD PTR [ebp+0x8] 0x080483de : leave 0x080483df : ret 0x4 

Еще раз посмотрим на это место в main :

 0x080483eb : push 0x2 0x080483ed : push 0x1 0x080483ef : push eax 0x080483f0 : call 0x80483bb

С учетом адреса возврата и сохраненного ebp , адрес структуры (push eax) будет отодвинут на 3 дворда, это 0xC байт, и, видимо, обращение к адресу структуры мы наблюдаем здесь:

mov eax,DWORD PTR [ebp+0xc] 

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

Как вернуть структуру из функции c

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

Структура как параметр функции

При передаче структуры в качестве параметра получает копию значений структуры:

#include struct person < char* name; int age; >; void print_person(struct person user) < printf("Name: %s \n", user.name); printf("Age: %d \n", user.age); >int main(void) < struct person tom = ; print_person(tom); return 0; >

В данном случае функция print_person() принимает объект структуры person и выводит значения его элементов на консоль.

Чтобы не писать тип параметра полностью — struct person , можно определить псевдоним структуры:

#include typedef struct < char* name; int age; >person; void print_person(person user) < printf("Name: %s \n", user.name); printf("Age: %d \n", user.age); >int main(void) < person tom = ; print_person(tom); return 0; >

Указатели на структуру как параметры

При использовании структур в качестве параметров в функции следует учитывать, что при вызове функции для структуры, также как и для параметров типа int или char, выделяется память, в которую помещаются значения элементов структуры. То есть структура в функцию передается по значению, а это значит, что переданную в функцию структуру мы изменить не можем.

Если необходимо уменьшить выделение памяти (особенно если структура большая) или иметь возможность изменять изначальную структуру в функции, то можно передавать в функцию указатель на структуру:

#include struct person < char* name; int age; >; void change_person(struct person * user) < user->age = user->age + 1; > int main(void) < struct person bob = ; printf("Before change. %s : %d \n", bob.name, bob.age); change_person(&bob); printf("After change. %s : %d \n", bob.name, bob.age); return 0; >

В этом примере функция change_person принимает указатель на структуру person и увеличивает на единицу значение элемента age.

Для проверки в функции main выводим данные объекта person на консоль до и после вызова функции change_person.

Before change. Bob : 22 After change. Bob : 23

Структура как результат функции

Также функция может возвращать объект структуры:

#include struct person < char* name; int age; >; struct person create_person(char* name, int age) < struct person user; user.name = name; user.age = age; return user; >int main(void)

Здесь функция create_person() создает на основании полученных параметров объект структуры person и возвращает его в качестве результата.

Возврат структуры из функции в C++

Существует легенда, что возврат структуры по значению из функции в C++ — затратная процедура. Сегодня я займусь проверкой этой легенды.

Для этого пишу небольшой тестовый примерчик:

#include #include struct Object < public: int a; int b; int c; char string[50]; >; Object func() < Object o; o.a = 1; o.b = 2; o.c = 3; strcpy(o.string, "Hello world!"); return o; >int main(int argc, char ** argv)

Компилирую его c помощью gcc в моем случае. Тестирую, работает как положено выводит Hello world. Вторым шагом, чтобы проверить к чему приводит такой код, компилирую приведенный тестовый пример в ассемблер. gcc -S -c main.cpp

Что я вижу в ассеблерном коде:

.file "main.cpp" .section .rodata.str1.1,"aMS",@progbits,1 .LC0: .string "Hello world!" .text .p2align 1,0x90 .p2align 2,,3 .globl _Z4funcv .type _Z4funcv, @function _Z4funcv: .LFB3: pushl %ebp .LCFI0: movl %esp, %ebp .LCFI1: movl 8(%ebp), %eax pushl %edi .LCFI2: pushl %esi .LCFI3: cld movl $.LC0, %esi leal 12(%eax), %edi movl $3, %ecx movl $1, (%eax) movl $2, 4(%eax) movl $3, 8(%eax) rep movsl movsb popl %esi popl %edi leave ret $4 .LFE3: .size _Z4funcv, .-_Z4funcv .section .rodata.str1.1 .LC1: .string "%s" .text .p2align 1,0x90 .p2align 2,,3 .globl main .type main, @function main: .LFB4: pushl %ebp .LCFI4: movl %esp, %ebp .LCFI5: subl $72, %esp .LCFI6: andl $-16, %esp leal -72(%ebp), %eax subl $16, %esp pushl %eax .LCFI7: call _Z4funcv subl $8, %esp leal -60(%ebp), %eax pushl %eax pushl $.LC1 .LCFI8: call printf xorl %eax, %eax leave ret .LFE4: .size main, .-main .section .eh_frame,"a",@progbits .Lframe1: .long .LECIE1-.LSCIE1 .LSCIE1: .long 0x0 .byte 0x1 .string "zP" .uleb128 0x1 .sleb128 -4 .byte 0x8 .uleb128 0x5 .byte 0x0 .long __gxx_personality_v0 .byte 0xc .uleb128 0x4 .uleb128 0x4 .byte 0x88 .uleb128 0x1 .p2align 2 .LECIE1: .LSFDE3: .long .LEFDE3-.LASFDE3 .LASFDE3: .long .LASFDE3-.Lframe1 .long .LFB4 .long .LFE4-.LFB4 .uleb128 0x0 .byte 0x4 .long .LCFI4-.LFB4 .byte 0xe .uleb128 0x8 .byte 0x85 .uleb128 0x2 .byte 0x4 .long .LCFI5-.LCFI4 .byte 0xd .uleb128 0x5 .byte 0x4 .long .LCFI7-.LCFI5 .byte 0x2e .uleb128 0x4 .byte 0x4 .long .LCFI8-.LCFI7 .byte 0x2e .uleb128 0x10 .p2align 2 .LEFDE3: .ident "GCC: (GNU) 3.4.6 [FreeBSD] 20060305"

Что отсюда видно. Видно что в функции main() резервируется место в стеке под структуру Object o. А потом, как это не странно ссылка на эту выделенную память передается внутрь функции func(). И функция func не производя никакого выделения памяти самостоятельно, работает с полями структуры, предварительно загрузив адрес структуры в регистр eax.

Т.е. это означает, что никаких накладных расходов данный фрагмент не вызывает! Во первых нет ни одной операцией с «кучей». Всё выделяется в стеке вызывающей функции. Во-вторых адрес выделенной памяти передается скрытой ссылкой или указателем. Это как вам больше нравится. В ассеблере просто передается адрес.

Теперь проверим следующий, закономерный вопрос. А что если функция func сама является членом другого класса. Как компилятор поступит в этом случае. Провожу для этого второй эксперимент, аналогичный первому:

#include #include struct Object < int a; int b; int c; char s[50]; >; class A < int a; public: Object func(); >; Object A::func() < Object o; o.a=1; o.b=2; o.c=3; strcpy(o.s,"Hello world"); a=5; return o; >int main(int argc, char ** argv)

Аналогично, тестирую, затем компилирую в ассемблер:

.file "main1.cpp" .section .rodata .LC0: .string "Hello world" .text .p2align 1,0x90 .p2align 2,,3 .globl _ZN1A4funcEv .type _ZN1A4funcEv, @function _ZN1A4funcEv: .LFB3: pushl %ebp .LCFI0: movl %esp, %ebp .LCFI1: pushl %ebx .LCFI2: subl $4, %esp .LCFI3: movl 8(%ebp), %ebx movl $1, (%ebx) movl $2, 4(%ebx) movl $3, 8(%ebx) subl $8, %esp pushl $.LC0 leal 12(%ebx), %eax pushl %eax .LCFI4: call strcpy addl $16, %esp movl 12(%ebp), %eax movl $5, (%eax) movl %ebx, %eax movl -4(%ebp), %ebx leave ret $4 .LFE3: .size _ZN1A4funcEv, .-_ZN1A4funcEv .section .rodata .LC1: .string "%s" .text .p2align 1,0x90 .p2align 2,,3 .globl main .type main, @function main: .LFB4: pushl %ebp .LCFI5: movl %esp, %ebp .LCFI6: subl $88, %esp .LCFI7: andl $-16, %esp movl $0, %eax addl $15, %eax addl $15, %eax shrl $4, %eax sall $4, %eax subl %eax, %esp leal -88(%ebp), %edx subl $8, %esp leal -12(%ebp), %eax pushl %eax pushl %edx .LCFI8: call _ZN1A4funcEv addl $12, %esp subl $8, %esp leal -88(%ebp), %eax addl $12, %eax pushl %eax pushl $.LC1 call printf addl $16, %esp movl $0, %eax leave ret .LFE4: .size main, .-main .section .eh_frame,"a",@progbits .Lframe1: .long .LECIE1-.LSCIE1 .LSCIE1: .long 0x0 .byte 0x1 .string "zP" .uleb128 0x1 .sleb128 -4 .byte 0x8 .uleb128 0x5 .byte 0x0 .long __gxx_personality_v0 .byte 0xc .uleb128 0x4 .uleb128 0x4 .byte 0x88 .uleb128 0x1 .p2align 2 .LECIE1: .LSFDE1: .long .LEFDE1-.LASFDE1 .LASFDE1: .long .LASFDE1-.Lframe1 .long .LFB3 .long .LFE3-.LFB3 .uleb128 0x0 .byte 0x4 .long .LCFI0-.LFB3 .byte 0xe .uleb128 0x8 .byte 0x85 .uleb128 0x2 .byte 0x4 .long .LCFI1-.LCFI0 .byte 0xd .uleb128 0x5 .byte 0x4 .long .LCFI3-.LCFI1 .byte 0x83 .uleb128 0x3 .byte 0x4 .long .LCFI4-.LCFI3 .byte 0x2e .uleb128 0x10 .p2align 2 .LEFDE1: .LSFDE3: .long .LEFDE3-.LASFDE3 .LASFDE3: .long .LASFDE3-.Lframe1 .long .LFB4 .long .LFE4-.LFB4 .uleb128 0x0 .byte 0x4 .long .LCFI5-.LFB4 .byte 0xe .uleb128 0x8 .byte 0x85 .uleb128 0x2 .byte 0x4 .long .LCFI6-.LCFI5 .byte 0xd .uleb128 0x5 .byte 0x4 .long .LCFI8-.LCFI6 .byte 0x2e .uleb128 0x10 .p2align 2 .LEFDE3: .ident "GCC: (GNU) 3.4.6 [FreeBSD] 20060305"

Этот код показывает, что опять в функцию func() в качестве первого аргумента передается указатель на структуру Object o. Функция в данном случае загружает его адрес в регистр ebx и заполняет поля структуры. Затем загружает в регистр eax второй скрытый параметр, содержащий указатель на экземпляр класса, которому принадлежит функция, т.е. this.

Т.о. вывод при возврате структуры по значению никаких накладных расходов на его выделение не случается. Память выделяется в стеке вызывающей функции. В функцию передается скрытый указатель на выделенную память. В случае, если функция, возвращающая структуру является членом класса, тогда в нее передается не один, а два указателя. Один указатель на выделенную для возвращаемого значения память и второй указатель this (на экземпляр объекта класса, членом которого является функция). Функция по окончании работы в регистре eax возвращает указатель на объект, тот же, что ей передали в скрытом параметре. Это уже лишнее действие по сути. Но присвоение регистра — это не сильно затратная операция.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *