Co jest specjalnego w strukturach?

81

Wiem, że w C nie możemy zwrócić tablicy z funkcji, ale wskaźnik do tablicy. Ale chcę wiedzieć, na czym polega szczególna cecha structstego, że są one zwracane przez funkcje, nawet jeśli mogą zawierać tablice.

Dlaczego structopakowanie sprawia, że ​​następujący program jest ważny?

Sourav Ghosh
źródło
1
Możesz zrobić to samo z plikiem union. Co jest specjalnego w związkach zawodowych?
user253751
19
Powinieneś raczej zapytać, dlaczego tablice są tak dziwne w C.
CodesInChaos
przy zwracaniu struktury, jeśli struktura nie zmieści się w kilku rejestrach, a następnie "ukryta" pamięć przydzielona przez kompilator, struktura jest kopiowana (przez memcpy ()) do pamięci ukrytej, a następnie ponownie kopiowana (przez memcpy ( )) do zmiennej strukturalnej wywołujących. Wszystkie inne funkcje tracą tę „ukrytą” pamięć. Dwa dodatkowe wywołania memcpy()i utrata „ukrytej” pamięci są głównym powodem, dla którego struktura nie powinna być passed toani returned fromfunkcją. Najlepszą zasadą jest przekazanie wskaźnika do struktury.
user3629249
żadna z trzech odpowiedzi nie odnosi się do przekazywania struktury (raczej omawiają one tylko przekazywane tablice), ale nie odpowiadają na pytanie.
user3629249
1
@ user3629249 - nie można odpowiedzieć na pytanie, ponieważ pytanie jest oparte na braku zrozumienia. Jedynym sposobem odpowiedzi na to pytanie jest próba wyjaśnienia, dlaczego nie można zadać pytania. Wyobraź sobie, że zapytałem cię „Dlaczego niebieski ma ten sam kolor co czerwony?” Szybko wyjaśnisz, dlaczego nie możesz odpowiedzieć na pytanie.
Hogan

Odpowiedzi:

100

Lepszym sposobem zadania tego samego pytania byłoby „co jest specjalnego w tablicach”, ponieważ to tablice mają dołączoną specjalną obsługę, structa nie s.

Zachowanie przekazywania i zwracania tablic przez wskaźnik prowadzi do pierwotnej implementacji C. Tablice „rozpadają się” na wskaźniki, powodując spore zamieszanie, zwłaszcza wśród osób nieznających języka. Z drugiej strony struktury zachowują się tak samo, jak typy wbudowane, takie jak ints, doubles itp. Obejmuje to wszelkie tablice osadzone w elemencie, z structwyjątkiem elastycznych elementów tablicy , które nie są kopiowane.

