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

Я знаю, что в 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

Лучшим способом задать один и тот же вопрос будет "что особенно важно в массивах", поскольку к ним относятся массивы, к которым привязана специальная обработка, а не struct s.

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

Ответ 2

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

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

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

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

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


Примечание:

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

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

Ответ 3

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

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

struct foo { ... };

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

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

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

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

Ответ 4

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