Udostępnij przez


Dodatkowe zagadnienia

Podczas przenoszenia kodu należy wziąć pod uwagę następujące kwestie:

  • Następujące założenie nie jest już prawidłowe:

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

    Jednak kompilator 64-bitowy definiuje _WIN32 na potrzeby zgodności z poprzednimi wersjami.

  • Następujące założenie nie jest już prawidłowe:

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

    W takim przypadku klauzula else może reprezentować _WIN32 lub _WIN64.

  • Zachowaj ostrożność przy wyrównaniu typu danych. Makro TYPE_ALIGNMENT zwraca wymagania dotyczące wyrównania typu danych. Na przykład: TYPE_ALIGNMENT( KFLOATING_SAVE ) == 4 na procesorze x86, 8 na procesorze Intel ItaniumTYPE_ALIGNMENT( UCHAR ) == 1 wszędzie

    Na przykład kod jądra, który obecnie wygląda następująco:

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

    prawdopodobnie należy zmienić na:

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

    Automatyczne poprawki wyjątków wyrównania trybu jądra są wyłączone dla systemów Intel Itanium.

  • Zachowaj ostrożność przy użyciu operacji NOT. Rozważ następujące kwestie:

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

    Problem polega na tym, że ~(b–1) generuje wartość "0x0000 0000 xxxx xxxx", a nie "0xFFFF FFFF xxxx xxxx". Kompilator nie wykryje tego. Aby rozwiązać ten problem, zmień kod w następujący sposób:

    a = a & ~((UINT_PTR)b - 1);
    
  • Zachowaj ostrożność podczas wykonywania niepodpisanych i podpisanych operacji. Rozważ następujące kwestie:

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

    Wynik jest nieoczekiwanie duży. Reguła polega na tym, że jeśli którykolwiek operand jest niepodpisany, wynik jest niepodpisany. W poprzednim przykładzie element a jest konwertowany na niepodpisaną wartość podzieloną przez b i wynik przechowywany w języku c. Konwersja nie obejmuje manipulacji liczbowej.

    W innym przykładzie rozważ następujące kwestie:

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

    Problem występuje, ponieważ x jest niepodpisane, co sprawia, że całe wyrażenie niepodpisane. To działa dobrze, chyba że y jest ujemne. W tym przypadku wartość y jest konwertowana na wartość niepodpisaną, wyrażenie jest obliczane przy użyciu dokładności 32-bitowej, skalowanej i dodawanej do zmiennej pVar1. 32-bitowa liczba ujemna bez znaku staje się dużą 64-bitową liczbą dodatnią, co daje niewłaściwy wynik. Aby rozwiązać ten problem, zadeklaruj wartość x jako wartość ze znakiem lub jawnie wpisz go, aby long w wyrażeniu.

  • Należy zachować ostrożność podczas tworzenia alokacji rozmiaru kawałków. Na przykład:

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

    Poniższy kod jest nieprawidłowy, ponieważ kompilator wyścieła strukturę z dodatkowymi 4 bajtami, aby wyrównać 8 bajtów:

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

    Następujący kod jest poprawny:

    malloc(offsetof(struct xx, Pointers) + 100*sizeof(PVOID));
    
  • Nie przekazuj (HANDLE)0xFFFFFFFF do funkcji, takich jak CreateFileMapping. Zamiast tego użyj INVALID_HANDLE_VALUE.

  • Użyj odpowiednich specyfikatorów formatu podczas drukowania ciągu. Użyj %p, aby wydrukować wskaźniki w szesnastkowym. Jest to najlepszy wybór w przypadku wskaźników drukowania. Program Microsoft Visual C++ obsługuje %I drukowania danych polimorficznych. Język Visual C++ obsługuje również %I64 do drukowania wartości, które są 64-bitowe.