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


Дополнительные сведения

При переносе кода учитывайте следующие моменты.

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

    #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 на процессореTYPE_ALIGNMENT( UCHAR ) Intel Itanium == 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 xxxx". Компилятор не обнаружит этого. Чтобы устранить эту проблему, измените код следующим образом:

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

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

    Результат неожиданно большой. Правило заключается в том, что если один из операндов не подписан, результатом будет unsigned. В предыдущем примере преобразуется в неподписаемое значение, делимое на 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-разрядных значений.