首先说明本题目的原意:以下程序是GBK编码和解码程序,根据编码过程encode(),将解码过程decode()补充完整。写出输出结果,输出结果是一句话。
程序的运行环境是Linux,编译命令gcc -std=c99 -o code code.c; 这样执行结果居然是乱码!!!然后我就怀疑我的解码程序有问题,我就检查了数小时,实在认为我写的没有错误,然后我就协议几个测试用例进行完整的编码和解码,结果能够正常解码。这就奇怪了!然后,我又查网友的资料,结果查不到,我请大牛同学帮忙,请网上认识的高人。大牛和高人要么是忙,要么直接不摆我,伤心啊。
可以对比一下代码的变化,好消息是结果出来了,正是下图:
下面代码是原题(程序风格都没变),说实在的,这程序员代码风格实在是,一个字乱!
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <string.h>
int encode(const void* raw_in, void* raw_out, uint32_t password, size_t len)
{
const uint8_t* in = (const uint8_t*)raw_in;
uint8_t* out = (uint8_t*)raw_out;
uint32_t seed = password ^ 0x55157c65u;
for (size_t i = 0 ; i < len; ++i) {
uint8_t a = ( in[i] ^ seed ) >> 5;
uint8_t b = ( ( ((uint32_t)in[i]) << 15 ) ^ seed ) >> (15-3);
a &= 7;
b &= 248;
a = 7 & ( a ^ (b << 3));
out[i] = a | b;
seed = (((seed << 7) ^ seed ^ in[i]) + 536513);
}
}
int decode(const void* raw_in, void* raw_out, uint32_t password, size_t len)
{
const uint8_t* in = (const uint8_t*)raw_in;
uint8_t* out = (uint8_t*)raw_out;
uint32_t seed = password ^ 0x55157c65u;
for (size_t i = 0 ; i < len; ++i) {
// 请在此处补全代码
}
}
int main()
{
const uint8_t buf1[] = {0xc3, 0x27, 0x60, 0x33, 0x8f, 0x88, 0xd8, 0xc1, 0x01, 0xd1, 0xd5, 0xa2, 0x9e, 0x5b, 0x57, 0xb7, 0xd0, 0x89, 0xc5, 0x2d, 0x41, 0x91, 0x0d, 0x1c, 0x84, 0x0a, 0xee, 0x32, 0x7a, 0x89, 0xd9, 0x26, 0x25, 0xf0, 0xb3, 0x2c, 0x53, 0x68, 0x8f, 0x5f, 0x23, 0x50, 0xb0, 0xb8, 0xdc, 0x60, 0x15, 0x01, 0xc4, 0xe4, 0x0d, 0x26, 0xc5, 0x7a, 0x11, 0x16, 0xfd, };
uint8_t buf2[100] = {};
const uint32_t password = 0x35bcaac9u;
const size_t len = sizeof(buf1);
decode(buf1, buf2, password, len);
printf("%s\n", buf2);
}
分析编码过程,写出解码,如同加密和解密一样,是一个逆过程。慢慢推敲便可以补上确实代码:
uint8_t a = 7 & in[i];
uint8_t b = 248 & in[i];
b = 31 & ( ( ( (uint32_t)b << 12) ^seed) >> 15);
a = 224 & ( (a << 5) ^ seed);
out[i] = a | b;
seed = ( ( (seed << 7) ^ seed ^ out[i]) + 536513);
程序的运行环境是Linux,编译命令gcc -std=c99 -o code code.c; 这样执行结果居然是乱码!!!然后我就怀疑我的解码程序有问题,我就检查了数小时,实在认为我写的没有错误,然后我就协议几个测试用例进行完整的编码和解码,结果能够正常解码。这就奇怪了!然后,我又查网友的资料,结果查不到,我请大牛同学帮忙,请网上认识的高人。大牛和高人要么是忙,要么直接不摆我,伤心啊。
我一度认为是他们给定的要解码的源数据有问题。我不死心又上了他的在线测试系统,结果还是乱码,纠结!怎么能这样?半小时后又交了白卷。
最后,我终于下定决心,将Linux下的代码移植到Window XP下的VC 6.0上。(我的编程环境还是很全乎的)然后我把代码改成了这样:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#define uint8_t unsigned char
#define uint32_t unsigned int
#define size_t unsigned int
int encode(const void *raw_in, void *raw_out, uint32_t password, size_t len)
{
uint8_t a;
uint8_t b;
const uint8_t *in = (const uint8_t *)raw_in;
uint8_t *out = (uint8_t *)raw_out;
uint32_t seed = password ^ 0x55157c65u;
size_t i;
for (i = 0; i < len; ++i)
{
a = ( in[i] ^ seed) >> 5;
b = ( ( ( (uint32_t)in[i]) << 15) ^ seed) >> (15-3);
a &= 7;
b &= 248;
a = 7 & (a ^ (b << 3));
out[i] = a | b;
seed = ( ( (seed << 7) ^ seed ^ in[i]) + 536513);
}
return 0;
}
int decode(const void *raw_in, void *raw_out, uint32_t password, size_t len)
{
uint8_t a;
uint8_t b;
const uint8_t *in = (const uint8_t *)raw_in;
uint8_t *out = (uint8_t *)raw_out;
uint32_t seed = password ^ 0x55157c65u;
size_t i;
for (i = 0; i < len; ++i)
{
a = 7 & in[i];
b = 248 & in[i];
b = 31 & ( ( ( (uint32_t)b << 12) ^seed) >> 15);
a = 224 & ( (a << 5) ^ seed);
out[i] = a | b;
seed = ( ( (seed << 7) ^ seed ^ out[i]) + 536513);
}
return 0;
}
int main()
{
const uint8_t buf1[] = {0xc3, 0x27, 0x60, 0x33, 0x8f, 0x88, 0xd8, 0xc1, 0x01, 0xd1, 0xd5, 0xa2, 0x9e, 0x5b, 0x57, 0xb7, 0xd0, 0x89, 0xc5, 0x2d, 0x41, 0x91, 0x0d, 0x1c, 0x84, 0x0a, 0xee, 0x32, 0x7a, 0x89, 0xd9, 0x26, 0x25, 0xf0, 0xb3, 0x2c, 0x53, 0x68, 0x8f, 0x5f, 0x23, 0x50, 0xb0, 0xb8, 0xdc, 0x60, 0x15, 0x01, 0xc4, 0xe4, 0x0d, 0x26, 0xc5, 0x7a, 0x11, 0x16, 0xfd, };
uint8_t buf2[100] = {0};
const uint32_t password = 0x35bcaac9u;
const size_t len = sizeof(buf1);
decode(buf1, buf2, password, len);
printf("%s\n", buf2);
return 0;
}
可以对比一下代码的变化,好消息是结果出来了,正是下图:
至此,问题算是源码解决了,然后我花了9分钟进行了第三次在线测试,成功了。至于Linux下为什么显示不出来?暂时还不好说,因为我自己的测试用例正确地执行了,以后再慢慢发现吧。
注:关于Linux/Unix字符<------->Window下字符转化问题,我一向是先考到UltraEdit-32下,然后再考到Window下的其他编程环境下。