Тестирование битов для создания строки - есть ли лучший подход? - PullRequest
2 голосов
/ 01 апреля 2009

Этот код работает, но мне интересно, есть ли лучший способ сделать это. По сути, мне нужно проверить биты и записать соответствующий символ или символы в строку в зависимости от состояния бита. Пробелы присутствуют, потому что символы будут отображаться шрифтом фиксированной ширины, и я бы хотел, чтобы они не перемещались. C или C ++ в порядке.

const char* Letters[10] = {"A", "B", "Sl", "St", "R", "L", "U", "D", "RS", "LS"};
const char* Ext[2] = {"X", "Y"};
const char* Spaces[10]  = {" ", " ", "  ", "  ", " ", " ", " ", " ", "  ", "  "};

char str[60];
char FinalString[60];

void MakeBitString(u16 data, u16 dataExt) {

    int x;
    strcpy(str, "");

    for (x = 0; x < 2; x++) {

        //X and Y
        if(dataExt & (1 << x)) {
            strcat(str, Spaces[x]); 
        }
        else
            strcat(str, Ext[x]);
    }

    for (x = 0; x < 10; x++) {

        //the rest
        if(data & (1 << x)) {
            strcat(str, Spaces[x]); 
        }
        else
            strcat(str, Letters[x]);
    }

    strcpy(FinalString, str);
}

Ответы [ 7 ]

4 голосов
/ 01 апреля 2009
  • используйте std :: string вместо char * и strcat;
  • зачем вам массив с пробелами? кажется, может быть только один пробел;
  • у вас есть почти идентичный код для двух параметров u16 - создайте одну маленькую функцию и вызовите ее дважды;
  • не записывать результат в глобальную переменную - вернуть std :: string
3 голосов
/ 01 апреля 2009

В основном решение C ++ выглядит как

Codes convert( std::size_t data,
               const Codes& ext, 
               const Codes& letters )
{
    Codes result;
    std::transform( ext.begin(),
                    ext.end(),
                    std::back_inserter( result ),
                    Converter( data ) );

    std::transform( letters.begin(),
                    letters.end(),
                    std::back_inserter( result ),
                    Converter( data ) );
    return result;
}

Где Converter реализовано как

struct Converter
{
    Converter( std::size_t value ):
        value_( value ), x_( 0 )
    {}
    std::string operator() ( const std::string& bitPresentation )
    {
        return ( value_ & ( 1 << x_++ ) ) ?
            std::string( bitPresentation.size(), ' ' ):
            bitPresentation;
    }
    std::size_t value_;
    std::size_t x_;
};

Вот преобразование из кодов в строковую функцию

std::string codesToString( const Codes& codes )
{
    std::ostringstream stringStream;
    std::copy( codes.begin(), codes.end(), 
               std::ostream_iterator<std::string>( stringStream ) );
    return stringStream.str();
}
3 голосов
/ 01 апреля 2009

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

Я также предполагаю, что у вас есть веская причина использовать глобальные переменные и символьные массивы фиксированной длины.

Вот что я бы сделал:

char FinalString[60];

void ConcatBitLabel(char ** str, u16 data, u16 bitMask, const char * label)
{
    if (data & bitMask)
    {
        // append spaces for strlen(label)
        while (*label) { *((*str)++) = ' '; label++; }
    }
    else
    {
        // append the label
        while (*label) { *((*str)++) = *label; label++; }
    }
}

void MakeBitString(u16 data, u16 dataExt)
{
    char * strPtr = FinalString;

    ConcatBitLabel(&strPtr, dataExt, 0x0001, "X");
    ConcatBitLabel(&strPtr, dataExt, 0x0002, "Y");

    ConcatBitLabel(&strPtr, data, 0x0001, "A");
    ConcatBitLabel(&strPtr, data, 0x0002, "B");
    ConcatBitLabel(&strPtr, data, 0x0004, "Sl");
    ConcatBitLabel(&strPtr, data, 0x0008, "St");
    ConcatBitLabel(&strPtr, data, 0x0010, "R");
    ConcatBitLabel(&strPtr, data, 0x0020, "L");
    ConcatBitLabel(&strPtr, data, 0x0040, "U");
    ConcatBitLabel(&strPtr, data, 0x0080, "D");
    ConcatBitLabel(&strPtr, data, 0x0100, "RS");
    ConcatBitLabel(&strPtr, data, 0x0200, "LS");

    *strPtr = 0; // terminate the string
}
1 голос
/ 01 апреля 2009

Ценой некоторых динамических выделений (внутри std :: string) вы можете сделать этот код более легко модифицируемым, не имея жестко закодированных чисел:

#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))

std::string MakeBitString(u16 data, const std::string* letters, int count) {
    std::string s;
    for (int x = 0; x < count; x++) {
        if (data & (1 << x))
            s.append(letters[x].size(), ' '); 
        else
            s += letters[x];
    }
    return s;
}

std::string MakeBitString(u16 data, u16 dataExt) {
    const std::string Letters[] = {"A", "B", "Sl", "St", "R", "L", "U", "D", "RS", "LS"};
    const std::string Ext[] = {"X", "Y"};

    std::string s = MakeBitString(dataExt, Ext, ARRAYSIZE(Ext));
    s += MakeBitString(dataExt, Letters, ARRAYSIZE(Letters));
    return s;
}
0 голосов
/ 03 апреля 2009

Нехороший, чистый раствор:

std::string MakeBitString(u16 data, u16 dataExt) {
    std::string ret;

    static const char *letters = "A B SlStR L U D RSLS";
    static const char *ext = "XY";
    static const char *spaces = "  ";

    for(int bit = 0; bit < 2; ++bit) {
        const char *which = (dataExt & 1) ? &ext[bit] : spaces;

        ret += std::string(which, 0, 1);

        dataExt >>= 1;
    }

    for(int bit = 0; bit < 10; ++bit) {
        const int length = letters[bit * 2 + 1] == ' ' ?  1 : 2;
        const char *which = (dataExt & 1) ? &letters[bit * 2] : spaces;

        ret += std::string(which, 0, length);

        dataExt >>= 1;
    }

    return ret;
}
0 голосов
/ 02 апреля 2009

Вот один из немногих способов сделать это за один проход. Он даже расширяется до 16 бит, если вы уверены, что маска wide установлена ​​в любом месте, где у вас есть двухсимвольный символ.

#define EXT_STR "XY"
#define DATA_STR "ABSlStRLUDRSLS"
const char FullStr[] =  EXT_STR DATA_STR;
#define  EXT_SZ  2 //strlen(EXT_STR);

void MakeBitStr(u16 data, u16 dataExt) {
    char* dest = FinalString;
    const char* src= FullStr;
    u16 input = (data<<EXT_SZ)|dataExt;
    u16 wide = (0x30C<<EXT_SZ)|0;  //set bit for every 2char tag;
    while ((src-FullStr)<sizeof(FullStr))
    {   *dest++ = (input&1)?' ':*src;
        if (wide&1)
        { wide&=~1;
        }
        else
        { input>>=1;wide>>=1;
        }
        src++;
    }
    *dest='\0';
}
0 голосов
/ 01 апреля 2009

Это должно быть хорошо; если вы хотите добавить кнопки или оси, вы можете немного обобщить их.

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