Преобразование структур с прямым порядком байтов в порядок с прямым порядком байтов - PullRequest
5 голосов
/ 20 января 2012

Я делаю программу на C, которая связывается с монитором пациента, использующим порядок байтов с прямым порядком байтов. Например, если у меня есть определенная структура C

typedef struct {
   int short a;
   int short b;
   int       c;
} msg;

Чтобы прочитать такую ​​структуру, я могу просто использовать ntohs (msg.a), ntohs (msg.b), ntohl (msg.c). Но некоторые структуры имеют буфер с короткими целыми числами, но сам этот буфер является типом другой структуры. Например,

typedef struct {
   int short length;
   int short b[MAX_BUF_SIZE];
} msg1;

Поле "b" в вышеприведенной структуре представляет другую структуру, которая находится ниже:

typedef struct {
   int short a;
   int short b;
} msg2;

Теперь мой вопрос: 1) я должен преобразовать все короткие целые числа структуры "msg1" в порядок хостов, а затем привести его к указателю типа "msg2" и просто прочитать "msg2.a" и "msg2.b" или 2) я должен преобразовать порядок байтов в "msg2.a" и "msg2.b", а также 3) просто приведение msg1.b указывает на указатель типа msg2 и считывает msg2.a и msg2.b, преобразовывая каждый из них в порядок хостов?

Пожалуйста, скажите, какой из подходов корректен для чтения msg1

ПОДХОД 1

int t[msg1.length];
for(int i = 0; i < msg1.length; i++)
   t[i] = ntohs(*(msg1.b + i));
msg2 * msg2_m = (msg2 *)t;
/* should I convert the msg2_m.a and msg2_m.b as well? */
printf("%d:%d", msg2_m.a, msg2_m.b);

ПОДХОД 2

Все то же самое, кроме

printf("%d:%d", ntohs(msg2_m.a), ntohs(msg2_m.b));

ПОДХОД 3

Не преобразовывать msg1.b и напрямую приводить msg1.b к msg2, а просто преобразовывать msg2.a и msg2.b в порядок хостов.

msg2 *msg2_m = (msg2 *)msg1.a;
printf("%d:%d", ntohs(msg2_m.a), ntohs(msg2_m.b));

Мне нужно понять, когда структура приводится к некоторым другим структурам, меняется ли ее порядок байтов в соответствии с новой структурой при передаче по сети? Я думаю, что APPROACH 3 правильный, но это только я, я не уверен насчет внутренних элементов порядка байтов. Любая помощь будет оценена.

Спасибо, Шивам Калра

Ответы [ 2 ]

3 голосов
/ 20 января 2012

Во-первых, приведение не влияет на порядок байтов.

Во-вторых, вы не хотите думать о порядке следования байтов повсюду в вашем коде, потому что вы или кто-то еще забудут и допустят ошибку где-нибудь, и это будет адская попытка найти ошибку позже. Поэтому, как только вы прочитаете данные, преобразуйте их в правильный порядок байтов. Если вы прочитали структуру, содержащую массив шорт, немедленно преобразуйте весь массив шорт в правильный порядок байтов. То же самое касается любых других структур. Преобразовать данные и сохранить результат; не просто используйте ntohs каждый раз, когда вам нужно что-то прочитать или напечатать. Отделите этот код от остальной части вашей программы, чтобы вы могли забыть о порядке следования байтов в других частях программы и думать о порядке следования байтов только при работе с кодом преобразования.

2 голосов
/ 20 января 2012

Я думаю, что обычно лучше не пытаться читать или писать struct с напрямую. Вместо этого вы должны явно определить свой проводной формат и записать в него свою побайтную структуру (а затем сделать обратное при чтении). Например, написать:

typedef struct {
   short int a;
   short int b;
   int       c;
} msg;

Вы можете сделать:

void WriteBigEndian16(uint16_t x, FILE* fp)
{
   fputc((x >> 8) & 0xFF, fp);
   fputc( x       & 0xFF, fp);
}

void WriteBigEndian32(uint32_t x, FILE* fp)
{
   fputc((x >> 24) & 0xFF, fp);
   fputc((x >> 16) & 0xFF, fp);
   fputc((x >>  8) & 0xFF, fp);
   fputc( x        & 0xFF, fp);
}

FILE* fp = fopen(...);
msg m; // Assume that this is initialized.
WriteBigEndian16(m.a, fp);
WriteBigEndian16(m.b, fp);
WriteBigEndian32(m.c, fp);

Это имеет следующие преимущества:

  • Код является порядком байтов. Неважно, работаете ли вы на машине с прямым порядком байтов или на машине с прямым порядком байтов. Вам не нужно знать.
  • Вы избегаете любой путаницы в отношении того, являются ли ваши 1013 * в памяти поменяемые байтами или нет. Они всегда будут такими же, как и у платформы.
  • Вы также определяете размеры своих полей. Если вы не определяете формат проводника, вы не только склонны к несоответствиям порядка байтов, но также подвержены несоответствиям размеров. Кто сказал, что обе конечные точки используют одинаковый размер для int?
...