У чому особливість конструкцій?


81

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

Чому structобертання робить наступну програму дійсною?


1
Ви можете зробити те саме з a union. У чому особливість профспілок?
user253751

19
Вам краще запитати, чому масиви настільки дивні в C.
CodesInChaos

при поверненні структури, якщо структура не вписується в пару регістрів, то "прихована" пам'ять, виділена компілятором, структура копіюється (через memcpy ()) у приховану пам'ять, а потім знову копіюється (через memcpy ( )) до структурної змінної викликів. Ця "прихована" пам'ять втрачається для всіх інших функцій. Два додаткові виклики memcpy()та втрата "прихованої" пам'яті є основною причиною того, що структура не повинна бути passed toані returned fromфункцією. Найкраща політика - передати вказівник на структуру.
user3629249

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

1
@ user3629249 - відповісти на запитання неможливо, оскільки питання ґрунтується на нерозумінні. Єдиний спосіб відповісти на запитання - спробувати пояснити, чому не можна задати питання. Уявіть, якби я запитав вас: "Чому блакитний колір має такий самий колір, як червоний?" Ви швидко пояснили б, чому не можете відповісти на запитання.
Хоган

Відповіді:


100

Кращим способом задати те саме питання буде "що особливого в масивах", адже саме до масивів прикріплена спеціальна обробка, а не structs.

Поведінка передавання та повернення масивів за допомогою покажчика веде свій початок від початкової реалізації 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 - це не набагато більше, ніж збірка, якщо ви вважаєте, що ніколи не існує причин не використовувати вказівник, я, можливо, бачу, як ви можете подумати, що передавати структури марно. Але для решти з нас, хто розглядає С як мову високого рівня (хоч і низькорівневу, як HLL), і хто ставиться до системи типу С як загальну (за винятком винятків статусу масивів другого класу) ), чому б нам не хотіти передавати або повертати структури? (BTW, IIRC, K & R1 сказали, що передача структури вже була в дорозі, і вона працювала у V7 cc на момент виходу книги).
Самміт Стіва,

38

Перш за все, процитувати C11, розділ §6.8.6.4, returnтвердження, ( курсив мій )

Якщо returnвиконується оператор із виразом, значення виразу повертається абоненту як значення виразу виклику функції.

Повернення змінної структури можливо (і правильне), оскільки повертається значення структури . Це схоже на повернення будь-якого примітивного типу даних (повернення int, наприклад).

З іншого боку, якщо ви повертаєте масив , використовуючи return <array_name>, він, по суті, повертає адресу першого елемента масиву ПРИМІТКА , який стає недійсним у абонента, якщо масив був локальним для викликаних функцій. Отже, повернення масиву таким чином неможливе.

Отже, TL; DR , з s немає нічого особливогоstruct , спеціальність - у масивах .


ПРИМІТКА:

C11Знову цитуючи , глава §6.3.2.1, ( мій акцент )

За винятком випадків, коли це операнд sizeofоператора, _Alignofоператора або унарного& оператора, або є рядковим літералом, що використовується для ініціалізації масиву, вираз, що має тип '' масив типу '' , перетворюється у вираз із типом '' вказівник на тип '', який вказує на початковий елемент об'єкта масиву і не є значенням l. [...]


що саме OTOH ?!

1
@Sukl Це абревіатура для "з іншого боку" :)
Sourav Ghosh

1
@Sukl Я думаю, що ці скорочення приблизно такі ж старі, як і сам Інтернет. Їх, безсумнівно, багато використовували під час днів слави Usenet, і вони все ще виживають на більшості форумів. На щастя, навіть для тих, хто не обізнаний, Google може їх розшифрувати ;-) І є лише кілька, які часто використовуються сьогодні (найпоширеніші)
чи

@chi так. Google досить чудово здатний їх розшифрувати.

1
@Sukl: Ви можете знайти AcronymFinder корисним для відстеження скорочень.
Джонатан Леффлер

11

У structтипах немає нічого особливого ; це те, що в типах масивів є щось особливе, що заважає їм повертатися безпосередньо з функції.

structВираз розглядається як вираження будь-якого іншого типу без масиву; він оцінює на значення з struct. Тож ви можете робити такі речі

Вираз someFooобчислюється в вартості зstruct foo об'єкта; вміст об’єкта повертається із функції (навіть якщо цей вміст містить масиви).

Вираз масиву трактується по-різному; якщо це не операнд операторів or sizeofабо одинарних &операторів, або якщо це не строковий літерал, який використовується для ініціалізації іншого масиву в оголошенні, вираз перетворюється ("розпадається") з типу "масив T" на "вказівник" наT " , а значення виразу - це адреса першого елемента.

Отже, ви не можете повернути масив за значенням від функції, оскільки будь-яке посилання на вираз масиву автоматично перетворюється на значення покажчика.


-5

Структури за замовчуванням мають загальнодоступні члени даних, тому у випадку структури можна отримати доступ до даних у main, але не у випадку класу. Отже, обгортання структури є дійсним.


1
Ви бачили, що питання стосується С? У C немає public/ privateвідмінності, і немає classES. Питання в тому, навіщо а structпотрібне в C, щоб повернути значення масиву.
PJTraill
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.