【问题标题】:Byte level length description字节级长度说明
【发布时间】:2010-09-07 06:59:51
【问题描述】:

我有一个协议,它需要一个最长为 32 位的长度字段,并且它必须是 在运行时生成以描述给定数据包中有多少字节。

下面的代码有点丑,但我想知道这是否可以重构为 稍微更有效或更容易理解。问题是, 代码只会生成足够的字节来描述数据包的长度,所以 小于 255 字节 = 1 字节长度,小于 65535 = 2 字节长度 等等……

{
    extern char byte_stream[];
    int bytes = offset_in_packet;
    int n = length_of_packet;
   /* Under 4 billion, so this can be represented in 32 bits. */
    int t;
   /* 32-bit number used for temporary storage. */

    /* These are the bytes we will break up n into. */
    unsigned char first, second, third, fourth;

    t = n & 0xFF000000;
    /* We have used AND to "mask out" the first byte of the number. */
    /* The only bits which can be on in t are the first 8 bits. */
    first = t >> 24;
    if (t)  {
        printf("byte 1: 0x%02x\n",first );
        byte_stream[bytes] = first; bytes++;
        write_zeros = 1;
    }
    /* Now we shift t so that it is between 0 and 255. This is the first, highest byte of n. */
    t = n & 0x00FF0000;
    second = t >> 16;
    if (t || write_zeros) {
        printf("byte 2: 0x%02x\n", second );
        byte_stream[bytes] = second; bytes++;
        write_zeros = 1;
    }

    t = n & 0x0000FF00;
    third = t >> 8;
    if ( t || write_zeros) {
        printf("byte 3: 0x%02x\n", third );
        byte_stream[bytes] = third; bytes++;
        write_zeros = 1;
    }

    t = n & 0x000000FF;
    fourth = t;
    if (t || write_zeros) {
        printf("byte 4: 0x%02x\n", fourth);
        byte_stream[bytes] = fourth; bytes++;
    }
}

【问题讨论】:

    标签: c protocols


    【解决方案1】:

    你真的应该为你的长度使用一个固定宽度的字段。

    • 当接收端的程序必须读取你的数据包的长度字段时,它如何知道长度停止在哪里?
    • 如果数据包的长度可能达到 4 GB,那么 1-3 字节的开销真的很重要吗?
    • 您看到您的代码已经变得多么复杂了吗?

    【讨论】:

      【解决方案2】:

      实际上,您只进行了四次计算,因此在这里,可读性似乎比效率更重要。我使此类内容更具可读性的方法是

      1. 将公共代码提取到函数中
      2. 将相似的计算放在一起,使模式更明显
      3. 摆脱中间变量 print_zeroes 并明确说明输出字节的情况,即使它们为零(即前一个字节非零)

      我已将随机代码块更改为函数并更改了一些变量(下划线在降价预览屏幕中给我带来了麻烦)。我还假设 bytes 正在被传入,并且传入它的任何人都会传给我们一个指针,以便我们可以修改它。

      代码如下:

      /* append byte b to stream, increment index */
      /* really needs to check length of stream before appending */
      void output( int i, unsigned char b, char stream[], int *index )
      {
          printf("byte %d: 0x%02x\n", i, b);
          stream[(*index)++] = b;
      }
      
      
      void answer( char bytestream[], unsigned int *bytes, unsigned int n)
      {
          /* mask out four bytes from word n */
          first  = (n & 0xFF000000) >> 24;
          second = (n & 0x00FF0000) >> 16;
          third  = (n & 0x0000FF00) >>  8;
          fourth = (n & 0x000000FF) >>  0;
      
          /* conditionally output each byte starting with the */
          /* first non-zero byte */
          if (first) 
             output( 1, first, bytestream, bytes);
      
          if (first || second) 
             output( 2, second, bytestream, bytes);
      
          if (first || second || third) 
             output( 3, third, bytestream, bytes);
      
          if (first || second || third || fourth) 
             output( 4, fourth, bytestream, bytes);
       }
      

      对最后四个 if 语句的修改将更加高效,也许更容易理解:

          if (n>0x00FFFFFF) 
             output( 1, first, bytestream, bytes);
      
          if (n>0x0000FFFF) 
             output( 2, second, bytestream, bytes);
      
          if (n>0x000000FF)  
             output( 3, third, bytestream, bytes);
      
          if (1) 
             output( 4, fourth, bytestream, bytes);
      

      不过,我同意压缩此字段会使接收状态机过于复杂。但是如果你不能改变协议,这段代码就更容易阅读了。

      【讨论】:

        【解决方案3】:

        试试这个循环:

        {
            extern char byte_stream[];
            int bytes = offset_in_packet;
            int n = length_of_packet; /* Under 4 billion, so this can be represented in 32 bits. */
            int t; /* 32-bit number used for temporary storage. */
            int i;
        
            unsigned char curByte;
        
            for (i = 0; i < 4; i++) {
                t = n & (0xFF000000 >> (i * 16));
        
                curByte = t >> (24 - (i * 8));
                if (t || write_zeros)  {
                    printf("byte %d: 0x%02x\n", i, curByte );
                    byte_stream[bytes] = curByte;
                                    bytes++;
                    write_zeros = 1;
                }
        
            }
        
        }
        

        【讨论】:

        • 虽然这个答案确实产生了一个非常紧凑的代码解决方案,但它的工作原理并不清楚。我选择的答案使解决方案一目了然,代码一目了然。
        【解决方案4】:

        我不确定我是否理解您的问题。你到底想计算什么?如果我理解正确,您正在尝试查找最重要的非零字节。
        你可能最好使用这样的循环:

        int i;  
        int write_zeros = 0;  
        for (i = 3; i >=0 ; --i) {  
            t = (n >> (8 * i)) & 0xff;  
            if (t || write_zeros) {  
                write_zeros = 1;  
                printf ("byte %d : 0x%02x\n", 4-i, t);  
                byte_stream[bytes++] = t;
            }  
        }
        

        【讨论】:

          猜你喜欢
          • 2013-10-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-11-07
          • 1970-01-01
          • 1970-01-01
          • 2013-10-24
          相关资源
          最近更新 更多