读取String作为int指针

时间:2013-12-04 21:29:16

标签: c#

好吧,所以这一切都始于我对哈希码的兴趣。在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 吗?

6 个答案:

答案 0 :(得分:12)

你的问题是你正在将指针转换为int*指针..这是32位..而不像char*那样16。

因此,每个增量为32位。这是一张照片(如果你必须赞美我的作品):

char* int* 对不起那些狡猾的箭头抱歉..我认为我的鼠标电池已经死了

当您通过char指针阅读时...您正在逐字符地读取16位。

当你将它转换为int指针时......你正在以32位为增量读取。这意味着,ptr[0]同时是He(但指向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)

@Simon Whitehead的回答是一个很好的解释。

将值降低到它们驻留在内存中的字节将有助于您更好地理解这一点。希望下面的代码和注释可以帮助您了解为什么您只在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是一种很酷且非常有趣(受到辩论)的方式。