C, пожалуйста, помогите объяснить маленький код - PullRequest
1 голос
/ 14 августа 2010

Пожалуйста, помогите мне понять 2 вещи, которые я нашел в этом коде C:

Во-первых, есть целый код:

usbMsgLen_t usbFunctionSetup(uchar data[8])  
{  
usbRequest_t    *rq = (void *)data;  
static uchar    dataBuffer[4];  /* buffer must stay valid when usbFunctionSetup returns */  
if(rq->bRequest == CUSTOM_RQ_ECHO){ /* echo -- used for reliability tests */  
        dataBuffer[0] = rq->wValue.bytes[0];  
        dataBuffer[1] = rq->wValue.bytes[1];  
        dataBuffer[2] = rq->wIndex.bytes[0];  
        dataBuffer[3] = rq->wIndex.bytes[1];  
        usbMsgPtr = dataBuffer;         /* tell the driver which data to return */  
        return 4;  
    }else if(rq->bRequest == CUSTOM_RQ_SET_STATUS){  
        if(rq->wValue.bytes[0] & 1){    /* set LED */  
            LED_PORT_OUTPUT |= _BV(LED_BIT);  
        }else{                          /* clear LED */  
            LED_PORT_OUTPUT &= ~_BV(LED_BIT);  
        }  
    }else if(rq->bRequest == CUSTOM_RQ_GET_STATUS)  {  
        dataBuffer[0] = ((LED_PORT_OUTPUT & _BV(LED_BIT)) != 0);  
        usbMsgPtr = dataBuffer;         /* tell the driver which data to return */  
        return 1;                       /* tell the driver to send 1 byte */  
    }  
    return 0;   /* default for not implemented requests: return no data back to host */  
}  

Теперь usbFunctionSetup получает массив из 8 беззнаковых символов. Теперь идет строка:

usbRequest_t    *rq = (void *)data;

Итак, я получаю левую часть утверждения, но что справа? Я знаю, что (void *) приведен к этому типу, но почему?

И второй вопрос: не является ли этот код неэффективным? Потому что первая функция получает 8 байтов данных, а затем создает дополнительный указатель на них. И этот дополнительный указатель создается, по крайней мере, если я прав, просто чтобы иметь возможность доступа к отдельным данным по их имени, определенному в usbRequest_t struct. Было бы проще и эффективнее просто использовать в коде вместо rq->bRequest == something только для примера data[2]==something или если bRequest больше одного байта, например data[1] == low_byte_of_something && data[2]== high_byte_of_something?

Ответы [ 4 ]

0 голосов
/ 14 августа 2010

Что касается вашего заявления о том, что код неэффективен, я вижу небольшую или никакую разницу между доступом к data[x] и rq->x.В обоих случаях код начинается с базового адреса и смещается на несколько байтов (по-видимому, максимум до 8 байтов).

[Base Address] + [Offset] будет одинаковым, независимо от того, делаете ли вы это по массиву или по структуре.И если простые дополнения являются источником неэффективности вашей программы, у вас гораздо большие проблемы.

0 голосов
/ 14 августа 2010

Вопрос 1: Поскольку data равно uchar *, вам необходимо привести его к другому типу. Вы можете привести его к usbRequest_t *, если хотите.

Вопрос 2: Адрес rq->bRequest занимает столько же времени, сколько и адрес data[2]. В обоих случаях вы берете указатель из стека и добавляете к нему фиксированное смещение. Использование указателя структуры приводит к более четкому коду.

0 голосов
/ 14 августа 2010

ваша первая строка ( rq = (void ) ..) говорит компилятору обрабатывать 8 байтов, переданных как usbRequest_t

предположительно, это пакет от устройства или сетии код хочет смотреть на него так, как будто он соответствует структуре

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

и наоборот, ваше предложение rq-> bRequest == что-то на самом деле скопирует данные - что является (v небольшим для 8 байт) накладных расходов

Это очень распространенное явлениеметодика отображения структур на сериализованные потоки данных

0 голосов
/ 14 августа 2010

Функция получает «необработанный» буфер данных, а строка:

usbRequest_t    *rq = (void *)data;

просто создает указатель на этот буфер для доступа к нему, используя макет данных, заданный структурой usbRequest_t.

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

С другой стороны, могут быть проблемы с переносимостью,но это может быть не важно для вашего конкретного приложения.

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