Ulteriori considerazioni

Quando si effettua la conversione del codice, considerare i punti seguenti:

  • Il presupposto seguente non è più valido:

    #ifdef _WIN32 // Win32 code
        ...
    #else         // Win16 code
        ...
    #endif
    

    Tuttavia, il compilatore a 64 bit definisce _WIN32 per la compatibilità con le versioni precedenti.

  • Il presupposto seguente non è più valido:

    #ifdef _WIN16 // Win16 code
        ...
    #else         // Win32 code
        ...
    #endif
    

    In questo caso, la clausola else può rappresentare _WIN32 o _WIN64.

  • Prestare attenzione all'allineamento del tipo di dati. La macro TYPE_ALIGNMENT restituisce i requisiti di allineamento di un tipo di dati. Ad esempio: TYPE_ALIGNMENT( KFLOATING_SAVE ) == 4 su x86, 8 su processoreTYPE_ALIGNMENT( UCHAR ) Intel Itanium == 1 ovunque

    Ad esempio, il codice kernel simile al seguente:

    ProbeForRead( UserBuffer, UserBufferLength, sizeof(ULONG) );
    

    probabilmente deve essere modificato in:

    ProbeForRead( UserBuffer, UserBufferLength, TYPE_ALIGNMENT(IOCTL_STRUC) );
    

    Le correzioni automatiche delle eccezioni di allineamento in modalità kernel sono disabilitate per i sistemi Intel Itanium.

  • Prestare attenzione alle operazioni NOT. Considerare quanto segue:

    UINT_PTR a; 
    ULONG b;
    a = a & ~(b - 1);
    

    Il problema è che ~(b-1) produce "0x0000 0000 xxxx xxxx" e non "0xFFFF FFFF xxxx xxxx". Il compilatore non rileverà questa situazione. Per risolvere questo problema, modificare il codice nel modo seguente:

    a = a & ~((UINT_PTR)b - 1);
    
  • Prestare attenzione a eseguire operazioni non firmate e firmate. Considerare quanto segue:

    LONG a;
    ULONG b;
    LONG c;
    
    a = -10;
    b = 2;
    c = a / b;
    

    Il risultato è inaspettatamente grande. La regola è che se uno degli operandi non è firmato, il risultato non è firmato. Nell'esempio precedente, un oggetto viene convertito in un valore senza segno, diviso per b e il risultato archiviato in c. La conversione non comporta alcuna manipolazione numerica.

    Come altro esempio, considerare quanto segue:

    ULONG x;
    LONG y;
    LONG *pVar1;
    LONG *pVar2;
    
    pVar2 = pVar1 + y * (x - 1);
    

    Il problema si verifica perché x è senza segno, che rende l'intera espressione senza segno. Questo funziona bene, a meno che y non sia negativo. In questo caso, y viene convertito in un valore senza segno, l'espressione viene valutata usando precisione a 32 bit, ridimensionata e aggiunta a pVar1. Un numero negativo senza segno a 32 bit diventa un numero positivo a 64 bit di grandi dimensioni, che dà il risultato errato. Per risolvere questo problema, dichiarare x come valore firmato o digitarlo in modo esplicito su LONG nell'espressione.

  • Prestare attenzione quando si effettuano allocazioni di dimensioni a fasi. Ad esempio:

    struct xx {
       DWORD NumberOfPointers;
       PVOID Pointers[100];
    };
    

    Il codice seguente non è corretto perché il compilatore riempirà la struttura con altri 4 byte per rendere l'allineamento a 8 byte:

    malloc(sizeof(DWORD) + 100*sizeof(PVOID));
    

    Il codice seguente è corretto:

    malloc(offsetof(struct xx, Pointers) + 100*sizeof(PVOID));
    
  • Non passare (HANDLE)0xFFFFFFFF a funzioni come CreateFileMapping. Usare invece INVALID_HANDLE_VALUE.

  • Utilizzare gli identificatori di formato appropriati durante la stampa di una stringa. Utilizzare %p per stampare i puntatori in formato esadecimale. Questa è la scelta migliore per i puntatori di stampa. Microsoft Visual C++ supporta %I per stampare dati polimorfici. Visual C++ supporta anche %I64 per stampare valori a 64 bit.