Sergey Kalinichenko
źródło
4
„powodując duże zamieszanie”. „x” i „& x” będące tą samą wartością / adresem są po prostu szalone. Nic dziwnego, że newbowie źle rozumieją kierunek :(
Martin James
1
Moja pamięć może mnie oszukiwać, ale czy nie zdarzały się sytuacje, w których przekazywanie structwartości przez wartość nie było możliwe?
alk
5
@alk Myślę, że kiedy struktury zostały po raz pierwszy dodane do języka, początkowo istniały pewne ograniczenia dotyczące przekazywania ich do / zwracania ich z funkcji, ale zostały one wyraźnie oznaczone jako niedociągnięcie w kompilatorze, które wkrótce zostało poprawione, a nie wskazanie że było coś złego w chęci przejścia i zwrócenia ich.
Steve Summit
8
@jamesqf: struct Point {short x, y, z;};. Naprawdę chcesz używać wskaźników, aby je przesuwać? Z pewnością nie oszczędzasz w ten sposób miejsca.
Mark VY
6
@jamesqf Nie jestem pewien, czy to zasługuje na odpowiedź. Jeśli uważasz, że C to niewiele więcej niż asemblacja, jeśli uważasz, że nigdy nie ma powodu, aby nie używać wskaźnika, być może mogę zobaczyć, jak możesz pomyśleć, że przekazywanie struktur jest bezużyteczne. Ale dla reszty z nas, którzy traktują C jako język wysokiego poziomu (aczkolwiek jako język niskiego poziomu, jak robią to HLL) i traktują system typów C jako ogólny (z odnotowanym wyjątkiem statusu tablicy drugiej ), dlaczego nie chcielibyśmy przekazywać lub zwracać struktur? (BTW, IIRC, K & R1 powiedzieli, że przekazywanie struktur było w drodze i działało w V7 cc do czasu ukazania się książki.)
Steve Summit
38

Przede wszystkim, aby zacytować C11, rozdział §6.8.6.4, returnoświadczenie, ( moje wyróżnienie )

Jeśli wykonywana jest returninstrukcja z wyrażeniem, wartość wyrażenia jest zwracana wywołującemu jako wartość wyrażenia wywołania funkcji.

Zwracanie zmiennej strukturalnej jest możliwe (i poprawne), ponieważ zwracana jest wartość struktury . Jest to podobne do zwracania dowolnego pierwotnego typu danych ( intna przykład zwracania ).

Z drugiej strony, jeśli zwrócisz tablicę , używając funkcji return <array_name>, zwróci ona zasadniczo adres pierwszego elementu tablicy UWAGA , który staje się nieprawidłowy w funkcji wywołującej, jeśli tablica była lokalna dla wywoływanych funkcji. Zatem zwrócenie tablicy w ten sposób nie jest możliwe.

Tak więc, TL; DR , nie ma nic specjalnego w structs, specjalnością są tablice .


UWAGA:

Cytując C11ponownie, rozdział §6.3.2.1, (wyróżnienie moje )

Z wyjątkiem sytuacji, gdy jest to operand sizeofoperatora, _Alignofoperator lub &operator jednoargumentowy lub literał łańcuchowy używany do inicjalizacji tablicy, wyrażenie typu „tablica typu” jest konwertowane na wyrażenie o typie „” wskaźnik do typu „”, który wskazuje na początkowy element obiektu tablicy i nie jest wartością l. […]

Sourav Ghosh
źródło
czym właściwie jest OTOH ?!
1
@Sukl To skrót od „z drugiej strony” :)
Sourav Ghosh
1
@Sukl Myślę, że te skróty są mniej więcej tak stare, jak sam Internet. Z pewnością były często używane w czasach świetności Usenetu i nadal przetrwały na większości forów. Na szczęście nawet dla nieświadomych Google może je zdekodować ;-) I jest tylko kilka, które są dziś często używane (najczęściej)
chi
@chi tak, Google jest genialny i potrafi je zdekodować.
1
@Sukl: AcronymFinder może być przydatny do śledzenia akronimów.
Jonathan Leffler
11

Nie ma nic specjalnego w structtypach; chodzi o to, że jest coś szczególnego w typach tablicowych, które uniemożliwiają zwracanie ich bezpośrednio z funkcji.

structEkspresja jest traktowany jak ekspresja dowolnego innego rodzaju niż tablica; ocenia do wartości z struct. Możesz więc robić takie rzeczy jak

Wyrażenie someFooocenia do wartości w struct fooobiekcie; zawartość obiektu jest zwracana przez funkcję (nawet jeśli ta zawartość zawiera tablice).

Wyrażenie tablicowe jest traktowane inaczej; jeśli nie jest operandem operatorów sizeofjednoargumentowych &lub lub jeśli nie jest to literał łańcuchowy używany do inicjalizacji innej tablicy w deklaracji, wyrażenie jest konwertowane („rozpada się”) z typu „tablica T” na „wskaźnik do T” , a wartością wyrażenia jest adres pierwszego elementu.

Dlatego nie można zwrócić tablicy według wartości z funkcji, ponieważ każde odwołanie do wyrażenia tablicowego jest automatycznie konwertowane na wartość wskaźnika.

John Bode
źródło
-5

Struktury mają domyślnie publiczne elementy składowe danych, więc w przypadku struct możliwe jest uzyskanie dostępu do danych w main, ale nie w przypadku klasy. Tak więc zawijanie struktury jest prawidłowe.

hoh
źródło
1
Czy widziałeś, że pytanie dotyczy C? W C nie ma rozróżnienia public/ privatei nie ma classes. Pytanie dotyczy tego, dlaczego a structjest potrzebne w C, aby zwrócić wartość tablicy.
PJTraill