【问题标题】:Testing Bits To Create A String - Is there a better approach?测试位以创建字符串 - 有更好的方法吗?
【发布时间】:2010-10-16 22:17:21
【问题描述】:

此代码有效,但我想知道是否有更好的方法。基本上我需要测试位,并根据位的状态将适当的字符写入字符串。存在空格是因为字符将以固定宽度的字体显示,我想防止它们四处移动。 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);
}

【问题讨论】:

    标签: c++ c string loops bit-manipulation


    【解决方案1】:
    • 使用 std::string 代替 char* 和 strcat;
    • 为什么需要带空格的数组?似乎只有一个空格;
    • 您的两个 u16 参数的代码几乎相同 - 创建一个小函数并调用它两次;
    • 不要将结果写入全局变量 - 返回 std::string

    【讨论】:

    • 无论是否设置位,都确保宽度相同。
    【解决方案2】:

    我推荐一些更明确的方法,它不使用循环,因为您似乎只有少量位要检查。如果这需要扩展到数万位,那么一定要使用循环。

    我还假设您有充分的理由使用全局变量和固定长度的字符数组。

    我会这样做:

    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
    }
    

    【讨论】:

      【解决方案3】:

      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();
      }
      

      【讨论】:

      • 我认为使用 boost::array 或通常的 aray 存储字符串会更好(易于创建)。您的转换器也计算调用次数 - 我不确定这是否合法。
      • @bb:当然可以更改初始化阶段,甚至转换器也可以接受集合作为参数。 boost::array 在允许提升的情况下是个好主意。使用通常的数组只是为了简短 - 我不喜欢它们:) 和它们的大小计算。必须检查有关在函子中计数的标准。
      • 不是。代码分为几部分:一部分处理位,另一部分处理位。当你需要改变一个部分时,你不要碰其他部分。一种低耦合。
      【解决方案4】:

      以一些动态分配为代价(在 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;
      }
      

      【讨论】:

        【解决方案5】:

        应该没问题;但是,如果您想添加按钮或轴,您可能需要对其进行概括。

        【讨论】:

          【解决方案6】:

          这是一次完成的一种有点麻烦的方法。只要您确保 wide 掩码在您有 2 字符指示符的任何位置都设置了位,它甚至可以扩展到最多 16 位。

          #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';
          }
          

          【讨论】:

            【解决方案7】:

            非 hacky、干净的解决方案:

            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;
            }
            

            【讨论】:

              猜你喜欢
              • 2016-04-29
              • 2018-04-24
              • 1970-01-01
              • 2013-09-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多