Зачем объявлять структуру, содержащую только массив в C?

131

Я наткнулся на код, содержащий следующее:

struct ABC {
    unsigned long array[MAX];
} abc;

Когда имеет смысл использовать подобное объявление?

Joe.Z
источник

Ответы:

184

Он позволяет передавать массив в функцию по значению или получать его по значению, возвращаемому функцией.

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

Благовест Буюклиев
источник
1
Остерегайтесь делать это с массивами, размером более 16 или 32 байтов, для функций, которые не встроены: более эффективно передавать их по константной ссылке, если вызываемому объекту уже не нужна копия tmp, которую он может уничтожить. Если вызов / возврат не оптимизируются, массив от среднего до большого (тысячи байтов) - ужасная вещь для передачи по значению.
Питер Кордес
85

Еще одно преимущество состоит в том, что он абстрагирует размер, поэтому вам не нужно использовать [MAX]весь код везде, где вы объявляете такой объект. Этого также можно добиться с помощью

typedef char ABC[MAX];

но тогда у вас есть гораздо более серьезная проблема: вы должны знать, что ABCэто тип массива (даже если вы не видите этого, когда объявляете переменные типа ABC), иначе вы будете ужалены тем фактом, что это ABCбудет означать что-то другое в списке аргументов функции по сравнению с объявлением / определением переменной.

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

R .. GitHub ОСТАНОВИТЬ, ПОМОГАЯ ЛЕД
источник
45

Вы можете скопировать структуру и вернуть структуру из функции.

Вы не можете сделать это с массивом - если он не является частью структуры!

Бо Перссон
источник
26

Вы можете скопировать это так.

struct ABC a, b;
........
a = b;

Для массива вам нужно будет использовать функцию memcpy или цикл для назначения каждого элемента.

MetallicPriest
источник
6
(так что он позволяет более чистый код - это не повлияет на скорость и т. д.)
Джон Картер,
3
Это полезно К сожалению, вы не можете сделать if (a == b)!?! как это непоследовательно. Для C ++ он ищет оператор ==. В C написано «недопустимые операнды для двоичного ==».
Мэтт
11

Вы можете использовать структуру для создания нового типа данных, например строки . вы можете определить:

struct String {
    char Char[MAX];
};

или вы можете создать список данных, которые вы можете использовать в качестве аргумента функций или вернуть в своих методах. Структура более гибкая, чем массив, потому что она может поддерживать некоторые операторы, такие как =, и вы можете определять в ней некоторые методы.

Надеюсь, это будет полезно для вас :)

Хоссейн Мобашер
источник
2
По сути, это самое близкое к C создание класса. Мне нравится этот ответ, потому что он наиболее точно указывает на это.
Nate CK
1
Нет такой вещи, как метод в C. Структуры в C не являются простыми старыми данными. У него есть оператор =, поддерживаемый по умолчанию (который, как показывают другие ответы, является причиной для этого), но это вводит в заблуждение и в основном относится к C ++, а не C.
Джонатан Стернберг
3
@J Sternberg: «Метод» - это просто способ думать о подпрограммах как о связанных с «объектами» данных, на которые они влияют. Вы, конечно, можете создавать «классы» «объектов» и «методов», которые оперируют с ними в C. Просто язык формально не определяет такие вещи. Если вы хотите создать более качественные абстракции на C, обычно лучше всего это сделать в виде структуры.
Nate CK,
Вдобавок, если вы действительно хотите «создать» методы на C, вы можете использовать указатели на функции (да, да, сложный синтаксис, отсутствие защиты данных и т. Д.), Чтобы связать функции с данными, с которыми они работают. Вы должны передать «self» в первый аргумент (вы можете даже назвать его «this», если хотите), поскольку нет автоматического создания этого указателя внутри функции в C.Конечно, это все гимнастика, вы получаете такие вещи по умолчанию в C ++, хотя это правда, что в качестве бонуса могут быть скрытые накладные расходы ...
BenPen
2

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

Если вы не оборачиваете массив в a struct, вы все равно можете объявить typedefдля него a : это имеет некоторые из преимуществ: struct• тип объявляется один раз, • размер автоматически корректируется, • смысл кода становится более ясным, • а код более удобен в обслуживании, но вы теряете ◦ строгую безопасность типов, ◦ возможность копировать и возвращать значения типа и ◦ возможность добавлять элементы позже, не нарушая остальной код. Два typedefs для пустых массивов данного типа дают разные типы, только если они имеют разные размеры. Более того, если вы используете typedefбез *аргумента функции, это эквивалентно char *значительному снижению безопасности типов.

В итоге :

typedef struct A_s_s { char m[113]; } A_s_t; // Full type safey, assignable
typedef char   A_c_t[113];                   // Partial type-safety, not assignable

A_s_t          v_s(void);     // Allowed
A_c_t          v_c(void);     // Forbidden

void           s__v(A_s_t);     // Type-safe, pass by value
void           sP_v(A_s_t *);   // Type-safe
void           c__v(A_c_t);     // UNSAFE, just means char * (GRRR!)
void           cP_v(A_c_t *);   // SEMI-safe, accepts any array of 113
PJTraill
источник
1

Структура может содержать функции инициализации массива, копирования и завершения, имитирующие некоторые преимущества парадигм управления памятью ООП. Фактически, очень легко расширить эту концепцию, чтобы написать универсальную утилиту управления памятью (используя структуру sizeof (), чтобы точно знать, сколько байтов обрабатывается) для управления любой структурой, определяемой пользователем. Многие интеллектуальные производственные кодовые базы, написанные на C, интенсивно используют их и обычно никогда не используют массив, если его область действия не является очень локальной.

Фактически, для массива, встроенного в структуру, вы могли бы делать другие «умные вещи», такие как проверка привязки, в любое время, когда вы хотели получить доступ к этому массиву. Опять же, если объем массива не очень ограничен, использовать его и передавать информацию между программами - плохая идея. Рано или поздно вы столкнетесь с ошибками, которые не дадут вам уснуть по ночам и испортят ваши выходные.

Aniket
источник
Это не отвечает на вопрос, почему можно использовать, structсодержащий только массив.
PJTraill