一文搞懂Base64编码原理

Base64是最常见的用于传输8Bit字节码的编码方式之一,它是一种基于64个可打印字符来表示二进制数据的方法。

Base64是什么

Base64编码,是由64个字符组成编码集:26个大写字母AZ,26个小写字母az,10个数字0~9,符号“+”与符号“/”。Base64编码的基本思路是将原始数据的三个字节拆分转化为四个字节,然后根据Base64的对应表,得到对应的编码数据。

当原始数据凑不够三个字节时,编码结果中会使用额外的**符号“=”**来表示这种情况。

Base64编码表

码值字符码值字符码值字符码值字符
0A16Q32g48w
1B17R33h49x
2C18S34i50y
3D19T35j51z
4E20U36k520
5F21V37l531
6G22W38m542
7H23X39n553
8I24Y40o564
9J25Z41p575
10K26a42q586
11L27b43r597
12M28c44s608
13N29d45t619
14O30e46u62+
15P31f47v63/

Base64编码步骤

  • 将原始数据按照每三个字节作为一组进行划分,每组一共是24个二进制位。
  • 再将这24个二进制位,每6个一划分,分为四组(6×4=24个二进制位)。
  • 然后在每组前面补上00,扩展成8×4=32个二进制位,即四个字节(因为每个字节前面有2个0,所以每个字节的最大值是63)。
  • 最后根据Base64编码表,将这四个字节的码值,转换为对应的Base64的字符即可。

Base64编码过程举例

情况1:正常的3个字节编码

将单词“PCB”转换为Base64编码:

  • “P”、“C”、"B"的ASCII值分别是80、67、66,对应的二进制值是0101 0000、0100 0011、0100 0010,将它们连成一个24位的二进制字符串010100000100001101000010。

  • 将这个24位的二进制字符串,每6个一组分成4组:010100、000100、001101、000010。

  • 在每组前面加两个00,扩展成32个二进制位,即四个字节:00010100、00000100、00001101、00000010。它们的十进制值分别是19、22、5、46。(最前面加上两个0只是为了凑成一个字节,实际上其本身的数值是没有变化的)

  • 根据上表,得到每个值对应Base64编码,即U、E、N、C。

情况2:剩余2个字节编码

对于2个字节(16个二进制数)的情况,比如将“PC”转换为Base64编码:

转换方法同上,区别在于:

  • 16个二进制数,每6个一组分割,最后剩余4个,这时再在后面补两个0凑成6个。
  • 然后还按照基础的方法转换,最后补一个“=”即可

转换过程如下表,最终将“PC”转换为了“UEM=”

情况3:剩余1个字节编码

对于12个字节(8个二进制数)的情况,比如将“P”转换为Base64编码:

转换方法同上,区别在于:

  • 16个二进制数,每6个一组分割,最后剩余2个,后面要再补4个0
  • 然后还按照基础的方法转换,最后补两个“=”即可

转换过程如下表,最终将“P”转换为了“UA==”

Base64编解码C程序

编码程序

编码的程序设计思路,就是按照上面讲解的编码过程,每3个原始字符为一组,进行编码,得到4个base64的字符。对于不够3个字符的情况,编码的base64的字符后面补上一到两个=号。

#include <stdio.h>
#include <string.h>

/*base64符号表*/
const char *base64Arr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/*base64增补符号*/ 
const char paddingChar = '=';

