Explicar este código C #: byte * p = (byte *) (void *) Scan0;
-
22-07-2019 - |
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;
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?