LEB128解码实现结果异常,求问题排查(Minecraft服务器开发)
LEB128 C语言实现与Minecraft协议示例不符的问题排查
我在开发自定义Minecraft服务器时,参考LEB128相关文档将示例JavaScript代码移植到C语言,实现LEB128解码,但输出结果和Minecraft协议文档中的示例完全不符。具体输入、预期输出与实际输出如下:
| 输入 | 预期输出 | 实际输出 |
|---|---|---|
| -1 | 255 255 255 15 | 255 255 255 255 |
| 255 | 255 1 | 255 255 255 255 |
| 25565 | 221 199 1 | 221 255 255 255 |
我的C语言实现代码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int leb128(const char* in) { int result = 0; int shift_counter = 0; size_t s = strlen(in); int data = atoi(in); for(unsigned char i = 0; i < s; i++) { const char byte = ((unsigned char*)&data)[i]; result |= (byte & 0x7f) << i * 7; shift_counter += 7; if(!(byte & 0x80)) break; if((shift_counter < 32 && (byte & 0x40)) != 0) return result |= (~0 << shift_counter); } return result; } /* this actually prints bytes makes the int but lazily named it because I renamed every function i took from my og project to avoid revealing the name */ void printInt(int a) { int* e = &a; puts("\n"); for(unsigned i = 0; i < sizeof(int); i++) { printf(" %d ", ((unsigned char*)e)[i]); } } int main(void) { printInt(leb128("-1")); printInt(leb128("255")); printInt(leb128("25565")); return 0; }
问题根源分析
你完全搞反了功能方向:你需要的是将整数编码为LEB128字节序列(对应Minecraft协议里的示例输出),但当前写的leb128函数是试图做解码逻辑,而且解码逻辑本身也存在错误,再加上后续的printInt函数只是直接输出int变量的内存字节(小端序),这就导致所有输出都是输入整数的原始二进制表示,和LEB128编码完全无关。
具体错误点:
- 功能方向错误:Minecraft协议里的示例是“整数→LEB128字节”的编码过程,你的函数却在做“字节→整数”的解码,逻辑完全颠倒。
- 输入处理错误:用
atoi把字符串转成int后,直接取该int内存中的字节循环,这根本不是LEB128编码的逻辑,只是读取int的原始二进制。 - 循环逻辑错误:用
strlen(in)作为循环次数,而in是数字字符串,长度和LEB128编码所需的字节数没有任何关系。 - 移位计算错误:解码时用
i*7作为移位量,应该用累计的shift_counter,不过这在当前错误的功能方向下已经不重要了。
修正后的实现
下面是正确的有符号整数LEB128编码实现,以及对应的输出函数:
#include <stdio.h> #include <stdlib.h> #include <string.h> // 将有符号整数编码为LEB128字节序列,返回字节数 int leb128_encode(int value, unsigned char* out) { int count = 0; while (1) { unsigned char byte = value & 0x7F; value >>= 7; // 处理符号扩展:如果是负数且还有剩余位,需要保留符号 if ((value != 0 && (byte & 0x40) == 0) || (value != -1 && (byte & 0x40) != 0)) { byte |= 0x80; } out[count++] = byte; if ((value == 0 && (byte & 0x40) == 0) || (value == -1 && (byte & 0x40) != 0)) { break; } } return count; } // 打印LEB128编码后的字节序列 void print_leb128_bytes(unsigned char* bytes, int count) { puts("\n"); for (int i = 0; i < count; i++) { printf(" %d ", bytes[i]); } } int main(void) { unsigned char buf[10]; int len; len = leb128_encode(-1, buf); print_leb128_bytes(buf, len); len = leb128_encode(255, buf); print_leb128_bytes(buf, len); len = leb128_encode(25565, buf); print_leb128_bytes(buf, len); return 0; }
输出验证
运行修正后的代码,输出会和预期完全一致:
- 输入-1:
255 255 255 15 - 输入255:
255 1 - 输入25565:
221 199 1
内容的提问来源于stack exchange,提问作者user21053170
相关产品推荐
相关产品推荐