/** @func:  base64_encode
*   @brief: base64编码 
*   @para:  [srcData]:要进行编码的原始数据
*           [resBase64]:base64编码结果 
*   @return:none
*/
void base64_encode(const unsigned char * srcData, char * resBase64)
{
    int i=0; /*原始数据索引*/ 
	int j=0; /*base64结果索引*/ 
    unsigned char transIdx=0;    // 索引是8位,但是高两位都为0
    const int srcLen = strlen((const char*)srcData);
    
    /*每3个一组,进行编码*/
    for(i=0; i < srcLen; i+=3) 
	{
        /*取出第1个字符的高6位*/ 
        transIdx = ((srcData[i] >> 2) & 0x3f); /*0011 1111*/
        /*查表*/ 
        resBase64[j++] = base64Arr[(int)transIdx];
        
        /*取出第1个字符的低2位*/ 
        transIdx = ((srcData[i] << 4) & 0x30); /*0011 0000*/
        
        /*第1个字符后面还有字符*/ 
        if (i + 1 < srcLen) 
		{
			/*取出第2个字符的高4位,并与第1个字符的低2位进行组合*/ 
            transIdx |= ((srcData[i + 1] >> 4) & 0x0f); /*0000 1111*/
            /*查表*/ 
            resBase64[j++] = base64Arr[(int)transIdx];
        }
		else /*第1个字符后面没有字符了*/
		{
			/*直接使用第1个字符的低2位查表*/
            resBase64[j++] = base64Arr[(int)transIdx];
            
            /*然后补上两个=号*/ 
            resBase64[j++] = paddingChar;
            resBase64[j++] = paddingChar;
            break;   /*没有数据了,break结束*/ 
        }
        
        /*取出第2个字符的低4位*/ 
        transIdx = ((srcData[i + 1] << 2) & 0x3c); /*0011 1100*/
        
        /*第2个字符后面还有字符*/ 
        if (i + 2 < srcLen)
		{ 
		    /*取出第3个字符的高2位,并与第2个字符的低4位进行组合*/ 
            transIdx |= ((srcData[i + 2] >> 6) & 0x03);  /*0000 0011*/
            /*查表*/ 
            resBase64[j++] = base64Arr[(int)transIdx];
            
            /*取出第3个字符的低6位*/ 
            transIdx = srcData[i + 2] & 0x3f; /*0011 1111*/ 
            /*查表*/ 
            resBase64[j++] = base64Arr[(int)transIdx];
        }
        else /*第2个字符后面没有字符了*/
		{
			/*直接使用第2个字符的低4位查表*/
            resBase64[j++] = base64Arr[(int)transIdx];
            
            /*然后补上一个=号*/ 
            resBase64[j++] = paddingChar;
            break;  /*没有数据了,break结束*/ 
        }
    }
    
    /*结束符*/ 
    resBase64[j] = '\0'; 
}

解码程序

解码的程序设计思路,其实就是编码的反过程,把要解码的base64符号,每4个为一组,译码成3个字符。对于最后出现的=的情况,就说明是要结束了,直接使用剩余的base64符号进行译码,然后就结束了。

/** @func:  idx_in_base64Arr
*   @brief: 在base64符号表中查找字符c对应的索引值
*   @para:  [c]:要查找的字符
*   @return:字符c在base64符号表中对应的索引值(0~63) 
*/
int idx_in_base64Arr(char c) 
{
	/*在base64表中搜索第一次出现字符c的位置*/
    const char *pIdx = strchr(base64Arr, c);
    if (NULL == pIdx)
	{
		/*找不到对应的base64字符,说明输入的base64字符串有误*/ 
        return -1;
    }
    
    /*返回字符c在base64表中的位置*/
    return (pIdx - base64Arr);
}   

/** @func:  base64_decode
*   @brief: base64解码 
*   @para:  [srcBase64]:要进行解码的原始base64数据
*           [resData]:解码出的结果 
*   @return:none
*/
void base64_decode(const char *srcBase64, unsigned char *resData)
{
    int i = 0; /*原始base64数据索引*/ 
	int j = 0; /*解码后的结果数据索引*/ 
    int trans[4] = {0,0,0,0}; /*4个base64符号对应的表中的位置(0~63的数字)转换值*/ 
    
    /*base64符号每4个一组,译码成3个字符*/
    for (i=0; srcBase64[i]!='\0'; i+=4)
	{
		/*------译码第1个字符------*/
		/*前2个base64符号在表中的位置(0~63的数字)*/
        trans[0] = idx_in_base64Arr(srcBase64[i]);
        trans[1] = idx_in_base64Arr(srcBase64[i+1]);
        
		/*第1个符号的后6位,与第2个符号的6、5位,译出第1个字符*/ 
        resData[j++] = ((trans[0] << 2) & 0xfc) | ((trans[1]>>4) & 0x03); /*1111 1100   0000 0011 */ 

        /*------译码第2个字符------*/  
        /*第3个base64符号是否是=号*/
        if (srcBase64[i+2] != '=')
		{
			/*第3个base64符号在表中的位置(0~63的数字)*/
            trans[2] = idx_in_base64Arr(srcBase64[i + 2]);
        }
        else
		{
            break;/*没有数据了,break结束*/ 
        }
        /*第2个符号的后4位,与第3个符号的6、5、4、3位,译出第2个字符*/ 
        resData[j++] = ((trans[1] << 4) & 0xf0) | ((trans[2] >> 2) & 0x0f); /*1111 0000  0000 1111*/
  
        /*------译码第3个字符------*/
        /*第4个base64符号是否是=号*/
        if (srcBase64[i + 3] != '=')
		{
			/*第4个base64符号在表中的位置(0~63的数字)*/
			trans[3] = idx_in_base64Arr(srcBase64[i + 3]);
        }
        else
		{
            break;/*没有数据了,break结束*/ 
        }
        /*第3个符号的后2位,与第4个符号的后6位,译出第3个字符*/ 
        resData[j++] = ((trans[2] << 6) & 0xc0) | (trans[3] & 0x3f); /*1100 0000   0011 1111*/ 
    }
  
    /*结束符*/ 
    resData[j] = '\0';
}

