概述
C语言的的DLL是一个很好用的东西,很多过程以及实现都可以自己控制,很多语言也都支持DLL动态链接库的读取和使用,最近接触了下,让我对算法有了更深的理解。
语言环境
- C语言,32位和64位可根据自己需求在编辑器上进行选择
- 这里使用的DEV C++可发工具
- 头文件:
#include “dll.h”
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <string.h>
#include <wchar.h>
#include <assert.h>
#include <locale.h>
功能说明
- base64编码常用于数据数据传输过程,可作为图片或者其他数据的字节流传输形式,通过转码和解码,也在一定程度上保证了信息的安全和不可见,另外以字符形式存储避免了中文传输问题;后文提供转码和解码的详细逻辑和注释。
- utf-8是一种编码格式,使用很广泛,我是在某个API接口服务使用时用到的;后文给出其与Unicode编码的互转逻辑
实现代码
函数:Base64与字符串互转
/**
字符串转base64码 编码
**/
__declspec(dllexport) unsigned char* __stdcall StrBase64(unsigned char *str)
{
//定义base64编码表
unsigned char *base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
long len; //转换后字符串长度
long str_len; //转换前字符长度
unsigned char *out; //转换后字符串
int i,j; //角标序号 i:转换前字符串 j:转换后字符串
//计算字符串长度 转换前
str_len = strlen(str);
//计算字符串长度 转换后
len = ((str_len + 2) / 3) * 4 ;
//定义动态字符数组用于存放base64码
out = (unsigned char *)malloc(sizeof(unsigned char)*len+1);
//录入末尾结束符
out[len] = '\0';
//字符串转base64码 3*8 = 4*6
for(i=0,j=0;j<len-2;i+=3,j+=4){
out[j] = base64_table[str[i]>>2];//第一个
out[j+1] = base64_table[((str[i]&0x3)<<4) | (str[i+1]>>4)];//第二个
out[j+2] = base64_table[((str[i+1]&0xf)<<2) | (str[i+2]>>6)];//第三个
out[j+3] = base64_table[str[i+2]&0x3f];//第四个
}
//补充不足字符,依据字符串除以3取余的情况赋值
switch(str_len % 3)
{
case 1:
out[j-2]='=';
out[j-1]='=';
break;
case 2:
out[j-1]='=';
break;
}
return out;
}
/**
base64码转字符串 解码
**/
DLLIMPORT unsigned char* __stdcall Base64Str(unsigned char *base)
{
//转码规则 base64码字符对应ASCII的二进制-十进制以确定位置然后取到base64编码规范中对应的value值以还原初始字符串对应二进制-十进制值
//base64--ASCII(十进制值)--原始数据(十进制值) 共123个值,122-z最后一个
int table[]={
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0,
0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51
};
long base_len;//base64字符串长度
long str_len;//原始字符串长度
unsigned char *str;//原始字符串
int i,j;//角标序号 i:原始字符串 j:base64字符串
//计算base64字符串长度
base_len = strlen(base);
//判断"="字符的个数,以确定原字符串长度
if(strstr(base,"==")){
str_len = (base_len/4)*3 - 2;
} else if(strstr(base,"=")) {
str_len = (base_len/4)*3 - 1;
} else {
str_len = (base_len/4) * 3;
}
//定义动态字符数组用于存放base64码
str = (unsigned char *)malloc(sizeof(unsigned char)*str_len+1);
//录入末尾结束符
str[str_len]='\0';
//4*6 = 3*8 解码
for(i=0,j=0;j<base_len-2;i+=3,j+=4){
str[i] = ((table[base[j]]<<2) | (table[base[j+1]]>>4));//第一个值,ASCII十进制对应的图像符号
str[i+1] = ((table[base[j+1]]<<4) | (table[base[j+2]]>>2));//第二个值
str[i+2] = ((table[base[j+2]]<<6) | (table[base[j+3]]));//第三个值
}
return str;
}
函数:UTF-8编码格式转换
/**
ACSII转utf-8的内部方法,供其他方法函数调用
**/
int AsciToUtf8(char* pSrc, char* pBuffer, unsigned int nBufferLen)
{
assert(pSrc != NULL);
unsigned int nSrcLen = lstrlen(pSrc) + 1;
int nRet = 0;
int nUtf16Len = MultiByteToWideChar(CP_ACP, 0, pSrc, nSrcLen, NULL, 0);
if(nUtf16Len > 0)
{
wchar_t* pW ;//= new wchar_t[nUtf16Len];
pW = (wchar_t*)malloc(sizeof(wchar_t*)*nUtf16Len);
if(pW != NULL)
{
nUtf16Len = MultiByteToWideChar(CP_ACP, 0, pSrc, nSrcLen, pW, nUtf16Len);
if(pBuffer == NULL || nBufferLen <= 0)
{
nRet = WideCharToMultiByte(CP_UTF8, 0, pW, nUtf16Len, NULL, 0, NULL, NULL);
}
else
{
nRet = WideCharToMultiByte(CP_UTF8, 0, pW, nUtf16Len, pBuffer, nBufferLen, NULL, NULL);
}
free(pW);
pW = NULL;
}
}
return nRet;
}
/**
ASCII码转UTF-8
**/
DLLIMPORT unsigned char* __stdcall AscIIOrUtf(unsigned char *acs){
int nLen = lstrlen(acs) + 1; //
int nBufferLen = AsciToUtf8(acs, NULL, 0);
char* pBuffer;
pBuffer = (char*)malloc(sizeof(char*)*nBufferLen);
AsciToUtf8(acs,pBuffer, nBufferLen);
return pBuffer;
}
/**
utf-8转ASCII或者Unicode编码
**/
DLLIMPORT unsigned char* __stdcall Utf8ToAsci(unsigned char* pSrc)
{
setlocale(LC_ALL, "");
assert(pSrc != NULL);
int wcsLen = MultiByteToWideChar(CP_UTF8, 0, pSrc, strlen(pSrc), NULL, 0);
wchar_t* ph ;
ph = (wchar_t*)malloc(sizeof(wchar_t*)*wcsLen+1);
MultiByteToWideChar(CP_UTF8, 0, pSrc, strlen(pSrc), ph, wcsLen);//此处已经转换过来了
ph[wcsLen] = '\0';
unsigned char* pBuffer;
int len = strlen(pSrc);//此处使用该长度是为了防治数据溢出的异常,会比实际有效字符长度略大,汉子越多差距越大
pBuffer = (unsigned char*)malloc(sizeof(unsigned char*)*len + 1);
//pBuffer[len] = '\0';//可加可不加,因为在后面赋值时'\0'结束符同样会赋值给pBuffer
//wcstombs(pBuffer,ph,strlen(pSrc));
sprintf(pBuffer, "%ls", ph);//ls或S
//最终pBuffer的有效长度等于实际长度
free(ph);//释放
return pBuffer;
}
函数:生成随机数,同UUID随机数,32个字符
/**
生成随机数UUID
**/
DLLIMPORT unsigned char* __stdcall UUIDStr(){
unsigned char *buf;
buf = (unsigned char *)malloc(sizeof(unsigned char)*36+1);
buf[36] = '\0';
const char *c = "89ab";
char *p = buf;
int n;
for( n = 0; n < 16; ++n )
{
int b = rand()%255;
switch( n )
{
case 6:
sprintf(
p,
"4%x",
b%15 );
break;
case 8:
sprintf(
p,
"%c%x",
c[rand()%strlen( c )],
b%15 );
break;
default:
sprintf(
p,
"%02x",
b );
break;
}
p += 2;
switch( n )
{
case 3:
case 5:
case 7:
case 9:
//*p++ = '-';//这时buf含有值32+4+‘\0’,需要过滤‘-’
break;
}
}
*p = 0;
return buf;
}
小贴士
1、对于C语言中char *型数据,在支持string(字符串类型)的语言中可直接使用string类型,如PB。
2、注意指针类型内存的释放。
3、注意数据的初始化
另外,本文也参照学习了网上其他博主的想法和代码,但在语言环境上面不够完善,不适用于C语言,所以本文在本地实现时做了部分更改,完全适用于C语言环境。
引用连接:
https://blog.csdn.net/weixin_30426957/article/details/95842873
https://blog.51cto.com/11998200/1867446