C#中使用指针实现高效比较字符串的小技巧
2008-05-15 15:48
274 查看
判断随机字符串之间的是否相等是程序设计中常用的技巧,再C++时代,我们可以通过把字符串中每四个字节转换为一个int对象,通过int对象一次比较四个字符,从而实现相对高效的字符串比较工作。那么,这个思路在C#中能否是实现呢?答案是肯定的。
在C#中使用上述思想,必须要解决两个问题,其一是在C#中使用指针,并且指针指向的托管变量位置不能被GC重新分配。其二,托管字符串在内存中与int或long之间的对应关系。
很多文章中已经详细描述了在C#中使用指针的方法,本文不再详细叙述,开启unsafe开关的方式为,右键单击解决方案目录——选择属性——再Build对话框中选中“允许unsafe代码”选项, 这样再C#中就可通过unsafe关键字标记可以使用指针的区域了。我们知道,被托管的变量由系统随机分配、回收和调整在内存中的位置,因此,指向托管变量的指针可能会由于托管变量被随机调整而指向错误区域。为了保证指针自始至终都能指向同一个托管变量,C#中提供了fixed语句来完成该任务。被标记了fixed的指针,在fixed所标志的区域中回自始至终的指向改变量,而系统不会对该托管变量进行调整和再分配。代码如下:
string str="Hello World!";
unsafe
{
fixed (char* ps = str)
{
//该区域中ps始终指向托管字符串str
}
}
使用sizeof可以测出,C#中long占用8个字节,那么在上面代码中如果将ps的前8个字节强转为long型,得到的结果是什么呢?我们利用如下代码进行测试:
long n=0;
long nLow = 0, nHigh = 0;
string str = "Hello World!";
unsafe
{
fixed (char* ps = str)
{
char* psTemp = ps;
n=*(long*)psTemp;
nLow = n & 0xFFFF; //取最后两个字节
nHigh = (n >> 16) & 0xFFFF; //取第3,4个字节
MessageBox.Show(((char)nLow).ToString() + " " + ((char)nHigh).ToString());
nLow = (n >> 32) & 0xFFFF; //取第5,6个字节
nHigh = (n >> 48) & 0xFFFF; //取第7,8个字节
MessageBox.Show(((char)nLow).ToString() + " " + ((char)nHigh).ToString());
}
}
可以看出,上面MessageBox中的输出分别为H,e和l,l共4个字符,并非我们直观上认为的8个字符,这是由于在转换的过程中,每个字符从byte被转成为一个2个字节的短整型short而造成的,因此,将字符串指针强转为long以后,该long型变量的值可以表示4个字符,那么,比较两个long型对象的值实际上就是在比较这4个字符的值,采用这个思路,实际上实现了做一次比较操作就能同时比较4个字符。
比较两字符串是否相等的代码如下:
protected bool IsEquals(string str1, string str2)
{
bool bRet = true;
int nC1 = 0, nC2 = 0, nLen = 0;
int i = 0;
if (str1.Length != str2.Length) //长度不相等则字符串不相等
{
return false;
}
//长度不是4的倍数则补位
nC1 = ((str1.Length % 4) != 0) ? (4 - str1.Length%4) : 0; //计算补偿位
nC2 = ((str2.Length % 4) != 0) ? (4 - str1.Length%4) : 0; //计算补偿位
nLen = (nC1 > nC2) ? nC1 : nC2;
for (i = 0; i <nLen; i++)
{
if (i < nC1)
{
str1 += " ";
}
if (i < nC2)
{
str2 += " ";
}
}
unsafe
{
fixed (char* psStr1 = str1) fixed (char* psStr2 = str2)
{
char* psTemp1 = psStr1;
char* psTemp2 = psStr2;
while (i < str1.Length)
{
if (*(long*)psTemp1 != (*(long*)psTemp2)) //一次比较4个字符
{
bRet = false;
break;
}
i += 4;
psTemp1 += 4;
psTemp2 += 4;
}
}
}
return bRet;
}
本文参考了.Net Framework 3.5源代码中String类的private unsafe static bool EqualsHelper(String strA, String strB)方法
QQ:819543772
EMail:wuchunlei@163.com
在C#中使用上述思想,必须要解决两个问题,其一是在C#中使用指针,并且指针指向的托管变量位置不能被GC重新分配。其二,托管字符串在内存中与int或long之间的对应关系。
很多文章中已经详细描述了在C#中使用指针的方法,本文不再详细叙述,开启unsafe开关的方式为,右键单击解决方案目录——选择属性——再Build对话框中选中“允许unsafe代码”选项, 这样再C#中就可通过unsafe关键字标记可以使用指针的区域了。我们知道,被托管的变量由系统随机分配、回收和调整在内存中的位置,因此,指向托管变量的指针可能会由于托管变量被随机调整而指向错误区域。为了保证指针自始至终都能指向同一个托管变量,C#中提供了fixed语句来完成该任务。被标记了fixed的指针,在fixed所标志的区域中回自始至终的指向改变量,而系统不会对该托管变量进行调整和再分配。代码如下:
string str="Hello World!";
unsafe
{
fixed (char* ps = str)
{
//该区域中ps始终指向托管字符串str
}
}
使用sizeof可以测出,C#中long占用8个字节,那么在上面代码中如果将ps的前8个字节强转为long型,得到的结果是什么呢?我们利用如下代码进行测试:
long n=0;
long nLow = 0, nHigh = 0;
string str = "Hello World!";
unsafe
{
fixed (char* ps = str)
{
char* psTemp = ps;
n=*(long*)psTemp;
nLow = n & 0xFFFF; //取最后两个字节
nHigh = (n >> 16) & 0xFFFF; //取第3,4个字节
MessageBox.Show(((char)nLow).ToString() + " " + ((char)nHigh).ToString());
nLow = (n >> 32) & 0xFFFF; //取第5,6个字节
nHigh = (n >> 48) & 0xFFFF; //取第7,8个字节
MessageBox.Show(((char)nLow).ToString() + " " + ((char)nHigh).ToString());
}
}
可以看出,上面MessageBox中的输出分别为H,e和l,l共4个字符,并非我们直观上认为的8个字符,这是由于在转换的过程中,每个字符从byte被转成为一个2个字节的短整型short而造成的,因此,将字符串指针强转为long以后,该long型变量的值可以表示4个字符,那么,比较两个long型对象的值实际上就是在比较这4个字符的值,采用这个思路,实际上实现了做一次比较操作就能同时比较4个字符。
比较两字符串是否相等的代码如下:
protected bool IsEquals(string str1, string str2)
{
bool bRet = true;
int nC1 = 0, nC2 = 0, nLen = 0;
int i = 0;
if (str1.Length != str2.Length) //长度不相等则字符串不相等
{
return false;
}
//长度不是4的倍数则补位
nC1 = ((str1.Length % 4) != 0) ? (4 - str1.Length%4) : 0; //计算补偿位
nC2 = ((str2.Length % 4) != 0) ? (4 - str1.Length%4) : 0; //计算补偿位
nLen = (nC1 > nC2) ? nC1 : nC2;
for (i = 0; i <nLen; i++)
{
if (i < nC1)
{
str1 += " ";
}
if (i < nC2)
{
str2 += " ";
}
}
unsafe
{
fixed (char* psStr1 = str1) fixed (char* psStr2 = str2)
{
char* psTemp1 = psStr1;
char* psTemp2 = psStr2;
while (i < str1.Length)
{
if (*(long*)psTemp1 != (*(long*)psTemp2)) //一次比较4个字符
{
bRet = false;
break;
}
i += 4;
psTemp1 += 4;
psTemp2 += 4;
}
}
}
return bRet;
}
本文参考了.Net Framework 3.5源代码中String类的private unsafe static bool EqualsHelper(String strA, String strB)方法
QQ:819543772
EMail:wuchunlei@163.com
相关文章推荐
- C#中使用指针实现高效比较字符串的小技巧
- C#中使用指针实现高效比较字符串的小技巧
- C#中使用指针实现高效比较字符串的小技巧
- [转]C#中使用指针实现高效比较字符串的小技巧
- [转]C#中使用指针实现高效比较字符串的小技巧
- C#字符串数组排序 C#排序算法大全 C#字符串比较方法 一个.NET通用JSON解析/构建类的实现(c#) C#处理Json文件 asp.net使用Jquery+iframe传值问题
- C#实现SMTP服务器,使用TCP命令实现,功能比较完善
- 判断一个字符串是否全是数字的多种方法及其性能比较(C#实现)
- C#实现字符串相似度比较[Levenshtein Distance算法].
- C#中使用IFormattable实现自定义格式化字符串输出示例
- C#使用yield实现高效查询
- 在Shell脚本中编写AWK脚本实现数据提取—注意格式、awk中使用shell变量、awk中数字字符串转换成数字、awk中字符串相等比较
- 问题一:编写函数stringcat,实现字符串的连接,程序中需要使用指针形式访问字符串
- 一个使用C#语言实现的数据比较案例
- 字符串公式解析器——使用“逆波兰式算法”及C#实现
- C#实现SQL全库检索数据-比较使用DataReader与DataAdapter+Datatable效率,差距惊人!
- c#打包文件解压缩 C#中使用委托、接口、匿名方法、泛型委托实现加减乘除算法 一个简单例子理解C#的协变和逆变 对于过长字符串的大小比对
- C#实现SMTP服务器,使用TCP命令实现,功能比较完善
- C# 使用Dictionary、linq实现根据集合里面的字符串进行分组
- 字符串相似度计算的方法,使用SQL以及C#实现,本文非原创摘自网络(.NET SQL技术交流群入群206656202需注明博客园)