字节水平长度描述

问题描述:

予有需要的长度字段多达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++; 
    } 
} 

真的你只是在做4次计算,所以可读性方式似乎更重要不是效率在这里。我的方法做这样的事情更易读是

  1. 提取公共代码的功能
  2. 把类似的计算在一起,使图案更加明显
  3. 摆脱中间变量print_zeroes的并明确说明你输出字节,即使他们是零的情况下(即前面的字节是非零)

我已经改变了随机代码块到一个函数,并改变了一些变量(下划线给我Markdown预览屏幕出现问题EN)。我还假定字节正在被传入,并且谁传递它将传递给我们一个指针,以便我们可以修改它。

下面的代码:

/* 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); 

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

试试这个循环:

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

    } 

} 
+0

虽然这个答案肯定会产生一个非常紧凑的代码解决方案,但为什么它的工作原理并不是很清楚。我选择的答案使解决方案清晰易懂,一目了然便于理解。 – 2008-09-16 23:04:13

我不知道我理解你的问题。你究竟想要计算什么?如果我理解正确,你试图找到最重要的非零字节。
你可能最好使用一个循环是这样的:

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

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

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