Для проекта в университете я должен расширить существующее приложение C, которое должно быть в конце работать на большом разнообразии коммерческих и некоммерческих систем Unix (FreeBSD, Солярис, AIX, и т.д.).
Какие вещи я должен рассмотреть, когда я хочу записать программу C, которая является самой портативной?
Лучший совет, который я могу дать, это переходить на другую платформу каждый день, тестируя по ходу дела.
Это заставит различия между платформами бросаться в глаза и одновременно научит вас проблемам переносимости.
Если отложить тестирование на разных платформах на конец, это приведет к неудаче.
Это не так
Обычно хорошей идеей является установка как можно более высокого уровня предупреждений компилятора, чтобы увидеть, на какие вещи компилятор может пожаловаться.
Я писал утилиты C, которые затем поддерживал на 16- и 64-битных архитектурах, в том числе на некоторых 60-битных машинах. Они включали по крайней мере три разновидности "порядка байтов", разные форматы с плавающей запятой, разные кодировки символов и разные операционные системы (хотя преобладала Unix).
При этом, если вы избежите соблазна писать что-то несколько раз и #ifdef основных частей кода, вы обнаружите, что кодирование и тестирование на разных платформах помогает быстрее находить ошибки. В итоге вы создадите более дисциплинированные, понятные и удобные в обслуживании программы.
Одним из конкретных вопросов, который вам, возможно, придется держать в курсе (например, если предполагается, что ваши файлы данных будут работать на разных платформах), является эндианальность.
Числа по-разному представляются на двоичном уровне в разных архитектурах. В системах big-endian старший байт располагается первым, а в системах little-endian первым располагается младший байт.
Если вы запишете необработанные данные в файл в одном эндиане, а затем прочитаете этот файл обратно на системе с другим эндианом, у вас, очевидно, возникнут проблемы.
Вы должны быть в состоянии получить endianness во время компиляции на большинстве систем из sys/param.h
. Если вам нужно определить ее во время выполнения, один из методов - использовать объединение int
и char
, затем установить char
в 1 и посмотреть, какое значение имеет int
.
Это очень длинный список. Лучше всего читать примеры. Например, исходный текст perl. Если вы посмотрите на исходный текст perl, то увидите гигантский процесс создания заголовочного файла, который решает около 50 проблем платформы.
Прочтите его и прослезитесь, или возьмите взаймы.
Список может быть длинным, но он не настолько длинный, как поддержка Windows и MSDOS. Что характерно для многих утилит.
Обычная техника состоит в том, чтобы отделить модули основных алгоритмов от тех, которые имеют дело с операционной системой - по сути, это стратегия многоуровневой абстракции.
Дифференциация между несколькими разновидностями unix довольно проста. Либо придерживайтесь функций, для которых все используют одинаковые RTL-имена, либо смотрите на конвенцию большинства для поддерживаемых платформ и #ifdef
в исключениях.
Постоянно обращайтесь к стандартам POSIX для любых библиотечных функций, которые вы используете. Некоторые части стандарта неоднозначны, и некоторые системы возвращают различные стили кодов ошибок. Это поможет вам упреждающе найти те действительно трудно обнаруживаемые ошибки, которые немного отличаются в реализации.