提问人:David Bryson 提问时间:8/30/2008 最后编辑:Keith ThompsonDavid Bryson 更新时间:11/18/2011 访问量:746
字节级长度说明
Byte level length description
问:
我有一个协议,它需要高达 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++;
}
}
答:
0赞
Daniel Jennings
8/30/2008
#1
试试这个循环:
{
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赞
David Bryson
9/17/2008
虽然这个答案确实产生了一个非常紧凑的代码解决方案,但它工作原理的本质并不清楚。我选择的答案通过一目了然的代码使解决方案清晰明了。
0赞
Nathan Fellman
8/30/2008
#2
我不确定我是否理解你的问题。你到底想算什么?如果我理解正确,您正在尝试找到最重要的非零字节。
最好使用这样的循环:
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赞
Tryke
8/30/2008
#3
您确实应该为您的长度使用固定宽度的字段。
- 当接收端的程序必须读取数据包的长度字段时,它如何知道长度停止的位置?
- 如果数据包的长度可能达到 4 GB,那么 1-3 字节的开销真的重要吗?
- 你看到你的代码已经变得多么复杂了吗?
0赞
Bart
9/3/2008
#4
实际上,您只进行了四次计算,因此可读性在这里似乎比效率更重要。我使这样的东西更具可读性的方法是
- 将通用代码提取到函数中
- 将类似的计算放在一起,使模式更加明显
- 去掉中间变量print_zeroes,明确输出字节的情况,即使它们为零(即前面的字节不为零)
我已将随机代码块更改为函数并更改了一些变量(下划线在 Markdown 预览屏幕中给我带来了麻烦)。我还假设正在传入字节,并且传入它的人将向我们传递一个指针,以便我们可以修改它。
代码如下:
/* 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);
但是,我同意压缩此字段会使接收状态机过于复杂。但是,如果您无法更改协议,则此代码更易于阅读。
下一个:如何列出 .so 文件中的符号
评论