Сегодня я учил пару друзей, как использовать C struct
s. Один из них спросил, можете ли вы вернуть a struct
из функции, на что я ответил: «Нет! Вместо этого вы бы возвращали указатели для динамически malloc
создаваемых struct
s».
Исходя из того, кто в основном работает на C ++, я ожидал, что не смогу вернуть struct
s по значениям. В C ++ вы можете перегружать operator =
свои объекты и имеет полный смысл иметь функцию, которая возвращает ваш объект по значению. В C, однако, у вас нет такой опции, и поэтому я подумал, что на самом деле делает компилятор. Учтите следующее:
struct MyObj{
double x, y;
};
struct MyObj foo(){
struct MyObj a;
a.x = 10;
a.y = 10;
return a;
}
int main () {
struct MyObj a;
a = foo(); // This DOES work
struct b = a; // This does not work
return 0;
}
Я понимаю, почему struct b = a;
не должно работать - вы не можете перегрузить operator =
для вашего типа данных. Как это хорошо, что a = foo();
компилируется? Это означает что-то кроме struct b = a;
? Может быть, вопрос, который нужно задать, состоит в следующем: что именно делает return
заявление в сочетании со =
знаком?
[править]: Хорошо, я только что указал struct b = a
на синтаксическую ошибку - это правильно, и я идиот! Но это делает это еще более сложным! Использование struct MyObj b = a
действительно работает! Что мне здесь не хватает?
struct b = a;
это синтаксическая ошибка Что если ты попробуешьstruct MyObj b = a;
?struct MyObj b = a;
кажется, работает :)Ответы:
Вы можете вернуть структуру из функции (или использовать
=
оператор) без каких-либо проблем. Это четко определенная часть языка. Единственная проблема вstruct b = a
том, что вы не указали полный тип.struct MyObj b = a
будет работать просто отлично. Вы также можете передавать структуры в функции - структура точно такая же, как и любой встроенный тип для целей передачи параметров, возвращаемых значений и назначения.Вот простая демонстрационная программа, которая выполняет все три операции - передает структуру в качестве параметра, возвращает структуру из функции и использует структуры в операторах присваивания:
Следующий пример почти такой же, но использует встроенный
int
тип для демонстрационных целей. Две программы имеют одинаковое поведение в отношении передачи по значению для передачи параметров, назначения и т. Д .:источник
При выполнении вызова, такого как
a = foo();
, компилятор может поместить адрес структуры результата в стек и передать его как «скрытый» указатель наfoo()
функцию. По сути, это может стать что-то вроде:Однако точная реализация этого зависит от компилятора и / или платформы. Как отмечает Карл Норум, если структура достаточно мала, она может быть полностью передана обратно в регистр.
источник
foo
кадра стека. Это должно быть в месте, которое выживает после возвращенияfoo
.foo
. Внутри функцииfoo
вы просто выполняете задание*r = a
конце (эффективно) будет скопирована локальная переменная в переменную вызывающего. Я говорю «эффективно», потому что компилятор может реализовать RVO и полностью исключить локальную переменнуюa
.c return struct
: они знают, что в cdecleax
возвращается значение и что структуры вообще не вписываются внутрьeax
. Это то, что я искал.struct b
Линия не работает , потому что это ошибка синтаксиса. Если вы расширите его, включив тип, он будет работать нормальноТо, что делает здесь C, по сути является структурой
memcpy
от источника до места назначения. Это верно как для присваивания, так и для возвратаstruct
значений (и действительно для любого другого значения в C)источник
memcpy
в этом случае - по крайней мере, если структура достаточно велика.memcpy
функцию структурных ситуаций. Например, вы можете создать программу быстрого тестирования и посмотреть, как это делает GCC. Для встроенных типов этого не произойдет - они недостаточно велики для запуска такого рода оптимизации.memcpy
символ не определен, поэтому мы часто сталкиваемся с ошибками компоновщика «неопределенный символ», когда компилятор решает выпустить его самостоятельно.да, возможно, мы можем передать структуру и вернуть структуру. Вы были правы, но на самом деле вы не передали тип данных, который должен быть таким, как эта структура MyObj b = a.
На самом деле, я также узнал, когда пытался найти лучшее решение для возврата более одного значения функции без использования указателя или глобальной переменной.
Теперь ниже приведен пример для того же, который рассчитывает отклонение оценок ученика от среднего.
источник
Насколько я помню, первые версии C позволяли возвращать только те значения, которые могли бы поместиться в регистр процессора, что означает, что вы могли возвращать только указатель на структуру. То же ограничение применяется к аргументам функции.
Более поздние версии позволяют передавать большие объекты данных, такие как структуры. Я думаю, что эта функция была распространена уже в восьмидесятых или начале девяностых.
Массивы, однако, все еще могут быть переданы и возвращены только как указатели.
источник
Вы можете назначить структуры в C.
a = b;
допустимый синтаксис.Вы просто удалили часть типа - тег struct - в своей строке, которая не работает.
источник
Нет проблем при передаче структуры. Будет передано по значению
Но что, если структура содержит какой-либо член, который имеет адрес локальной переменной
Теперь здесь e1.name содержит адрес памяти, локальный для функции get (). Как только get () вернет, локальный адрес для имени будет освобожден. Итак, в вызывающей стороне, если мы пытаемся получить доступ к этому адресу, это может вызвать ошибку сегментации, так как мы пытаемся освободить адрес. Это плохо..
Где e1.id будет совершенно действительным, так как его значение будет скопировано в e2.id
Таким образом, мы всегда должны стараться не возвращать адреса локальной памяти функции.
Все, что может быть доставлено, может быть возвращено как и когда угодно
источник
прекрасно работает с новыми версиями компиляторов. Как и идентификатор, содержимое имени копируется в назначенную структурную переменную.
источник
Адрес struct var e2 помещается как arg в стек вызываемого абонента, и там присваиваются значения. Фактически, get () возвращает адрес e2 в регистре eax. Это работает как звонок по ссылке.
источник