Записи данных определенного типа integer в буфер


У меня есть функция, которая записывает данные указанного типа в буфер. Вот часть этой записи тип uint8, типа uint16, тип uint32 и uint64 в, в большой и обратным порядком байтов. Как вы можете видеть, что один и тот же код повторяется несколько раз, поэтому я хочу сделать этот код более элегантным.

...        
            case BW_DATA_TYPE_UINT8:
            {
                Uint8_T val = *(static_cast(Uint8_T*, src));
                Uint8ToLittleEndianAr( IN val, OUT_FROM &bw->buffer[bw->curPos], OUT_TO &bw->buffer[bw->curPos] );
                bw->curPos += length;
                break;
            }

            case BW_DATA_TYPE_UINT16_LE:
            {
                Uint16_T val = *(static_cast(Uint16_T*, src));
                Uint16ToLittleEndianAr( IN val, OUT_FROM &bw->buffer[bw->curPos], OUT_TO &bw->buffer[bw->curPos] + 1 );
                bw->curPos += length;
                break;
            }

            case BW_DATA_TYPE_UINT32_LE:
            {
                Uint32_T val = *(static_cast(Uint32_T*, src));
                Uint32ToLittleEndianAr( IN val, OUT_FROM &bw->buffer[bw->curPos], OUT_TO &bw->buffer[bw->curPos] + 3 );
                bw->curPos += length;
                break;
            }

            case BW_DATA_TYPE_UINT64_LE:
            {
                Uint64_T val = *(static_cast(Uint64_T*, src));
                Uint64ToLittleEndianAr( IN val, OUT_FROM &bw->buffer[bw->curPos], OUT_TO &bw->buffer[bw->curPos] + 7 );
                bw->curPos += length;
                break;
            }


            case BW_DATA_TYPE_UINT16_BE:
            {
                Uint16_T val = *(static_cast(Uint16_T*, src));
                Uint16ToBigEndianAr( IN val, OUT_FROM &bw->buffer[bw->curPos], OUT_TO &bw->buffer[bw->curPos] + 1 );
                bw->curPos += length;
                break;
            }

            case BW_DATA_TYPE_UINT32_BE:
            {
                Uint32_T val = *(static_cast(Uint32_T*, src));
                Uint32ToBigEndianAr( IN val, OUT_FROM &bw->buffer[bw->curPos], OUT_TO &bw->buffer[bw->curPos] + 3 );
                bw->curPos += length;
                break;
            }

            case BW_DATA_TYPE_UINT64_BE:
            {
                Uint64_T val = *(static_cast(Uint64_T*, src));
                Uint64ToBigEndianAr( IN val, OUT_FROM &bw->buffer[bw->curPos], OUT_TO &bw->buffer[bw->curPos] + 7 );
                bw->curPos += length;
                break;
            }
    ...


477
7
задан 22 сентября 2011 в 04:09 Источник Поделиться
Комментарии
2 ответа

#define CONVERT(T, F, v) T val = *(static_cast(T*, src)); \
F( IN val, OUT_FROM &bw->buffer[bw->curPos], OUT_TO &bw->buffer[bw->curPos] + v ); \
bw->curPos += length;

[...]

case BW_DATA_TYPE_UINT8:
{
CONVERT(Uint8_T, Uint8ToLittleEndianAr, 0)
break;
}

case BW_DATA_TYPE_UINT16_LE:
{
CONVERT(Uint16_T, Uint16ToLittleEndianAr, 1)
break;
}

case BW_DATA_TYPE_UINT32_LE:
{
CONVERT(Uint32_T, Uint32ToLittleEndianAr, 3)
break;
}

case BW_DATA_TYPE_UINT64_LE:
{
CONVERT(Uint64_T, Uint64ToLittleEndianAr, 7)
break;
}

case BW_DATA_TYPE_UINT16_BE:
{
CONVERT(Uint16_T, Uint16ToBigEndianAr, 1)
break;
}

(непроверено!)
Вы можете пойти дальше и даже составить целое дело, но эта версия является компромиссом, чтобы сохранить читаемость.
[Править] я пропустил нижней части вашего кода, но я полагаю, вы можете завершить себя... :-)

4
ответ дан 22 сентября 2011 в 08:09 Источник Поделиться

Во-первых, я не думаю, что там что-то не так с исходным кодом. Понятно, что он делает и компилятор достаточно компетентен, чтобы оптимизировать вещи, которые повторяются в каждом операторе Case.

Но если вы действительно должны перегонять этот переключатель во что-то, что содержит только отличия между заявлениями, которые вы можете сделать как этот:

// typedef a function pointer, change "type" with the appropriate types for the function.
typedef void(*ToLittleEndianType)(type in, type out_from, type out_to);

Uint8_T val;
Uint8_T offset;
ToLittleEndianType ToLittleEndianAr;

case BW_DATA_TYPE_UINT8:
{
val = *(static_cast(Uint8_T*, src));
offset = 0;
ToLittleEndianAr = Uint8ToLittleEndianAr;
break;
}

case BW_DATA_TYPE_UINT16_LE:
{
val = *(static_cast(Uint16_T*, src));
offset = 1;
ToLittleEndianAr = Uint16ToLittleEndianAr;
break;
}

case BW_DATA_TYPE_UINT32_LE:
{
val = *(static_cast(Uint32_T*, src));
offset = 3;
ToLittleEndianAr = Uint32ToLittleEndianAr;
break;
}

case BW_DATA_TYPE_UINT64_LE:
{
val = *(static_cast(Uint64_T*, src));
offset = 7;
ToLittleEndianAr = Uint64ToLittleEndianAr;
break;
}

case BW_DATA_TYPE_UINT16_BE:
{
val = *(static_cast(Uint16_T*, src));
offset = 1;
ToLittleEndianAr = Uint16ToBigEndianAr;
break;
}

case BW_DATA_TYPE_UINT32_BE:
{
val = *(static_cast(Uint32_T*, src));
offset = 3;
ToLittleEndianAr = Uint32ToBigEndianAr;
break;
}

case BW_DATA_TYPE_UINT64_BE:
{
val = *(static_cast(Uint64_T*, src));
offset = 7;
ToLittleEndianAr = Uint64ToBigEndianAr;
break;
}

ToLittleEndianAr(IN val, OUT_FROM &bw->buffer[bw->curPos], OUT_TO &bw->buffer[bw->curPos] + offset);
bw->curPos += length;

Примечание: этот код является типобезопасным, в отличие от макросов.

2
ответ дан 22 сентября 2011 в 02:09 Источник Поделиться