Поделиться через


Дополнительные рекомендации

При переносе кода рассмотрите следующие моменты:

  • Следующее предположение больше не является допустимым:

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

    Однако 64-разрядный компилятор определяет _WIN32 для обратной совместимости.

  • Следующее предположение больше не является допустимым:

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

    В этом случае предложение else может представлять _WIN32 или _WIN64.

  • Будьте осторожны с выравниванием типа данных. Макрос TYPE_ALIGNMENT возвращает требования к выравниванию типа данных. Например: TYPE_ALIGNMENT( KFLOATING_SAVE ) == 4 в x86, 8 на процессоре Intel ItaniumTYPE_ALIGNMENT( UCHAR ) == 1 везде

    Например, код ядра, который в настоящее время выглядит следующим образом:

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

    может быть изменено на:

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

    Автоматические исправления исключений выравнивания в режиме ядра отключены для систем Intel Itanium.

  • Будьте осторожны с операциями NOT. Рассмотрим следующее:

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

    Проблема заключается в том, что ~(b–1) создает "0x0000 0000 xxxx xxxx", а не "0xFFFF FFFF xxxx xxxx". Компилятор не обнаружит это. Чтобы устранить эту проблему, измените код следующим образом:

    a = a & ~((UINT_PTR)b - 1);
    
  • Будьте осторожны при выполнении неподписанных и подписанных операций. Рассмотрим следующее:

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

    Результат неожиданно велик. Правило заключается в том, что если любой операнду не назначен, результат не указан. В предыдущем примере преобразуется в значение без знака, разделенное на b, и результат, хранящийся в c. Преобразование не включает числовые манипуляции.

    В качестве другого примера рассмотрим следующее:

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

    Проблема возникает из-за отмены знака x, что делает все выражение без знака. Это работает нормально, если y не является отрицательным. В этом случае y преобразуется в значение без знака, выражение вычисляется с помощью 32-разрядной точности, масштабирования и добавления в pVar1. 32-разрядное отрицательное число без знака становится большим 64-разрядным положительным числом, что дает неправильный результат. Чтобы устранить эту проблему, объявите x как подписанное значение или явно введите его в LONG в выражении.

  • Будьте осторожны при создании фрагментных выделений размера. Например:

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

    Следующий код неправильно, так как компилятор будет заполнять структуру дополнительными 4 байтами, чтобы сделать выравнивание 8-байтов:

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

    Следующий код правильный:

    malloc(offsetof(struct xx, Pointers) + 100*sizeof(PVOID));
    
  • Не передайте (HANDLE)0xFFFFFFFF в такие функции, как CreateFileMapping. Вместо этого используйте INVALID_HANDLE_VALUE.

  • При печати строки используйте правильные описатели формата. Используйте %p для печати указателей в шестнадцатеричном виде. Это лучший выбор для печати указателей. Microsoft Visual C++ поддерживает %I для печати полиморфных данных. Visual C++ также поддерживает %I64 для печати значений, 64 битов.