Хорошая форма: указатель против локальной переменной против индекса массива - PullRequest
5 голосов
/ 23 февраля 2010

Простите, если это кажется тривиальным вопросом - я, как правило, парень из систем управления (программирование и автоматизация), но в последнее время оказывался вовлеченным в некоторые проекты по встроенным микроконтроллерам и ПК.

Допустим, у меня есть функция, которая принимает указатель на массив «командных байтов», обычно длиной 5 или 10 байтов, например:

char cmd_i2c_read(unsigned char *cmd, unsigned short cmd_len) { ... }

Я хочу декодировать байты команды (* cmd).

Это лучше форма:

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

    unsigned char device_address = cmd[2];
    unsigned char register_address = cmd[3];
    unsigned char num_bytes = cmd[4];<br>
    // use the local variables:
    if(num_bytes &le 0xFF) {
        do_stuff(device_address, register_address, num_bytes);
    }
  2. Создание локальных указателей:

    unsigned char *device_address = &cmd[2];
    unsigned char *register_address = &cmd[3];
    unsigned char *num_bytes = &cmd[4];<br>
    // use the pointers:
    if(*num_bytes &le 0xFF) {
        do_stuff(*device_address, *register_address, *num_bytes);
    }
  3. Индексировать массив * cmd напрямую:
    if(cmd[4] <= 0xFF) { do_stuff(cmd[2], cmd[3], cmd[4]); }

Ответы [ 7 ]

4 голосов
/ 23 февраля 2010

Вариант 1 понятен, но немного многословен. Мне совсем не нравится 2, а 3 трудно понять. Лично я предпочитаю использовать структуры для такого рода вещей.

typedef struct  {
   unsigned char whatever[2];
   unsigned char device_address;
   unsigned char register_address;
   unsigned char num_bytes;
   }  CMD;

CMD * pcmd = (CMD *)&cmd[0];

// use the local variables:
if(num_bytes ≤ 0xFF) {
    do_stuff(pcmd->device_address, pcmd->register_address, pcmd->num_bytes);
3 голосов
/ 23 февраля 2010

ИМХО, первый способ лучше. Гораздо проще читать, чем номер 3, потому что вам не нужно знать сигнатуру функции, чтобы понять, что это за параметры.

Для больших структур данных я бы выбрал номер 2, то есть использовал указатель, чтобы вам не приходилось копировать значения. Но в этом случае разница не значительна, и я думаю, что * / & немного уменьшит читабельность.

3 голосов
/ 23 февраля 2010

Я предпочитаю пункт 3, но все сводится к предпочтению.

2 голосов
/ 23 февраля 2010

Определенно № 1. Это делает остальную часть кода намного более читабельной, а использование указателя, когда нормальная переменная будет делать, усложняет вопрос без причины. Компилятор оптимизирует все приросты микроскопической производительности, которые вы можете получить от # 3.

1 голос
/ 24 февраля 2010

Если бы это был я, я бы написал это как # 3, но с символическими именами для индексов массива, чтобы улучшить читаемость: -

#define DEVICE_ADDRESS 2
#define REGISTER_ADDRESS 3
#define NUM_BYTES 4

if (cmd[NUM_BYTES] <= 0xFF) {
    do_stuff(cmd[DEVICE_ADDRESS], cmd[REGISTER_ADDRESS], cmd[NUM_BYTES]);
}

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

0 голосов
/ 24 февраля 2010

Для меня это зависит от того, что вы будете делать с вашим буфером,

Хотя при прочих равных условиях я бы предпочел, чтобы буфер был структурой (допустим выравнивание) и, если это не удалось, напрямую индексировал буфер, хотя и не с магическими числами.

0 голосов
/ 24 февраля 2010

Мне больше всего нравится 1, он гораздо удобнее для чтения, чем остальные.

Если производительность важна (я имею в виду, например, что «нам нужно каждые 0,01% ускорения, которое мы можем получить»), вам придется тестировать, потому что от компилятора действительно зависит, какая последовательность окажется в самом быстром коде ( 1 может иметь ненужные копии, 2 может содержать лишние нагрузки из-за ограничений на наложение указателей, 3 может привести к лишним нагрузкам, если распределитель регистров действительно испорчен)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...