好吧,所以这一切都始于我对哈希码的兴趣。在Jon Skeet的一篇文章中做了一些阅读后,我问了this question。这让我对指针算法非常感兴趣,我几乎没有经验。所以,在阅读this page之后,我开始尝试,因为我从那里得到了基本的理解,而我的其他很棒的同行在这里!
现在我正在做更多的实验,我相信我已经准确地复制了下面string
实现中的哈希码循环(我保留了错误的权利):
Console.WriteLine("Iterating STRING (2) as INT ({0})", sizeof(int));
Console.WriteLine();
var val = "Hello World!";
unsafe
{
fixed (char* src = val)
{
var ptr = (int*)src;
var len = val.Length;
while (len > 2)
{
Console.WriteLine((char)*ptr);
Console.WriteLine((char)ptr[1]);
ptr += 2;
len -= sizeof(int);
}
if (len > 0)
{
Console.WriteLine((char)*ptr);
}
}
}
但是,结果对我来说有点困惑;的种类。结果如下:
Iterating STRING (2) as INT (4)
H
l
o
W
r
d
我想到,最初,ptr[1]
处的值将是第一个被读取(或挤压在一起)的第二个字母。但是,显然不是这样。那是因为ptr[1]
在第一次迭代时技术上是字节4 而第二次迭代是字节12 吗?
答案 0 :(得分:12)
你的问题是你正在将指针转换为int*
指针..这是32位..而不像char*
那样16。
因此,每个增量为32位。这是一张照片(如果你必须赞美我的作品):
对不起那些狡猾的箭头抱歉..我认为我的鼠标电池已经死了
当您通过char
指针阅读时...您正在逐字符地读取16位。
当你将它转换为int
指针时......你正在以32位为增量读取。这意味着,ptr[0]
同时是H
和e
(但指向H
的基础)。 ptr[1]
都是l
的..
这就是为什么你实际上是在输出中跳过一个字符。
当你把它转回char
时:
Console.WriteLine((char)*ptr);
..只有前16位才会产生转换,这是每对中的第一个字符。
答案 1 :(得分:3)
http://msdn.microsoft.com/en-us/library/vstudio/x9h8tsay.aspx
A char
是16位,int
是32位。每次向int ptr
添加1时,都会添加2个值得的char指针。
这就是为什么你只看到奇怪的字符。
答案 2 :(得分:3)
将值降低到它们驻留在内存中的字节将有助于您更好地理解这一点。希望下面的代码和注释可以帮助您了解为什么您只在int * indices中编写字符。
var val = "Hello World!";
/*
Hello World!
char idx = 012345678911
01
Hello World!
int idx = 0 1 2 3 4 5
-> this is why len should be 6 below
*/
unsafe
{
fixed (char* src = val)
{
var ptr = (int*)src;
//explicit definition of what val.Length / 2 would actually mean
// -> there are actually 6 integers here but 12 chars
var len = val.Length * sizeof(char) / sizeof(int);
while (len > 0)
{
//char pointer to the first "char" of the int
var word = (char*) ptr;
Console.WriteLine(*word);
/* types matter here. ptr[1] is the next _integer_
not the next character like it would for a char* */
Console.WriteLine(word[1]); //next char of the int @ ptr
ptr++; // next integer / word[2]
len--;
}
}
}
答案 3 :(得分:2)
c#字符串中的字符长度为2个字节,因为它们以UTF16编码。
答案 4 :(得分:1)
char
是16位,而int
是32,所以在演员之后你会读取32位。
如果您使用int
(16位)代替short
,则可以轻松查看。然后你会得到你的Hello
var ptr = (short*)src;
答案 5 :(得分:0)
我认为这是你的问题:
在C#中,字符由2个字节(16位)表示。另一方面,整数是4个字节(32位)。整数可转换为字符UP TO 2 ^ 16,因为表示该整数的相同16位可以重新解释为表示UTF-16中的字符。基础位完全相同,但它们被读作不同的值。然而,弄乱你的是尺寸差异。一个int是4个字节到字符2,所以通过以int
(4Bytes)而不是Char或Byte * 2为单位递增(如你的SizeOf(Int)
指针那样),你正在向前移动32位,读取16,然后跳过另一个32,导致你跳过其他所有的char。因此,H L O W R D。
如果你想了解有关指针artihmetic和按位操作的更多信息,学习一些基本的C是一种很酷且非常有趣(受到辩论)的方式。