Назначить одну структуру другой в C - PullRequest
131 голосов
/ 20 февраля 2010

Можете ли вы назначить один экземпляр структуры другому, например:

struct Test t1;
struct Test t2;
t2 = t1;

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

Ответы [ 5 ]

134 голосов
/ 20 февраля 2010

Да, если структура того же типа. Думайте об этом как о копии памяти.

124 голосов
/ 20 февраля 2010

Да, назначение поддерживается для структур. Однако есть проблемы:

struct S {
   char * p;
};

struct S s1, s2;
s1.p = malloc(100);
s2 = s1;

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

23 голосов
/ 30 января 2013

Первый взгляд на этот пример:

Код C для простой программы на C приведен ниже

struct Foo {
    char a;
    int b;
    double c;
    } foo1,foo2;

void foo_assign(void)
{
    foo1 = foo2;
}
int main(/*char *argv[],int argc*/)
{
    foo_assign();
return 0;
}

Эквивалентный код ASM для foo_assign ():

00401050 <_foo_assign>:
  401050:   55                      push   %ebp
  401051:   89 e5                   mov    %esp,%ebp
  401053:   a1 20 20 40 00          mov    0x402020,%eax
  401058:   a3 30 20 40 00          mov    %eax,0x402030
  40105d:   a1 24 20 40 00          mov    0x402024,%eax
  401062:   a3 34 20 40 00          mov    %eax,0x402034
  401067:   a1 28 20 40 00          mov    0x402028,%eax
  40106c:   a3 38 20 40 00          mov    %eax,0x402038
  401071:   a1 2c 20 40 00          mov    0x40202c,%eax
  401076:   a3 3c 20 40 00          mov    %eax,0x40203c
  40107b:   5d                      pop    %ebp
  40107c:   c3                      ret    

Как вы можете видеть, что назначение просто заменяется инструкцией "mov" в сборке, оператор присваивания просто означает перемещение данных из одной ячейки памяти в другую ячейку памяти. Назначение будет делать это только для непосредственных членов структур и не сможет скопировать, когда у вас есть сложные типы данных в структуре. Здесь COMPLEX означает, что вы не можете иметь массив указателей, указывающих на списки.

Массив символов в структуре сам по себе не будет работать на большинстве компиляторов, потому что присваивание просто попытается скопировать, даже не глядя на тип данных сложного типа.

15 голосов
/ 20 февраля 2010

Это простая копия, точно так же, как вы делали бы с memcpy() (действительно, некоторые компиляторы фактически вызывают для этого кода memcpy()). В Си нет «строки», только указатели на кучу символов. Если ваша исходная структура содержит такой указатель, то копируется указатель, а не сами символы.

6 голосов
/ 20 февраля 2010

Вы имели в виду «Комплекс», как в комплексном числе с действительными и мнимыми частями? Это кажется маловероятным, поэтому в противном случае вам не придется приводить пример, поскольку «сложный» не означает ничего конкретного с точки зрения языка Си.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...