2013-04-18 3 views
5

Если я следующее: -Переходя на структуру к функции в C

struct foo 
{ 
    int a; 
    int *b; 
} bar; 

void baz(struct foo qux) 
{ 

} 

Правильно ли я думать, что переход bar к baz() результатов в локальной копии bar быть в стек? Если да, то какая копия? в C++ я предполагаю, что он будет вызывать конструктор копирования или конструктор копии по умолчанию, но я действительно не знаю, как это будет работать в C.

Имеет ли C понятие конструктора копии по умолчанию и имеет ли он имя? Можно ли что-то сделать, чтобы выполнить глубокую копию? (Гипотетически). Единственный способ, о котором я мог думать, - это сделать глубокую копию, а затем передать ее функции.

Как правило, я бы передавал указатель на foo, но мне просто интересно, как он работает. Кроме того, у меня создается впечатление, что передача указателя происходит быстрее, экономит память и является рекомендуемым курсом действий при выполнении такого рода операций. Я бы предположил, что это мелкая копия; можно ли это изменить?

ответ

4

Я правильно понял, что прохождение бара к baz() приводит к тому, что локальная копия бара выталкивается в стек?

Да.

Я не знаю, как это будет работать в С.

По существу, как это было бы с конструктором копирования по умолчанию в C++; каждое поле копии инициализируется соответствующим полем оригинала. Конечно, из-за правила «как будто» все это может сводиться к memcpy.

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

Для больших struct s это часто бывает, но это не всегда так; если у вас есть небольшое число struct из нескольких небольших полей, накладные расходы на копирование, вероятно, будут меньше, чем косвенные (также, используя параметры указателя, может быть дорогостоящим, поскольку правила псевдонимов C и C++ могут предотвратить некоторые оптимизации).

Я бы предположил, что это мелкая копия; можно ли это изменить?

Нет, неполную копию (слепо копировать каждое поле) является то, что происходит с конструктором копирования по умолчанию (в то время как с «глубокой копией» вы обычно имеют в виду также создает копию каждого объекта, указанного в указатель/ссылочных полей).

Что вы имеете в виду «передать по ссылке», и это не по умолчанию, чтобы обеспечить максимальную гибкость (и для согласованности с прохождением примитивных типов). Если вы хотите пройти по ссылке, вы передаете указатель (или ссылку на C++), часто const, если вы находитесь только для производительности, иначе вы передаете сам объект.

+0

p.s. в C нет никаких конструкторов; только в C++. В C ваша структура данных просто будет скопирована byte-for-byte. –

+0

@EdwardFalk: конечно, в фактах я говорил о * инициализации *, а не о конструкции; Кроме того, стандарт «byte for for byte» не указан стандартом, который фактически говорит, что гарантируется копирование только названных полей («Элементы-члены« Без названия »имеют неопределенное значение даже после инициализации.), C99 §6.7 .8 ¶9) - то есть заполнение может копироваться или не копироваться. –

+0

Отличное объяснение, я предполагаю, что вы не можете переопределить поведение по умолчанию для выполнения глубокой копии, если это необходимо? – chrisw

1

Да, локальная копия бара помещается в стек. и отдых прокомментирован в следующем рабочем примере.

#include <stdio.h> 
    struct foo 
    { 
     int a; 
     int *b; 
    } bar; 
    void baz(struct foo qux) 
    { 
     bar.a = 2; // if its a different copy then printf on main should print 1 not 2. 
     *bar.b = 5; // if its a different copy then printf on main should print 5 not 4. since the place pointer pointing to is same 
    } 
    int main(){ 
     bar.a=1; 
     bar.b = (int*)malloc(sizeof(int)); 
     *bar.b = 4; 
     baz(bar); // pass it to baz(). now the copy of bar in the stack which is what baz going to use 
     printf("a:%d | b:%d\n",bar.a,*bar.b); 
     //answer is 2 and 5 
     /*So indeed it does a shallow copy thats why we lost the "4" stored in bar.b it did not created new space in heap to store "5" instead it used the same space that b was pointing to. 
     */ 
    return 0; 
    } 
Смежные вопросы