字节水平长度描述
问题描述:
予有需要的长度字段多达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次计算,所以可读性方式似乎更重要不是效率在这里。我的方法做这样的事情更易读是
- 提取公共代码的功能
- 把类似的计算在一起,使图案更加明显
- 摆脱中间变量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;
}
}
}
答
我不知道我理解你的问题。你究竟想要计算什么?如果我理解正确,你试图找到最重要的非零字节。
你可能最好使用一个循环是这样的:
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字节的开销真的很重要吗?
- 你是否看到你的代码已经变得复杂了?
虽然这个答案肯定会产生一个非常紧凑的代码解决方案,但为什么它的工作原理并不是很清楚。我选择的答案使解决方案清晰易懂,一目了然便于理解。 – 2008-09-16 23:04:13