字节级长度说明
时间:2020-03-05 18:45:09 来源:igfitidea点击:
我有一个协议,要求长度字段最多为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++; } }
解决方案
回答
试试这个循环:
{ 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; } } }
回答
我不确定我是否理解问题。我们到底想算什么?如果我正确理解,我们正在尝试查找最高有效的非零字节。
我们最好使用这样的循环:
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字节的开销真的重要吗?
- 我们看到代码已经变得多么复杂吗?
回答
实际上,我们仅执行四个计算,因此可读性似乎比效率更重要。我使这样的内容更具可读性的方法是
- 将通用代码提取到函数
- 将类似的计算放在一起,使模式更明显
- 摆脱中间变量print_zeroes并明确说明输出字节的情况,即使它们为零(即,前一个字节为非零)
我已将随机代码块更改为一个函数,并更改了一些变量(下划线在降价预览屏幕中给我带来麻烦)。我还假定要传递字节,并且无论谁传递字节都会向我们传递一个指针,以便我们可以对其进行修改。
这是代码:
/* 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);
但是,我同意压缩该字段会使接收状态机过于复杂。但是,如果我们不能更改协议,则此代码更容易阅读。