2017-02-17 7 views
2

Я пытаюсь напечатать переменные-члены структуры двумя различными функциями: save_struct_model_1 и save_struct_model_2. Оба, похоже, работают нормально и печатают правильные значения. Какой из этих двух правильных и предпочтительных.Структурные указатели в C

#include <stdio.h> 
#include <stdlib.h> 

struct model{ 
    char *name; 
    int year; 
}; 

void save_struct_model_1(struct model *s){ 
     printf("%s ", s->name); 
     printf("%d \n",s->year); 
} 

void save_struct_model_2(struct model s){ 
     printf("%s ", s.name); 
     printf("%d \n",s.year); 
} 

int main() 
{ 

typedef struct model M; 

M * honda = (M *) malloc (sizeof(M)); 
honda->name="civic"; 
honda->year=2000; 

save_struct_model_1(honda); 
save_struct_model_2(*honda);  

return 0; 
} 
+3

второй копирует временное значение из '* honda' и не может изменить первоначальную-структуру. –

+0

Спасибо @BlagovestBuyukliev, – marc

+3

'model_1' почти всегда предпочтительнее. Если вы только печатаете, используйте 'void save_struct_model_1 (const struct model * s);' Рассмотрим общий случай, где мы имеем: 'struct model {int x [1000000000]; }; 'Затем мы будем выталкивать 4GB + в стек. Это взорвало бы стек, не говоря уже о штрафе за исполнение при каждом вызове. Вот почему выполняется передача указателя struct. В 35 лет, когда я занимался C, мне никогда не приходилось использовать модель 2 –

ответ

3

Это, главным образом, субъективно. Но я бы сказал, что версия указателя (с использованием save_struct_model_1()) лучше, потому что она позволяет избежать копирования значения структуры.

Это может не иметь заметного влияния на ваш код - но представьте, есть ли структура, состоящая из 100 членов, и вы хотите распечатать их все.

+0

. Получил ее, поэтому задан вариант передачи по ссылке или по значению, предпочтительным является передача по ссылке. – marc

+1

@ kris: C - это язык, основанный только на значении. В первом варианте копируется только указатель, а во втором варианте вы копируете всю структуру. –

+2

Прежде всего, в C нет «прохода по ссылке»; все передается по значению. Только то, что прошло (по значению), отличается. В основном да, передача указателя лучше, потому что структурная копия может быть потенциально дорогостоящей. С другой стороны, использование 'save_struct_model_2()' 'honda' у вызывающего не может быть изменено - что может или не может того, что вы хотите. Как правило, я бы сказал, используйте версию указателя *, если у вас нет веской причины не для *. – usr

0

В функции save_struct_model_1 вся структура передается другой функции по адресу. Это означает, что только адрес структуры передается другой функции. Вся структура не передается другой функции со всеми членами и их значениями. Таким образом, эту структуру можно получить из вызываемой функции по ее адресу.

В функции save_struct_model_2 вся структура передается другой функции по значению. Это означает, что вся структура передается другой функции со всеми членами и их значениями. Таким образом, эту структуру можно получить из вызываемой функции. Эта концепция очень полезна при написании очень больших программ на C.

-1

Я думаю, что я хотел бы сделать это:

int //to singnal errors in printf 
save_struct_model_3(struct model const *s){ 
     //const to guarantee immutability 
     int r = 0; 
     r |= 0>printf("%s ", s->name); 
     r |= 0>printf("%d \n",s->year); 
     return -r; 
} 

Разницей между проходящими по структурам константного указателя и мимолетных структуры по значению является то, что последним немного быстрее для очень крошечных структур (меньше косвенных), тогда как первая быстрее для всех других структур (без копирования).

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

Вот мои результаты сравнительного анализа:

n_ints val/ns ptr/ns 
1 4.552 5.544 
2 4.748 5.336 
3 4.712 5.572 
4 5.556 5.460 << 
5 6.180 4.436 
6 5.252 5.424 
7 5.620 4.100 
8 4.316 4.164 
9 5.612 4.220 
10 6.656 4.656 
11 6.148 4.472 
12 6.708 4.708 
13 6.192 5.200 
14 8.560 4.652 
15 7.392 4.620 
16 8.512 4.728 
17 8.244 5.488 
18 10.108 5.360 
19 8.540 4.740 
20 10.028 5.468