Что особенного в структурах?

81

Я знаю, что в C мы не можем вернуть массив из функции, а только указатель на массив. Но я хочу знать, в чем особенность, structsкоторая делает их возвращаемыми функциями, даже если они могут содержать массивы.

Почему structупаковка делает действующей следующую программу?

Сурав Гош
источник
1
Вы можете сделать то же самое с файлом union. Что особенного в союзах?
user253751
19
Вам лучше спросить, почему массивы такие странные в C.
CodesInChaos
при возврате структуры, если структура не помещается в пару регистров, тогда «скрытая» память, выделенная компилятором, структура копируется (через memcpy ()) в скрытую память, а затем снова копируется (через memcpy ( )) к структурной переменной вызывающего объекта. Эта «скрытая» память теряется для всех других функций. Два дополнительные вызовы к memcpy()и потеря «скрытая» памяти является основной причиной того, что структура не должна быть passed toни returned fromфункцией. Лучшая политика - передать указатель на структуру.
user3629249
ни один из трех ответов не касается передачи структуры (скорее, они обсуждают только передаваемые массивы), но они не отвечают на вопрос.
user3629249
1
@ user3629249 - невозможно ответить на вопрос, потому что вопрос основан на непонимании. Единственный способ ответить на вопрос - это попытаться объяснить, почему вопрос нельзя задать. Представьте, если бы я спросил вас: «Почему синий такой же цвет, как и красный?» Вы быстро объясните, почему не можете ответить на вопрос.
Хоган

Ответы:

100

Лучше задать тот же вопрос: «Что особенного в массивах?», Поскольку особая обработка связана с массивами, а не с массивами struct.

Поведение передачи и возврата массивов с помощью указателя восходит к исходной реализации C. Массивы «распадаются» на указатели, вызывая большую путаницу, особенно среди людей, плохо знакомых с языком. Структуры, с другой стороны, ведут себя так же, как встроенные типы, такие как ints, doubles и т. Д. Сюда входят любые массивы, встроенные в struct, за исключением гибких элементов массива , которые не копируются.

Сергей Калиниченко
источник
4
действительно "вызывая большую путаницу". 'x' и '& x' - одно и то же значение / адрес - это безумие. Неудивительно, что новички ошибаются в косвенном обращении :(
Мартин Джеймс
1
Моя память могла меня обмануть, но разве не было случаев, когда передача structs по значению была невозможной?
alk
5
@alk Я думаю, когда структуры были впервые добавлены в язык, изначально были некоторые ограничения на их передачу / возврат из функций, но они были четко обозначены как недостаток в компиляторе, который был достаточно скоро исправлен, а не признак что было что-то плохое в желании сдать и вернуть их.
Стив Саммит,
8
@jamesqf: struct Point {short x, y, z;};. Вы действительно хотите использовать указатели для их перемещения? Вы точно не экономите место таким образом.
Mark VY
6
@jamesqf Я не уверен, что это заслуживает ответа. Если вы считаете, что C - это не что иное, как сборка, если вы считаете, что никогда не бывает причин не использовать указатель, я могу понять, как вы могли подумать, что передача структур бесполезна. Но для остальных из нас, кто рассматривает C как язык высокого уровня (хотя и низкоуровневый, как в случае с HLL), и кто рассматривает систему типов C как общую (с отмеченным исключением второго класса статуса массивов ), почему бы нам не передавать или возвращать структуры? (Между прочим, IIRC, K & R1 сказали, что передача структуры уже на подходе, и она работала в V7 cc к моменту выхода книги.)
Стив Саммит,
38

Прежде всего, процитируем C11главу §6.8.6.4, returnутверждение ( выделено мной )

Если выполняется returnинструкция с выражением, значение выражения возвращается вызывающей стороне как значение выражения вызова функции.

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

С другой стороны, если вы возвращаете массив с помощью return <array_name>, он по существу возвращает адрес первого элемента массива ПРИМЕЧАНИЕ. , который становится недействительным для вызывающей стороны, если массив был локальным для вызываемых функций. Таким образом, возврат массива таким способом невозможен.

Так, TL; DR , нет ничего особенного с structс, специальность в массивах .


ЗАМЕТКА:

C11Снова цитируя главу §6.3.2.1 ( выделено мной )

За исключением случаев, когда это операнд sizeofоператора, _Alignofоператора или унарного &оператора, или строковый литерал, используемый для инициализации массива, выражение, имеющее тип "массив типа", преобразуется в выражение с типом " указатель на тип '', который указывает на начальный элемент объекта массива и не является lvalue. [...]

Сурав Гош
источник
что именно такое OTOH ?!
1
@Sukl Это сокращение от «с другой стороны» :)
Сурав Гош,
1
@Sukl Я думаю, что эти сокращения примерно так же стары, как сам Интернет. Они наверняка много использовались во времена славы Usenet и до сих пор сохраняются на большинстве форумов. К счастью, даже для тех, кто не знает, Google может их расшифровать ;-) И есть лишь несколько, которые сегодня часто используются (самые распространенные)
chi
@chi, да, Google отлично умеет их расшифровывать.
1
@Sukl: Вы могли бы найти AcronymFinder полезным для отслеживания аббревиатуры.
Джонатан Леффлер
11

В structтипах нет ничего особенного ; дело в том, что в типах массивов есть что-то особенное, что не позволяет им напрямую возвращаться из функции.

structВыражение рассматривается как выражение любого другого типа без массива; он оценивает на значение из struct. Итак, вы можете делать такие вещи, как

Выражение someFooвычисляется в значение этого struct fooобъекта; содержимое объекта возвращается из функции (даже если это содержимое содержит массивы).

Выражение массива трактуется иначе; если это не операнд sizeofунарных &операторов или, или если это не строковый литерал, используемый для инициализации другого массива в объявлении, выражение преобразуется («распадается») из типа «массив T» в «указатель на T» , а значение выражения - это адрес первого элемента.

Таким образом, вы не можете вернуть массив по значению из функции, потому что любая ссылка на выражение массива автоматически преобразуется в значение указателя.

Джон Боде
источник
-5

По умолчанию структуры имеют открытые члены данных, поэтому в случае структуры можно получить доступ к данным в основном, но не в случае класса. Итак, обертка структуры действительна.

хо
источник
1
Вы видели, что речь идет о C? В C нет public/ privateразличий и нет classes. Вопрос в том, зачем structнужен C для возврата значения массива.
PJTraill