为什么 .NET String.EqualsHelper 似乎使用半大小的整数和长整型
本文关键字:整数 长整型 String NET EqualsHelper 为什么 | 更新日期: 2023-09-27 18:30:21
查看String.EqualsHelper和String.CompareOrdinalHelper(.NET 2和4)的实现,在我看来,比较假设int字节大小为2,长字节大小为4。我认为 .NET 32 位世界中的实际大小是 4 和 8。我错过了什么?这里有什么收获吗?.NET 框架和 http://www.netframeworkdevs.com/common-language-runtime/string-comparision-24141.shtml 中的 EqualsHelper 方法内部的源代码示例。
来自反射器的逆向工程源(框架 2):
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
private static unsafe bool EqualsHelper(string strA, string strB)
{
int length = strA.Length;
if (length != strB.Length)
{
return false;
}
fixed (char* str = ((char*) strA))
{
char* chPtr = str;
fixed (char* str2 = ((char*) strB))
{
char* chPtr2 = str2;
char* chPtr3 = chPtr;
char* chPtr4 = chPtr2;
while (length >= 10)
{
if ((((*(((int*) chPtr3)) != *(((int*) chPtr4))) || (*(((int*) (chPtr3 + 2))) != *(((int*) (chPtr4 + 2))))) || ((*(((int*) (chPtr3 + 4))) != *(((int*) (chPtr4 + 4)))) || (*(((int*) (chPtr3 + 6))) != *(((int*) (chPtr4 + 6)))))) || (*(((int*) (chPtr3 + 8))) != *(((int*) (chPtr4 + 8)))))
{
break;
}
chPtr3 += 10;
chPtr4 += 10;
length -= 10;
}
while (length > 0)
{
if (*(((int*) chPtr3)) != *(((int*) chPtr4)))
{
break;
}
chPtr3 += 2;
chPtr4 += 2;
length -= 2;
}
return (length <= 0);
}
}
}
private static unsafe int CompareOrdinalHelper(string strA, string strB)
{
int num = Math.Min(strA.Length, strB.Length);
int num2 = -1;
fixed (char* str = ((char*) strA))
{
char* chPtr = str;
fixed (char* str2 = ((char*) strB))
{
char* chPtr2 = str2;
char* chPtr3 = chPtr;
char* chPtr4 = chPtr2;
while (num >= 10)
{
if (*(((int*) chPtr3)) != *(((int*) chPtr4)))
{
num2 = 0;
break;
}
if (*(((int*) (chPtr3 + 2))) != *(((int*) (chPtr4 + 2))))
{
num2 = 2;
break;
}
if (*(((int*) (chPtr3 + 4))) != *(((int*) (chPtr4 + 4))))
{
num2 = 4;
break;
}
if (*(((int*) (chPtr3 + 6))) != *(((int*) (chPtr4 + 6))))
{
num2 = 6;
break;
}
if (*(((int*) (chPtr3 + 8))) != *(((int*) (chPtr4 + 8))))
{
num2 = 8;
break;
}
chPtr3 += 10;
chPtr4 += 10;
num -= 10;
}
if (num2 == -1)
{
goto Label_0101;
}
chPtr3 += num2;
chPtr4 += num2;
int num3 = chPtr3[0] - chPtr4[0];
if (num3 != 0)
{
return num3;
}
return (chPtr3[1] - chPtr4[1]);
Label_00E7:
if (*(((int*) chPtr3)) != *(((int*) chPtr4)))
{
goto Label_0105;
}
chPtr3 += 2;
chPtr4 += 2;
num -= 2;
Label_0101:
if (num > 0)
{
goto Label_00E7;
}
Label_0105:
if (num > 0)
{
int num4 = chPtr3[0] - chPtr4[0];
if (num4 != 0)
{
return num4;
}
return (chPtr3[1] - chPtr4[1]);
}
return (strA.Length - strB.Length);
}
}
}
chPtr3 += 2;
这会将指针前进四个字节,两个字符。 字符在 .NET 中是 2 个字节,它以 utf-16 编码存储字符。 递增字符指针会将其前进一个字符,两个字节。
这里真正发生的事情是 int* 的演员阵容。 这使得算法更快,同时比较两个字符。 这在 32 位 CPU 上运行良好,它具有足够大的寄存器以容纳两个字符(2 x 16 位 = 32 位)。 代码中将指针推进 10 个字符的部分等效于循环展开,这是一种使循环更快的常见优化策略。
该算法特定于 32 位代码,即 64 位版本的 mscorlib.dll使用不同的方法,将 4 个字符同时与单个指令进行比较。 使用源中的 #if 完成
Char 是两个字节。Int 是四个字节。Int 比较在一个比较上比较四个字节或 2 个字符。
操作"char_pointer + 2"将字符指针增加 2 个字符或 4 个字节。
单递增(+4字节)的大小与单倍递增(+4字节)的大小相同