aritmética ponteiro e o compilador C #
-
12-09-2019 - |
Pergunta
Para o propósito de aprender Recentemente, olhou para uma montagem existente (com refletor) que utiliza Win32 WriteFile. A implementação é:
Write(IntPtr handleFile, void* bufferData, uint length){
void* buffer = bufferData
while (length > 0)
{
uint wrtn;
if (!WriteFile(handle, buffer, len, out wrtn, IntPtr.Zero))
{
// Do some error handling
}
// This does not compile, because of the cast but also simply because void* does not have += operators (it is unknown size).
buffer += (void*)wrtn;
len -= wrtn;
}
}
É realmente as últimas 2 linhas que são problemáticos ... Por um lado, o compilador reclama que você não pode lançar uint para void *. Além disso, ele simplesmente não é possível usar + = ou mesmo + em void *, porque não é de tamanho conhecido.
Write(IntPtr handleFile, void* bufferData, uint length){
byte* buffer = (byte*)bufferData
while (length > 0)
{
uint wrtn;
if (!WriteFile(handle, (void*)buffer, len, out wrtn, IntPtr.Zero))
{
// Do some error handling
}
// This works! I can add to a byte*
buffer = buffer + wrtn; // I could also have used buffer += wrtn
len -= wrtn;
}
}
O código acima não funciona, mas ainda as últimas linhas irá compilar a:
buffer += (byte*)wrtn;
Eu não entendo por que e muito gostaria de saber por que se comporta compilador desta forma:
- Por que gerar o elenco como este (e por que não é aceito para fazer isso no código escrito pelo usuário)?
- O que se passa com as + = operadores em void * no primeiro exemplo? O código de código original geraram tampão + = (void *) wrtn onde tampão também é void * ????
Solução
Bem para o seu segundo ponto, void * não tem informações de tamanho para que o compilador não sabe o quanto a incrementar o ponteiro por. Deve incrementar por sizeof (double)? Apenas com informações do tipo ele sabe o que esperar.
Edit: Na verdade isso se aplica ao seu primeiro ponto também. O compilador precisa saber o tamanho do tipo de dados o seu incremento. Void * não tem informações de tamanho presente de modo lançando a um byte * você deixar o compilador sabe que ele precisa para incrementar o ponteiro por sizeof (byte) * wrtn.
Edit2: Com seu esclarecimento, parece que você está perguntando por que o código do refletor emite como um * vazio em vez de como ele está escalado adequadamente Tipo (byte *). Muito provavelmente, isso deve-se ao tipo de informação a ser extraída do tipo de parâmetro e um pouco ingènua a ser utilizado no método. Este é provavelmente um problema com refletor mais do que o compilador.
Também é possível que este código ponteiro perde-lo de informações de tipo no IL, eu não testei ainda, mas não pode transportar informações de digitação (além do tamanho dos dados) para o IL para o refletor para adequadamente emitem ( 'segura' normal IL deve ter sempre esta informação tipo). Se este foi o caso do refletor pode padrão para * nula ou o tipo inferido mais próximo.
Outras dicas
Para o propósito de aprender Recentemente, olhou para uma montagem existente (com refletor)
O único problema aqui é com refletor - aparentemente, não é tão bom em deduzir o código original C # da IL. A IL si é correta, e não tem elencos (nenhum são necessários - no IL, você empurra um ponteiro e um argumento inteiro na pilha, e fazer um add / subtrair). Refletor é errado.