Какова лучшая практика, когда у вас есть массив в структуре в C? - PullRequest
0 голосов
/ 06 декабря 2018

У меня есть собственная структура, которую я собираюсь использовать для отправки данных по TCP-соединению.Что было бы лучшим способом объявить массив внутри этой структуры?Было бы это:

typedef struct programData {
    int* dataArray;
    size_t numberofelements;
} pd;
// ...
pd data = {0};
data.dataArray = malloc(5*sizeof(int));
// put content in array ...
data.numerofelements = 5;

Или это было бы так:

typedef struct programData {
    int dataArray[5];
} pd;
// ...
pd data = {0};
data.dataArray[0] = ...;
// ...
data.dataArray[4] = ...;

Я сделал первый выход из привычки использовать malloc() в C, но не думаю, чтосодержимое массива будет фактически передано клиенту на другой стороне соединения, поскольку dataArray фактически будет указателем на адрес памяти в памяти сервера.Или send(2) действительно отправит содержимое массива вместе с ним?

edit: некоторые несоответствия из-за вставки копии из моего кода

Ответы [ 2 ]

0 голосов
/ 06 декабря 2018

send не является службой для передачи составных структур данных, включая интерпретацию значений указателей и связанных данных.Это сервис для отправки необработанных байтов.При использовании send вы должны преобразовать свои данные в необработанные байты, которые можно отправить.Получатель должен построить свои собственные структуры данных из этих байтов.Это означает, что вы должны создать схему для представления ваших данных с помощью байтов.

Когда необработанные байты структуры отправляются в другую систему, а принимающая система использует те же необработанные байты для представления структуры, результирующее значениеданных могут отличаться по следующим причинам:

  • Системы представляют объекты (например, целые числа) с байтами в разных порядках.
  • Системы вставляют разное количество байтов заполнения в структурудля поддержания выравнивания, требуемого или предпочитаемого аппаратным обеспечением.
  • Системы используют разные кодировки для символов или данных с плавающей запятой.
  • Типы в системе различны, так как для одного можно использовать два байтаint в то время как другой использует четыре.
  • Указатели в одной системе не имеют смысла в другой системе, так как они указывают на данные, которые никогда не передавались в другую систему и содержат адреса, которые не имеют отношения к адресу.макет на другой системе.

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

При условии, что у вас есть простойструктуры данных и использовать простой протокол отправки фактических байтов, которые представляют данные, тогда, конечно, объявление массива внутри структуры является самым простым.Если массив небольшой или обычно почти заполнен, так что при хранении и передаче неиспользуемых данных будет происходить лишь небольшое количество отходов, тогда объявление массива внутри структуры может быть хорошим решением.

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

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

Еще одна опция смешивает как динамическое распределение пространства для массива, так и включение массива в структуру.: Последний элемент структуры может быть членом гибкого массива.Это массив, объявленный в структуре как Type dataArray[];.Это должен быть последний элемент структуры.Он не имеет собственного размера, но при выделении пространства для структуры вы бы добавили дополнительное пространство для массива.В этом случае вместо структуры, имеющей указатель на массив, массив следует за базовой частью структуры в памяти.Такая структура с ее массивом может быть отправлена ​​в одном вызове send, при условии, что с учетом приведенных выше предостережений: Принимающая система должна быть способна правильно интерпретировать байты, и должен передаваться размер массива.

0 голосов
/ 06 декабря 2018

Лучшая практика - позволить требованиям вашего проекта определить, какой подход использовать.Оба имеют определенные преимущества в зависимости от того, что необходимо.

С учетом двух примеров:

1)

typedef struct programData {
int dataArray[5];//assuming '*' was a typo
} pd;

2)

typedef struct programData {
    int* dataArray;
    size_t numberofelements;
} pd; 

Если вы знаете требования к размеру до выполнения,тогда вариант 1), более простой подход, всегда предпочтителен.Если нет, то вариант 2) необходим, но имеет свои затраты.Динамическое распределение памяти усложняет код в отношении обработки ошибок и управления памятью, а также гарантирует, что все, что использует calloc и семейство, освобождается при его использовании.

Сериализация и десериализация рекомендуется для передачи любой формы.(и требуется для варианта 2, когда используются указатели.) Дополнительная строгость при реализации приносит дивиденды с точки зрения повышения предсказуемости того, что именно отправляется.

...