当前位置: 首页 > 工具软件 > MikroKopter > 使用案例 >

Mikrokopter MK 代码分析1

叶书
2023-12-01

1.可变参数va_list的使用

先来个简单的例子:

 

#include <stdio.h>

#include <stdarg.h>

int sum(int num,...);

int sum(int num,...)

  int result = 0;

  va_list argptr;

  va_start(argptr, num);

  while(num--)

 { printf("%s ",va_arg(argptr, char *));}

 va_end(argptr);

 return result;

}

int main()

{

 sum(3, "hello", "world", "!");       

 // output: hello world !

 return 0;

 

    可变参数中个数不定;可变参数中的每个参数的类型可以不同;可变参数的每个参数并没有实际的名称与之相对应,用起来是很灵活。可变参数是由宏实现的,但是由于硬件平台的不同,编译器的不同,宏的定义也不相同,下面是VC6.0x86平台的定义: 

typedef char * va_list;      // TC中定义为void*

#define _INTSIZEOF(n)    ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) 

//为了满足需要内存对齐的系统

#define va_start(ap,v)    ( ap = (va_list)&v + _INTSIZEOF(v) ) 

#define va_arg(ap,t)       ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) 

#define va_end(ap)  ( ap = (va_list)0 ) 

C语言的函数形参是从右向左压入堆栈的,以保证栈顶是第一个参数,而且x86平台内存分配顺序是从高地址到低地址。因此函数fun(int var1,int var2,...,int varN)内存分配大致上是这样的:(可变参数在中间)

栈区:

|栈顶             低地址

|第一个参数var1   <-- &v

|第二个参数var2   <-- va_start(ap,v)ap指向地址       

|...

|函数的最后varN

|...

|函数的返回地址

|...

|栈底    高地址

va_start(ap,v)ap = (va_list)&v + _INTSIZEOF(v)指向第二个参数地址调用va_arg(ap,t)( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )取出当前ap指针所指的值,并使ap指向下一个参数 

2.循环冗余校验

·循环校验码:英文cyclic redundancy check的简称,是数据通信领域中最常用的一种高效差错校验码,其特征是信息字段和校验字段的长度可以任意选定。

·生成CRC的基本原理:任意一个由二进制位串组成的代码都可以和一个系数仅为‘0’‘1’取值的多项式一一对应。例如:代码1010111对应的多项式为x6+x4+x2+x+1,而多项式为x5+x3+x2+x+1对应的代码101111

·CRC码集选择的原则:若设码字长度为N,信息字段为K位,校验字段为R(N=K+R),则对于CRC码集中的任一码字,存在且仅存在一个R次多项式g(x),使得V(x)=A(x)g(x)=xRm(x)+r(x)其中,m(x)K次信息多项式,r(x)R-1次校验多项式,g(x)称为生成多项式:g(x)=g0+g1x+g2x2+...+g(R-1)x(R-1)+gRxR。发送方通过指定的g(x)产生CRC码字,接收方则通过该g(x)来验证收到的CRC码字。 

·CRC校验码计算过程:借助于多项式除法,其余数为校验字段。例如:信息字段代码为: 1011001;对应m(x)=x6+x4+x3+1,假设生成多项式为:g(x)=x4+x3+1;则对应g(x)的代码为: 11001x4m(x)=x10+x8+x7+x4对应的代码记为:10110010000;采用多项式除法得余数为: 1010。这里的除法没有数学上的含义,而是采用计算机的模二除法,即除数和被除数做异或运算。进行异或运算时除数和被除数最高位对齐,按位异或。发送方:发出的传输字段为:  10110011010 信息字段校验字段接收方:使用相同的生成码进行校验:接收到的字段/生成码(二进制除法)如果能够除尽,则正确。 

·常用CRC校验多项式:常用的CRC码是,CRC-CCITTCRC-16,它们的生成多项式分别是:CRC-CCITT=x^16+x^12+x^5+1 CRC-16=x^16+x^15+x^2+1CRC-16例程: 

 

uint crc_16(uchar *ptr,uchar len)

{  uint crc = 0;

  uchar i;

  while(len--)

  {  for(i=0x80; i!=0; i>>=1)

    { if((crc&0x8000)!=0)

      {  crc<<=1;        

crc^=0x1021; }

      else

        crc<<=1;

      if((*ptr&i)!=0)

        crc^=0x1021; }

            ptr++;}

            return(crc); }

 

3. Base64编码

各位看官应该都是资深的网虫了,小弟斗胆在此问问大家,平时上网时,除了泡MM、到论坛灌水、扔版砖……之外,进行的最多的是什么活动?对了,你一定会说:是收发电子邮件!(谁敢说自己没收/发过电子邮件的?拉出去枪毙了!!)  

/E-mail的时候有一个安全性的问题——假想一下,你花了一整天时间给系花写的情书,在发送的过程中被隔壁宿舍张三那小子截获了(难道他是黑客??),更糟的是他是你的情敌啊……天,后果不堪设想!!因此,我们必须有一种比较可靠的加密方法,能够对电子邮件的明文进行转换,至少要得出一个无法被别人一眼就看出内容来的东西,而且编码/解码的速度还要足够快。(这时你可以再假想一下啦,张三那家伙截获了你的肉麻情书,可是他一看:咦?怎么乱七八糟的?垃圾邮件!!”——这样一来你不就逃过大难了?!)
Base64就是在这种背景下产生的加密方法。它的特点是:1、速度非常快。2、能够将字符串A转换成字符串B,而且如果你光看字符串B,是绝对猜不出字符串A的内容来的。不信吗?让我们来看看下面这串东西:xOO6w6Osu7bTrbniwdnAz8LetcTnzbfXzOy12KOh
呵呵,是什么啊?猜出来了吗?其实它就是下面这段文字经过Base64编码产生的东东:
你好,欢迎光临老罗的缤纷天地!介绍说完啦,让我们开始探讨实质性的东西。
Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,大家可以查看RFC2045RFC2049,上面有MIME的详细规范。
Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3
这样说会不会太抽象了?不怕,我们来看一个例子:

转换前

aaaaaabb

ccccdddd

eeffffff

转换后

00aaaaaa

00bbcccc

00ddddee

00ffffff

应该很清楚了吧?上面的三个字节是原文,下面的四个字节是转换后的Base64编码,其前两位均为0。转换后,我们用一个码表来得到我们想要的字符串(也就是最终的Base64编码),这个表是这样的:(摘自RFC2045
                            Table 1: The Base64 Alphabet
      Value Encoding  Value Encoding  Value Encoding  Value Encoding
           0 A            17 R            34 i            51 z
           1 B            18 S            35 j            52 0
           2 C            19 T            36 k            53 1
           3 D            20 U            37 l            54 2
           4 E            21 V            38 m            55 3
           5 F            22 W            39 n            56 4
           6 G            23 X            40 o            57 5
           7 H            24 Y            41 p            58 6
           8 I            25 Z            42 q            59 7
           9 J            26 a            43 r            60 8
          10 K            27 b            44 s            61 9
          11 L            28 c            45 t            62 +
          12 M            29 d            46 u            63 /
          13 N            30 e            47 v
          14 O            31 f            48 w           (pad) =
          15 P            32 g            49 x
          16 Q            33 h            50 y
解码只是编码的逆过程,在此我就不多说了,另外有关MIMERFC还是有很多的,如果需要详细情况请自行查找。
用更接近于编程的思维来说,编码的过程是这样的:第一个字符通过右移2位获得第一个目标字符的Base64表位置,根据这个数值取到表上相应的字符,就是第一个目标字符。
然后将第一个字符左移4位加上第二个字符右移4位,即获得第二个目标字符。再将第二个字符左移2位加上第三个字符右移6位,获得第三个目标字符。最后取第三个字符的右6位即获得第四个目标字符。在以上的每一个步骤之后,再把结果与 0x3F 进行 AND 位操作,就可以得到编码后的字符了。(感谢 Athena 指出以上描述中原有的一些错误!^_^
So easy! That’s all!!!
可是等等……聪明的你可能会问到,原文的字节数量应该是3的倍数啊,如果这个条件不能满足的话,那该怎么办呢?
我们的解决办法是这样的:原文的字节不够的地方可以用全0来补足,转换时Base64编码用=号来代替。这就是为什么有些Base64编码会以一个或两个等号结束的原因,但等号最多只有两个。因为:
余数 原文字节数 MOD 3
所以余数任何情况下都只可能是012这三个数中的一个。如果余数是0的话,就表示原文字节数正好是3的倍数(最理想的情况啦)。如果是1的话,为了让Base64编码是4的倍数,就要补2个等号;同理,如果是2的话,就要补1个等号。 讲到这里,大伙儿应该全明白了吧?如果还有不清楚的话就返回去再仔细看看,其实不难理解的。

 类似资料: