Не делайте предположений о размерах
Классической проблемой является код, исходящий из того, что тип int имеет размер 32 бита. Следующий фрагмент не работает, если у вас 32-битный указатель и 16-битный тип int (что может быть при архитектуре Intel 80x86):
double a[1000], *p = a;
// ...
dist_from_start_of_array_in_bytes = (int)p - (int)a;
Более трудно уловима такая проблема в Си (но не в Си++):
g()
{
doesnt_work( 0 );
}
doesnt_work( char *p )
{
if( !p ) // вероятно не работает
// ...
}
Компилятор соглашается с этим вызовом, потому что в Си разрешены ссылки вперед (и не разрешены в Си++, так что там это не проблема). 0 — это тип int, поэтому в стек помещается 16-битовый объект. Но функция ожидает 32-битный указатель, поэтому она использует 16 бит из стека и добавляет к ним еще 16 бит всякого мусора для создания 32-битного указателя. Вероятнее всего, что if(!p)
даст ложный результат, так как только 16 бит из 32 будут равны 0.
Традиционное решение состоит в использовании typedef :
typedef int word; // всегда 16 бит
typedef long
dword; // всегда 32 бита.
После чего вы можете поменять операторы typedef в новой операционной среде, чтобы гарантировать, что word по-прежнему имеет размер 16 бит, а dword — 32 бита. Для 32-разрядной системы предыдущее может быть переопределено как:
typedef short
word; // всегда 16 бит
typedef int dword; // всегда 32 бита.
Другая связанная с размерностью часовая бомба спрятана в том способе, которым в ANSI Си обеспечивается работа с иностранными языками. ANSI Си определяет тип wchar_t для работы с расширенными наборами символов типа Unicode —
нового 16-битного многонационального набора символов. Стандарт ANSI Си также утверждает, что перед строкой с расширенными символами должен стоять символ L. Microsoft и другие поставщики компиляторов стараются помочь вам писать переносимые программы, предусматривая макросы типа:
#ifdef _UNICODE
typedef wchar_t _TCHAR
# define _T(x) L##x
#else
typedef char
_TCHAR
# define
_T(x) x
#endif
Если константа _UNICODE не определена, то оператор:
_TCHAR *p = _T("делай_что_нужно");
имеет значение:
char *p = "делай_что_нужно";
Если константа _UNICODE
определена, тот же самый оператор получает значение:
wchar_t *p = L"делай_что_нужно";
Пока все хорошо. Вы теперь можете попробовать перенести вашу старую программу в среду Unicode, просто используя свой редактор для замены всех экземпляров char на _TCHAR и помещения всех строковых констант в скобки _T(). Проблема состоит в том, что такой код, как ниже (в котором все _TCHAR
первоначально были типа char), более не работает:
_TCHAR str[4];
// ...
int max_chars = sizeof(str); // предполагает, что тип char
// имеет
размер 1 байт
Тип _TCHAR
будет иметь размер 2 байта при определенной константе _UNICODE, поэтому число символов у вас будет определено в два раза большим, чем есть на самом деле. Для исправления ситуации вы должны воспользоваться следующим вариантом:
int max_chars = sizeof(str) / sizeof(*str);