Язык
Компиляторы ANSI С должны воспринимать и прежний синтаксис, но мы настоятельно рекомендуем вам забыть об этом и всегда писать прототипы для всех функций. Это сделает код более безопасным, вызовы функций будут полностью проверены на совместимость типов, и при изменении интерфейса компилятор это отловит. Если в коде употребляется вызов:
func(7, PI);
Afunc не имеет прототипа, компилятор не сможет проверить корректность такого вызова. Если библиотека впоследствии изменится так, что у func станет три аргумента, компилятор не сможет предупредить о необходимости внесения изменений в программу, потому что старый синтаксис не предусматривает проверки типов аргументов функций.
C++ – более мощный и обширный язык, и стандарт его появился лишь недавно, поэтому говорить об основном русле применительно к нему несколько сложнее. Например, нам представляется очевидным, что STL войдет в это основное русло, что происходит, однако, не мгновенно, и поэтому некоторые существующие реализации языка поддерживают STL не в полной мере.
Избегайте неоднозначных конструкций языка.
Как мы уже говорили, некоторые вещи в стандартах умышленно оставлены неопределенными для того, чтобы предоставить создателям компиляторов большую свободу для маневра. Список таких неопределенностей обескураживающе велик.
Размеры типов данных.
Размеры основных типов данных в С и C++ не определены. Не существует никаких гарантированных свойств, кроме общих правил, гласящих, что:
sizeof(char) <= sizeof (short) <= sizeof(int) <= sizeof(long) sizeof(float) <= sizeof(double) %
А также, что char должен иметь как минимум 8 битов, short и int – как минимум 16, a long – по крайней мере 32. Не требуется даже, чтобы значение указателя умещалось в inj.
Проверить, какие значения использует конкретный компилятор, достаточно просто:
Результат будет одинаковым для большинства распространенных машин:
char 1, short 2, int 4, long 4, float 4, double 8, void* 4
Однако возможны и другие значения. Некоторые 64-битовые машины покажут такие значения:
char 1, short 2, int 4, long 8, float 4, double 8, void* 8
А ранние компиляторы под PC показали бы такое:
char 1, short 2, int 2, long 4, float 4, double 8, void* 2
Во времена появления PC аппаратура поддерживала несколько видов указателей. Для того чтобы справиться с такой неразберихой, были придуманы модификаторы указателей far и near, ни один из которых не входит в стандарт, но до сих пор эти ключевые слова-призраки появляются во многих компиляторах. Если ваш компилятор может менять размеры базовых типов или если вы имеете доступ к машинам, поддерживающим другие размеры, постарайтесь скомпилировать и оттестировать вашу программу при таких новых для нее условиях.
Стандартный заголовочный файл stddef.h определяет ряд типов, которые могут помочь с переносимостью. Наиболее часто используемый из них – size_t, который представляет собой тип беззнакового целого, возвращаемого оператором sizeof. Значения этого типа возвращаются функциями типа strlen и во многих функциях, включая mallос, используются в качестве аргументов.
Наученная чужим горьким опытом, Java четко определяет размеры всех своих базовых типов: byte – 8 битов, char и short – 16, int – 32 и long – 64 бита.
Мы не будем рассматривать набор проблем, связанных с вычислениями с плавающей точкой, потому что разговор об этом достоин отдельной книги. Скажем только, что большинство современных машин поддерживают стандарт IEEE на аппаратуру для плавающей точки, и, следовательно, для них свойства арифметики с плавающей точкой определены достаточно четко.