Pergunta

Eu encontrei o código da rede em que eu não posso entender esta linha: -

byte* p = (byte*)(void*)Scan0;

Há Scan0 é System.IntPtr. É código de C # .Net. Plz Explicar a linha acima.

O código completo é dado abaixo. este é o código para converter uma imagem em escala de cinza.

public static Image GrayScale(Bitmap b)
    {

        BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

        int stride = bmData.Stride;
        System.IntPtr Scan0 = bmData.Scan0;

        unsafe
        {
            byte* p = (byte*)(void*)Scan0;

            int nOffset = stride - b.Width * 3;

            byte red, green, blue;

            for (int y = 0; y < b.Height; ++y)
            {
                for (int x = 0; x < b.Width; ++x)
                {
                    blue = p[0];
                    green = p[1];
                    red = p[2];

                    p[0] = p[1] = p[2] = (byte)(.299 * red + .587 * green + .114 * blue);

                    p += 3;
                }
                p += nOffset;
            }
        }

        b.UnlockBits(bmData);

        return (Image)b;
    }

Eu entendo todo o código, mas só tem o problema nesta linha.

byte* p = (byte*)(void*)Scan0;
Foi útil?

Solução

Primeiro converte a IntPtr para um ponteiro void. Então, para um ponteiro byte. Este é o código unsafe.

Mais sobre código inseguro: http://msdn.microsoft.com/en-us /library/aa288474%28VS.71%29.aspx

notas Como Robert Harvey, um ponteiro é um local de memória. Em C / matrizes C ++ são intimamente ligada a este conceito. Quando isso acontecer os colchetes, seu basicamente está ajustando o endereço.

Outras dicas

sua pergunta soa como se você está pedindo o o código está fazendo, mas com base em alguns dos seus comentários eu acho que você está depois por que está lançando primeiro a um ponteiro nulo.

Você está provavelmente confundido aqui, porque não há nenhuma razão para estar lançando Scan0 primeiro a um * vazio. O elenco de byte * iria funcionar tão bem.

IntPtr tem um operador explícita (void *) que permite a projeção para void *. Se você tentar lançar diretamente do IntPtr para outra coisa o compilador irá vomitar porque somente o * elenco vazio é definido para a classe IntPtr. Veja também IntPtr :: ToPointer ().

Moldagem de void * para byte * é permitido pelo compilador porque neste momento, se você não sabe o que está fazendo você já está em apuros.

Parece bizarro, mas então eu não sei C # muito bem. É pode ser que haja algum problema com lançando um System.IntPtr diretamente a um byte*, mas não com System.IntPtr para void* ou void* para byte*.

O resultado final é, provavelmente, o mesmo que se você lançar int* para char* em C:. A capacidade de p derefence para obter um único byte do inteiro (assumindo CHAR_BIT é 8 na implementação C)

Confira este tutorial sobre código inseguro. Ele irá explicar o que a linha de meio de código, e como ele pode ser usado para outros tipos além byte:

http://msdn.microsoft.com/ en-us / library / aa288474 (VS.71) .aspx

Essencialmente, código inseguro permite a utilização de ponteiros c-estilo.

Seria possível que você precisa elenco para void para evitar o objeto de executar algum código de auto-cast sobre ele?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top