Partilhar via


Regras para usar ponteiros

Portar seu código para compilar para o Microsoft Windows de 32 e 64 bits é simples. Você só precisa seguir algumas regras simples sobre transmissão de ponteiros e usar os novos tipos de dados em seu código. As regras para manipulação de ponteiro são as seguintes.

  1. Não lance ponteiros para int, long, ULONGou DWORD.

    Se você precisar lançar um ponteiro para testar alguns bits, definir ou limpar bits ou manipular seu conteúdo, use o tipo UINT_PTR ou INT_PTR. Esses tipos são tipos integrais que são dimensionados para o tamanho de um ponteiro para Windows de 32 e 64 bits (por exemplo, ULONG para Windows de 32 bits e _int64 para Windows de 64 bits). Por exemplo, suponha que esteja a transferir o seguinte código:

    ImageBase = (PVOID)((ULONG)ImageBase | 1);

    Como parte do processo de portabilidade, você alteraria o código da seguinte maneira:

    ImageBase = (PVOID)((ULONG_PTR)ImageBase | 1);

    Use UINT_PTR e INT_PTR quando apropriado (e se você não tiver certeza se eles são necessários, não há nenhum dano em usá-los apenas no caso). Não lance seus ponteiros para os tipos ULONG, LONG, INT, UINTou DWORD.

    Observe que HANDLE é definido como um void*, portanto, realizar typecasting de um valor HANDLE para um valor ULONG para testar, definir ou limpar os 2 bits de ordem inferior é um erro no Windows de 64 bits.

  2. Utilize as funções PtrToLong ou PtrToUlong para truncar ponteiros.

    Se você precisar truncar um ponteiro para um valor de 32 bits, use o PtrToLong ou função PtrToUlong (definida em Basetsd.h). Essas funções desativam o aviso de truncamento de ponteiro durante a chamada.

    Use estas funções com cuidado. Depois de converter uma variável de ponteiro usando uma dessas funções, nunca mais a use como ponteiro. Essas funções truncam os 32 bits superiores de um endereço, que geralmente são necessários para acessar a memória originalmente referenciada pelo ponteiro. Usar essas funções sem uma consideração cuidadosa resultará em código frágil.

  3. Tenha cuidado ao usar valores de POINTER_32 no código que podem ser compilados como código de 64 bits. O compilador assinará e estenderá o ponteiro quando ele for atribuído a um ponteiro nativo em código de 64 bits, e não ao ponteiro de extensão zero.

  4. Tenha cuidado ao usar valores de POINTER_64 no código que podem ser compilados como código de 32 bits. O compilador vai estender o ponteiro com sinal no código de 32 bits, não vai estender o ponteiro com zero.

  5. Tenha cuidado ao usar parâmetros OUT.

    Por exemplo, suponha que você tenha uma função definida da seguinte forma:

    void func( OUT PULONG *PointerToUlong );

    Não chame esta função da seguinte forma.

    ULONG ul;
    PULONG lp;
    func((PULONG *)&ul);
    lp = (PULONG)ul;
    

    Em vez disso, use a seguinte chamada.

    PULONG lp;
    func(&lp);
    

    Typecasting &ul para PULONG* evita um erro de compilação, mas a função escreverá um valor de ponteiro de 64 bits na memória em &ul. Este código funciona no Windows de 32 bits, mas causará corrupção de dados no Windows de 64 bits e será uma corrupção sutil e difícil de encontrar. Resumindo: não faça truques com o código C — direto e simples é melhor.

  6. Tenha cuidado com interfaces polimórficas.

    Não crie funções que aceitem parâmetros DWORD para dados polimórficos. Se os dados puderem ser um ponteiro ou um valor inteiro, use o tipo UINT_PTR ou PVOID.

    Por exemplo, não crie uma função que aceite uma matriz de parâmetros de exceção digitados como valores de DWORD. A matriz deve consistir de valores DWORD_PTR. Portanto, os elementos da matriz podem conter endereços ou valores integrais de 32 bits. (A regra geral é que, se o tipo original for DWORD e precisar ser largura de ponteiro, converta-o em um valor DWORD_PTR. É por isso que existem tipos correspondentes de precisão de ponteiro.) Se você tiver um código que usa DWORD, ULONGou outros tipos de 32 bits de forma polimórfica (ou seja, você realmente deseja que o parâmetro ou membro da estrutura mantenha um endereço), use UINT_PTR no lugar do tipo atual.

  7. Utilize as novas funções da classe de janela.

    Se você tiver dados privados de janela ou classe que contenham ponteiros, seu código precisará usar as seguintes novas funções:

    Essas funções podem ser usadas no Windows de 32 e 64 bits, mas são necessárias no Windows de 64 bits. Prepare-se para a transição usando essas funções agora.

    Além disso, você deve acessar ponteiros ou identificadores em dados privados de classe usando as novas funções no Windows de 64 bits. Para ajudá-lo a encontrar esses casos, os seguintes índices não são definidos no Winuser.h durante uma compilação de 64 bits:

    • GWL_WNDPROC
    • GWL_HINSTANCE
    • GWL_HWNDPARENT
    • GWL_USERDATA

    Em vez disso, Winuser.h define os seguintes novos índices:

    • GWLP_WNDPROC
    • GWLP_HINSTANCE
    • GWLP_HWNDPARENT
    • GWLP_USERDATA
    • GWLP_ID

    Por exemplo, o código a seguir não compila:

    SetWindowLong(hWnd, GWL_WNDPROC, (LONG)MyWndProc);

    Deve ser alterado da seguinte forma:

    SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)MyWndProc);

    Ao definir o membro cbWndExtra da estrutura WNDCLASS, certifique-se de reservar espaço suficiente para ponteiros. Por exemplo, se estiveres a reservar bytes do tamanho de sizeof(DWORD) para um valor de ponteiro, reserva bytes do tamanho de sizeof(DWORD_PTR).

  8. Aceda a todos os dados de janela e de classe usando FIELD_OFFSET.

    É comum acessar dados de janela usando deslocamentos codificados. Esta técnica não é portátil para Windows de 64 bits. Para tornar seu código portátil, acesse seus dados de janela e classe usando a macro FIELD_OFFSET. Não assuma que o segundo ponteiro tem um deslocamento de 4.

  9. Os tipos LPARAM, WPARAMe LRESULT mudam de tamanho com a plataforma.

    Ao compilar código de 64 bits, esses tipos se expandem para 64 bits, porque normalmente contêm ponteiros ou tipos integrais. Não misture esses valores com DWORD, ULONG, UINT, INT, int, ou valores longos. Examine como você usa esses tipos e certifique-se de não truncar valores inadvertidamente.