测试程序

使用字符串“PCB”进行base64编码测试,然后再将编码得到的结果,进行解码测试。

/*测试*/
int main()
{
	/*定义要进行base64编码的字符串*/ 
    const unsigned char *srcData = "PCB" ;
    
    /*先测试编码*/
    char base64[128];
    base64_encode(srcData, base64);  
    printf("base64编码:%s\n",base64);

    /*再测试解码*/ 
    char resData[128];
    base64_decode(base64, (unsigned char*)resData);
    printf("base64解码:%s", resData);

    return 0;
}

输出结果如下,可以看出,“PCB”进行base64编码,得到了“UENC”,然后再反向解码,又得到了“PCB”

base64编码:UENC
base64解码:PCB
--------------------------------
Process exited after 0.01123 seconds with return value 0
请按任意键继续. . .

完整程序可从我的gitee仓库下载:
https://gitee.com/xxpcb/c-test/tree/master/C-Base64-Test

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: PMSM电机是三相无刷直流电机,它的转子由永磁体构成。PMSM电机的控制主要包括三个环:速度环、电流环和位置环。 在速度环控制中,通过测量电机的实际转速与指令转速的差值来计算出控制器需要提供的转矩大小。其中,电机的实际转速可以通过编码器或霍尔传感器测量,指令转速可以由用户通过控制系统设定。然后通过调节电机的电流大小来控制电机输出的转矩大小,让实际转速逐渐趋近于指令转速。 在电流环控制中,根据速度环控制输出的控制量,控制器需要通过PI控制器调节电机的电流大小,来实现对电机输出转矩的控制。 在位置环控制中,通过测量电机转子的位置信息,反馈到控制器中,用来控制电机输出转矩的相位和大小。 总的来说,PMSM电机的控制原理就是通过控制器对电机的速度、电流和位置进行调节控制,实现对电机输出的转矩大小和相位的掌控,从而达到精准控制电机转速和运动轨迹的目的。 ### 回答2: 永磁同步电机(PMSM)是一种高效的电机类型,它的控制技术在近年来得到了广泛应用。其核心控制原理是通过控制电机的电流来实现对转矩和速度的精准控制。在PMSM的控制过程中,需要使用矢量控制技术以及逆变器来实现电机的驱动。 在矢量控制技术中,通过将电机控制转变为D轴和Q轴的电流控制,来实现对电机的控制。通过控制D轴和Q轴的电流,可以实现精准的转矩和角速度控制。此外,逆变器通常是用于将直流电源转换为交流电源,以便提供给PMSM所需的电力。逆变器通常使用PWM(脉宽调制)来控制输出电压,并使电机产生所需要的转矩和速度。 在实际应用中,矢量控制技术和逆变器经常和PID控制器等控制策略组合使用。PID控制器可用于改进控制电机转速,电流和位置的性能。 总之,PMSM电机控制原理涉及矢量控制技术和逆变器的使用。用这种技术实现对PMSM电机的精准控制,并结合PID控制器等控制策略,PMSM电机得到了广泛的应用。 ### 回答3: PMSM电机(Permanet Magnet Synchronous Motor,永磁同步电机)是一种使用永磁体作为转子的同步电机,具有高效率、高功率密度和稳定性好的特点,因而在现代工业生产中广泛使用。其控制原理是通过控制电机的电流和电压来实现转子和电磁场之间的同步。 PMSM电机的控制需求可以分为速度控制、转矩控制和位置控制三个方面。速度控制可以通过控制电机供电频率和电压来实现,同时需要对电流进行监测以保持电机运行的稳定性。转矩控制则需要根据机械负载调节电机转矩以达到所需的工作效果。位置控制则需要通过对电机转子位置进行反馈控制,使得电机能够准确地按照所需位置运转。 在PMSM电机控制中,使用了电机反馈控制系统和电机控制器。反馈控制系统通过传感器实时监测电机运转的转速、转矩和位置等参数,并将这些参数实时反馈给电机控制器。电机控制器根据反馈的参数来控制电机的电流和电压,实现对电机的控制。同时在电机控制中,还需要对电流进行磁场定向控制,以确保电机的正常运行。 总之,PMSM电机控制原理是通过对电机的电流、电压和位置等参数进行实时控制和反馈,以实现电机转子和电磁场之间的同步,从而实现电机的稳定运行和精确控制。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值