2016-04-26 6 views
81

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

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

#include <stdio.h> 

struct data { 
    char buf[256]; 
}; 

struct data Foo(const char *buf); 

int main(void) 
{ 
    struct data obj; 
    obj = Foo("This is a sentence."); 
    printf("%s\n", obj.buf); 
    return 0; 
} 

struct data Foo(const char *buf) 
{ 
    struct data X; 
    strcpy(X.buf, buf); 
    return X; 
} 
+1

Вы можете сделать то же самое с «union». Что особенного в профсоюзах? – immibis

+19

Вы должны спросить, почему массивы настолько странны в C. – CodesInChaos

+0

при возврате структуры, если структура не вписывается в пару регистров, а затем «скрытую» память, выделенную компилятором, структура копируется (через memcpy()) в скрытую память, а затем снова скопировали (через memcpy()) tot, которая является переменной struct. Эта «скрытая» память теряется для всех других функций. Два дополнительных вызова 'memcpy()' и потеря «скрытой» памяти являются основной причиной того, что структура не должна быть «передана» или «возвращена из» функции. Лучшая политика - передать указатель на структуру. – user3629249

ответ

100

Лучший способ задавать тот же вопрос будет «что особенного массивов», поскольку это массивы, которые имеют специальное обращение привязываться к ним, не struct с.

Поведение передающих и возвращаемых массивов по указателю возвращает к исходной реализации C. Массивы «распадаются» на указатели, что вызывает много путаницы, особенно среди людей, новых для этого языка.С другой стороны, структуры строятся так же, как и встроенные типы, такие как int s, double и т. Д. Сюда входят любые массивы, встроенные в struct, за исключением flexible array members, которые не копируются.

+3

«действительно вызывает много путаницы». 'x' и '& x', являющиеся одним и тем же значением/адресом, являются безумными. Это неудивительно, что newbs получают косвенную ошибку :( –

+1

Мое воспоминание может обманывать меня, но не было ли времени, когда передача 'struct' по значению была невозможна? – alk

+5

@alk Я думаю, когда структуры сначала добавлялись к на языке были изначально некоторые ограничения на их передачу/возврат их из функций, но они были четко обозначены как недостаток в компиляторе, который вскоре был исправлен, а не указание на то, что что-то не так с желанием пройти и вернуться –

38

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

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

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

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

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


Примечание:

Цитирование C11 снова, глава §6.3.2.1 (курсив мой)

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

+0

Что такое OTOH?! –

+1

@Sukl Это аббревиатура от «с другой стороны» :) –

+1

@Sukl Я думаю, что эти сокращения примерно такие же старые, как и сам Интернет. Они, безусловно, много использовались во времена славы в Usenet и все еще выживают на большинстве форумов. К счастью, даже для тех, кто не знает, Google может их расшифровать ;-) И есть только небольшая часть, которая часто используется сегодня (самые распространенные). – chi

11

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

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

struct foo { ... }; 

struct foo func(void) 
{ 
    struct foo someFoo; 
    ... 
    return someFoo; 
} 

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

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

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

-5

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

+1

Вы видели, что вопрос о C? В C нет никакого 'public' /' private' различия, и нет 'class'es. Вопрос в том, почему в C требуется 'struct', чтобы вернуть значение массива. – PJTraill

Смежные вопросы