Лучший способ определить 2 байта для легкого использования с инициализацией / сравнением массива в C? - PullRequest
1 голос
/ 08 января 2011

Опять же, я довольно новичок в C, поэтому прости простоту / глупость этого вопроса. Во всяком случае, здесь это идет. Каков наилучший способ #define 2-байтового макроса (то есть #define MSGID 0xABCD) в C, который легко поместить в байтовый массив, но также сравнить содержимое с операторами if?

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

unsigned char test_msg[] = { 0x00, 0x01, 0x02, MSGID, 0x03, 0x04, 0x05 };

С тем, как я определил это выше, он не будет работать, потому что он определен как большой int и gcc усекает его до беззнакового типа. Когда я определяю его как #define MSGID 0xAB, 0xCD, кажется, что он работает нормально, но я не понимаю, что делает запятая, и это выглядит не очень чисто. Я обнаружил, что другой вариант, который работает, но не является чистым, - это разделить его как #define MSGIDCLASS 0xAB, а затем #define MSGID 0xCD.

Я также хотел бы сравнить эти байты MSGID, и в данный момент мне приходится постоянно делать if (data [n] == MSGIDCLASS && data [n + 1] == MSGID) ... для каждого сообщения Мне нужно разобрать и ответить. Мне было интересно, есть ли более простой способ сделать это, вот и все. Если нет, я оставлю это как есть. Спасибо еще раз за помощь. Приносим извинения за то, что не использовал теги примеров кода, не думал, что они были необходимы с одним вкладышем.

Ответы [ 3 ]

3 голосов
/ 08 января 2011

#define просто заменяется их содержимым.Таким образом, когда вы используете запятые, конечный код становится:

unsigned char test_msg[] = { 0x00, 0x01, 0x02, 0xAB, 0xCD, 0x03, 0x04, 0x05 };

Вот почему он работает.

Вместо этого, отдельно определяя компоненты MSGIDHI и MSGIDLO, вы можете использовать исравнить легко.И вы можете определить MSGID как:

#define MSGIDLO 0xCD
#define MSGIDHI 0xAB
#define MSGID (MSGIDLO | (MSGIDHI << 8)) 

Таким образом, вы можете использовать их в любой форме.

1 голос
/ 08 января 2011

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

  • Сохранить отдельные значения класса и идентификатора.
  • Используйте эти отдельные значения для заполнения сообщений
  • Используйте следующие макросы для сравнения:

    #define MSGID(msgClass, ID) (((msgClass) << 8) | (ID))
    #define GET_MSGID(data, n) (((data)[n] << 8) | (data)[(n)+1])
    

Вы используете их так:

#define MSGCLASS_A 0xAB
#define MSGID_B    0xCD

unsigned char test_msg[] = { 0x00, 0x01, 0x02, MSGCLASS_A, MSGID_B, 0x03, 0x04, 0x05 };

if (GET_MSGID(test_msg, 0) == MSG_ID(MSGCLASS_A, MSGID_B))
{
  // matched message
}

Если ваши идентификаторы сообщений на самом деле просто 16-битные числа, вы можете сделать следующее:

  • Используйте одно определение для вашего идентификатора сообщения
  • Используйте следующие макросы для вставки / извлечения их из сообщения:

    #define MSGID(ID) (((ID) >> 8) & 0xFF), ((ID) & 0xFF) /* For static message definitions */
    #define ADD_MSGID(data, n, ID) do { (data)[n] = (((ID) >> 8) & 0xFF; (data)[(n)+1] = ((ID) & 0xFF; } while (0)
    #define GET_MSGID(data, n) (((data)[n] << 8) | (data)[(n)+1])
    

Вы используете их так:

#define MSGID_A 0xABCD

unsigned char test_msg[] = { 0x00, 0x01, 0x02, MSGID(MSGID_A), 0x03, 0x04, 0x05 };

// or: ADD_MSGID(test_msg, 0, MSGID_A)

if (GET_MSGID(test_msg, 0) == MSGID_A)
{
  // matched message
}

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

1 голос
/ 08 января 2011

Иногда вы можете предпочесть решение без препроцессора, например:

enum {MSGID = 0xABCD};
// in C++ you can use const int MSGID = 0xABCD instead, not sure about C

unsigned char test_msg[] = { 0x00, 0x01, 0x02, MSGID>>8, MSGID&0xff, 0x03, 0x04, 0x05 };
...