小时候听说过三只小猪的故事,隐约记得故事是讲三只小猪用不同方法造房子,对抗老狼。这些天做软件,遇到一个无比简单的问题,但在三种不同的语言中,却有着截然不同的解法。
最近,冷不丁地接到公司下派的一个紧急任务,做手持POS和PC程序之间交换数据的程序。各种各样的麻烦中,有一个小得不起眼的问题,POS机中数据的字
节序和PC相反。这可不算是什么啊。没错,是在太简单了。尽管如此,还是引发了一场争论。做POS程序的,希望PC程序做转换。做PC程序的,希望POS
程序做转换。(谁都想少做点,对吧;))。最终,作为和事佬的我,为了维护和谐的氛围,揽下了这件事。当然,到底在那里做,还是要决定的。最终选择在PC
上,毕竟PC上调试起来容易。(天煞的,这个POS机没有debug,也没有模拟器,显示屏还没我手机的大,做起来着实费事)。
其实,我的本意是想在POS上做这个转换。因为POS用的是C(一个不知什么年代的gcc),可以直接操作字节。基本的代码看起来差不多应该是这样:
unsigned long InvData(unsigned long val, int n) {
unsigned long t=val, res=0;
for(; n >0; n--)
{
res = res << 8;
res |= (unsigned char)t;
t = t >> 8;
}
return res;
}
n是数据类型的字节长度。这里使用了最长的无符号整数类型。这是核心转换函数,各种类型的转换函数都可以从中派生:
long InvDataLong(long val) {
return (long)InvData((unsigned long)val, sizeof(val));
}
short InvDataShort(short val) {
return (short)InvData((unsigned short)val, sizeof(val));
}
...
最后,有一个比较特殊的地方,float。float的编码不同于整型,如果直接用(unsigned
long)强制类型转换,只会把float数值的整数部分赋予参数,得不到正确的结果。正确的做法,应当是把float占用的四个字节直接映射成一个
unsigned long:
float InvDataFloat(float val) {
float val=InvData(*(unsigned long*)(&val), sizeof(val));
return *(float*)(&val);
}
通过将float变量的地址强制转换成unsigned long*类型,然后再dereference成unsigned
long类型。当然还有其他办法,比如memcpy,这里就不多说了。至于double类型,为了简化问题,这里将其忽略。如果有64位的整型,那么
double可以采用类似的解法。否则,就必须写专门的处理函数。
当然,最终我还是使用C#写这个转换。相比之下,C#的转换代码显得更具现代风味。基本算法还是一样:
public static ulong DataInv(ulong val, int n)
{
ulong v1_ = val, v2_ = 0;
for (; n > 0; n--)
{
v2_ <<= 8;
v2_ |= (byte)v1_;
v1_ >>= 8;
}
return v2_;
}
对于习惯于C/C++的同学们注意了,long/ulong在C#中不是4字节,而是8字节。也就是C/C++中的longlong。以这个函数为基础,其它整数类型的字节序转换也就有了:
public static ulong DataInv(ulong val)
{
return DataInv(val, sizeof(ulong));
}
public static uint DataInv(uint val)
{
return (uint)DataInv((ulong)val, sizeof(uint));
}
public static int DataInv(int val)
{
return (int)DataInv((uint)val);
}
...
然而,面对float,出现了麻烦。在C#中,没有指针,无法象C那样将float展开成ulong。(unsafe代码可以执行这类操作,但这不是C#嫡亲的特性,并且是违背C#设计理念的。这里不做考虑)。C#提供了另一种风格的操作:
public static float DataInv(float val)
{
float res_ = 0;
byte[] buf_ = BitConverter.GetBytes(val);
byte t = 0;
t = buf_[0];
buf_[0] = buf_[3];
buf_[3] = t;
t = buf_[1];
buf_[1] = buf_[2];
buf_[2] = t;
res_ = BitConverter.ToSingle(buf_, 0);
return res_;
}
这个做法尽管有些累赘,但道理上很简单:把float变量转换成一个字节流,然后把相应的位置对调,就获得了字节反序的float。相比C的float转
换,C#明显不够简练。原因很简单,C#根本不是用来干这个的。C是一种非常底层的语言,它的内存模型是完全直观的,与硬件系统相对应的。因而,对于这种
与机器相关的操作,当然也显得游刃有余。而C#定位于高层开发的高级语言,底层的内存模型是被屏蔽的,程序员无需知道和关心。
不过,C#的代码却拥有它的优势。只需看一眼这些函数的使用代码,便不言自明了:
//C代码
int x=234;
float y=789.89;
short z=332;
x=InvDataInt(x);
y=InvDataFloat(y);
z=InvDataShort(z);
//C#代码
int x=234;
float y=789.89;
short z=332;
x=DataInv(x);
y=DataInv(y);
z=DataInv(z);
在C代码中,对于不同的类型,需要使用不同命名的函数。而在C#代码中,则只需使用DataInv这样一个函数名。至于届时选用那个版本的函数,编译器会
根据实际的类型自动匹配。C#运用函数重载这个特性,使得调用代码可以采用统一的形式。即便是数据的类型有所变化,也无需对调用代码做任何修改。(这在我
的开发过程中的得到了验证,传输数据的成员类型曾经发生变化,我也只是修改了数据结构的定义,便将问题搞定)。这一点,在C中是无法做到的。
归结起来,C由于侧重于底层,在数据转换方便的灵活性,使得转换代码的构建更加容易。而C#则得益于函数重载,在转换代码使用方面,有独到的优势。
迄今为止,三只小猪中,还只有两只出现。下面就要第三只出场了。
作为C++的粉丝,我会自然而然地想到使用C++来实现这个转换功能。于是便有了如下的代码:
unsigned long InvData(unsigned long val, int n) {
unsigned long t=val, res=0;
for(; n >0; n--)
{
res = res << 8;
res |= (unsigned char)t;
t = t >> 8;
}
}
long InvData(long val) {
return (long)InvData((unsigned long)val, sizeof(val));
}
short InvData(short val) {
return (short)InvData((unsigned short)val, sizeof(val));
}
...
float InvData(float val) {
float val=InvData(*(unsigned long*)(&val), sizeof(val));
return *(float*)(&val);
}
这些代码就好象是C和C#代码的杂交后代。既有C的底层操作,也有C#的函数重载,兼有两者的优点。
不过,还能做得更好:
template<typename T>
T InvData(T val) {
T t=val, res=0;
int n=sizeof(T);
for(; n >0; n--)
{
res = res << 8;
res |= (unsigned char)t;
t = t >> 8;
}
return (T)res;
}
这样,就把所有的整型都一网打尽了,仅用一个函数模板,便完成了原先诸多函数所做的工作。而float版本的函数则保持不变,作为InvData()的一个重载。按照C++的函数模板-重载规则,float版的函数重载将被优先使用。
好了,三只小猪的故事讲完了。前两只小猪各有优点,也各有缺点。而第三只小猪则杂合和前两者的优点,并且具有更大的进步。尽管第三只小猪存在各种各样的缺陷,但毕竟它的众多特性为我们带来了很多效率和方便,这些还是应当值得肯定的。
附:第三只小猪的其他手段:
1、强制转换成字符串数组
template<typename T>
T InvData1(T v) {
unsigned char* pVal1=(unsigned char*)(&v)
, *pVal2=pVal1+sizeof(T)-1, t;
while(pVal2-pVal1>1)
{
t=*pVal2;
*pVal2=*pVal1;
*pVal1=t;
pVal1++;
pVal2--;
}
return v;
}
2、使用标准库,blog上有人留言建议的
template<typename T>
T InvData(T v) {
unsigned char* pVal=(unsigned char*)(&v);
size_t n=sizeof(T);
std::reverse(pVal, pVal+n, pVal);
}
3、使用traits
template<size_t n> struct SameSizeInt;
template<> struct SameSizeInt<1> { typedef unsigned char Type; };
template<> struct SameSizeInt<2> { typedef unsigned short Type; };
template<> struct SameSizeInt<4> { typedef unsigned long Type; };
template<> struct SameSizeInt<8> { typedef unsigned longlong Type; };
template<typename T>
T InvData(T v) {
size_t n=sizeof(T);
typedef SameSizeInt<sizeof(T)>::Type NewT;
NewT v1=*(NewT*)(&v), v2=0;
for(; n >0; n--)
{
v2= v2<< 8;
v2|= (unsigned char)v1;
v1 = v1 >> 8;
}
return *(T*)(&v2);
}
甚至可以使用tmp去掉其中的循环。在C++中,
<wbr>这类任务的实现方法,完全看程序员的想象力了。:)</wbr>
相关推荐
《三只小猪》是一则深受儿童喜爱的经典故事,它在中小学教育中扮演着重要的角色。这个故事通过简单的情节和鲜明的角色,传递了关于勤劳、智慧和安全的重要理念,对于中班的孩子们来说,是进行早期阅读、语言理解和...
三只小猪.pdf
《三只小猪》是一个经典的儿童故事,常用于教育孩子们关于努力、聪明和坚韧的重要性。在这个故事中,猪妈妈让她的三个孩子——呼呼、噜噜和嘟嘟各自建造一间房子,以此学习新技能。故事的主角是这三只小猪,每一只都...
《三只小猪》是一部经典的童话故事,常被用于儿童教育和戏剧表演。这个剧本讲述了三只小猪离开妈妈独立生活的故事,通过他们的经历教导孩子们关于责任、智慧和团队合作的重要性。 1. 角色设定: - 猪大哥:贪玩、...
三只小猪与容器的故事.pdf
非常漂亮的三只小猪Flash钟表,含声音,每走一秒三只小猪依次会有不同的动作.
三只小猪的故事PPT模板.ppt
小学数学数墙与三只小猪PPT教案.pptx
小学英语一年级drama《三只小猪》剧本——英语剧本.pdf
《儿童故事大全三只小猪》是一篇深受儿童喜爱的经典故事,它蕴含着丰富的教育意义。故事讲述了三只小猪兄弟各自建造房子的过程,以及如何智斗大野狼的冒险经历。这个故事不仅富有趣味性,而且在寓教于乐中传递了多个...
1. 教育方法:此文档描述了一个幼儿教育活动,利用故事《三只小猪》作为教学素材,旨在让孩子们通过角色扮演学习规则和合作,这展示了寓教于乐的教学理念。 2. 幼儿教育目标:活动目标包括激发孩子参与表演的兴趣,...
《三只小猪的故事》是一篇寓言性质的作文,以动物的形象来传达深刻的人生道理。故事中的主角——尹尹、沙沙和毅毅,起初是猪猪欢乐学园中的“犯罪三猪组”,他们不守纪律,经常抄袭作业、打架、骂人,甚至欺凌其他...
3. 社会性发展:通过《三只小猪上幼儿园》的故事,幼儿可以学习到如何与人交往,比如使用礼貌用语,以及如何在集体中互动和合作。 4. 规则与常规学习:活动过程中,教师通过故事引导幼儿理解和遵守幼儿园的规则,如...
《三只小猪造高楼》是一个中班数学活动,旨在通过趣味性的故事引导孩子们学习比较和构造的概念。在这个活动中,孩子们将使用积木进行实践,理解建筑物高度的变化以及稳定性的重要性。 1. **比较与测量**:活动的...
【童话剧三只小猪盖房子教案】是一个教育戏剧的教学方案,主要分为三个课时进行。教育戏剧是一种融合教育和戏剧元素的活动,旨在通过戏剧形式提升学生的学习兴趣,培养他们的表演技巧和团队协作能力。 **第一课时:...
《三只小猪》的故事,虽然看似简单,但其中蕴含的深意却值得我们深入探讨。这个故事以寓言的形式,向我们传达了许多重要的生活智慧和价值观,尤其对于IT行业的发展,同样有着深刻的启示。 首先,故事中的三只小猪...
《三只小猪》找词语游戏是针对小学初中阶段少儿英语教学的一种有趣且富有教育意义的活动。这个游戏设计旨在帮助孩子们提高词汇记忆、拼写能力和英语兴趣,同时增强他们的观察力和逻辑思维能力。通过寻找隐藏在混乱...
【大班美术活动教案:三只小猪造房教案(附教学反思)】 在幼儿教育领域,美术活动是激发孩子创造力、想象力和动手能力的重要手段。以“三只小猪造房”为题材的美术教案,旨在通过孩子们熟悉的故事背景,引导他们进行...
幼儿园中班绘本课件:三只小猪().ppt
这篇故事虽然名为“(中小学教育)三只小猪的故事”,但它蕴含的教育意义远远超出了单纯的故事范畴。这个故事在中小学教育中常被用来教授孩子们关于努力、责任、创新和安全的重要价值。 首先,故事强调了成长与独立...