Из указанного выше подхода следует сделать одно исключение. Поскольку в некоторых средах компиляции тип данных off_t имеет размерность long long, мы приводим off_t-значения к этому типу и в соответствии с описанием из раздела 5.10 используем спецификатор %lld.

В стандарте C99 для printf() определен модификатор длины z, показывающий, что Результат следующего целочисленного преобразования соответствует типу size_t или ssize_t. Следовательно, вместо использования %ld и приведения к этим типам можно указать %zd для ssize_t и аналогично %zu для size_t. Хотя этот спецификатор доступен в glibc, нам нужно избегать его применения, поскольку он доступен не во всех реализациях UNIX.

В стандарте C99 также определен модификатор длины j, который указывает на то, что соответствующий аргумент имеет тип intmax_t (или uintmax_t) — целочисленный тип, гарантированно достаточно большой для представления целого значения любого типа. По сути, использование приведения к типу (intmax_t) и добавление спецификатора %jd должно заменить приведение к типу (long) и задание спецификатора %ld, а также стать лучшим способом вывода числовых значений типов системных данных. Первый подход справляется и со значениями long long, и с любыми расширенными целочисленными типами, такими как int128_t. Но и в данном случае нам следует избегать применения этой методики, поскольку она доступна не во всех реализациях UNIX.

3.6.3. Прочие вопросы, связанные с портированием

В этом разделе рассматриваются некоторые другие вопросы портирования, с которыми можно столкнуться при написании системных программ.

Инициализация и использование структур

В каждой реализации UNIX указывается диапазон стандартных структур, используемых в различных системных вызовах и библиотечных функциях. Рассмотрим в качестве примера структуру sembuf, которая применяется для представления операции с семафором, выполняемой системным вызовом semop():

struct sembuf {

unsigned short sem_num; /* Номер семафора */

short sem_op; /* Выполняемая операция */

short sem_flg; /* Флаги операции */

};

Хотя в SUSv3 определены такие структуры, как sembuf, важно уяснить следующее.

• Обычно порядок определения полей внутри таких структур не определен.

• В некоторых случаях в такие структуры могут включаться дополнительные поля, имеющие отношение к конкретной реализации.

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

struct sembuf s = { 3, -1, SEM_UNDO };

Хотя этот инициализатор будет работать в Linux, он не станет работать в других реализациях, где поля в структуре sembuf определены в ином порядке. Чтобы инициализировать такие структуры портируемым образом, следует воспользоваться явно указанными инструкциями присваивания:

struct sembuf s;

s. sem_num = 3;

s. sem_op = -1;

s. sem_flg = SEM_UNDO;

Если применяется C99, то для написания эквивалентной инициализации можно воспользоваться новым синтаксисом:

struct sembuf s = {.sem_num = 3, sem_op = -1, sem_flg = SEM_UNDO };

Порядок следования элементов стандартных структур также придется учитывать, если нужно записать содержимое стандартной структуры в файл. Чтобы обеспечить в данном случае портируемость, мы не можем просто выполнить двоичную запись в структуру. Вместо этого поля структуры должны быть записаны по отдельности (возможно, в текстовом формате) в указанном порядке.

Использование макросов, которых может не быть во всех реализациях

В некоторых случаях макрос может быть не определен во всех реализациях UNIX. Например, широкое распространение получил макрос WCOREDUMP() (проверяет, создается ли дочерним процессом файл дампа ядра), но его определение в SUSv3 отсутствует. Следовательно, этот макрос может быть не представлен в некоторых реализациях UNIX. Чтобы для обеспечения портируемости преодолеть подобные обстоятельства, можно воспользоваться директивой препроцессора языка C #ifdef:

#ifdef WCOREDUMP

/* Использовать макрос WCOREDUMP() */

#endif

Отличия в требуемых заголовочных файлах в разных реализациях

В зависимости от реализации UNIX будут различаться списки необходимых прототипу заголовочных файлов с различными системными вызовами и библиотечными функциями. В данной книге показываются требования применительно к Linux и обращается внимание на любые отклонения от SUSv3.

В некоторых функциях, кратко рассматриваемых в книге, показан конкретный заголовочный файл, сопровождаемый комментарием /* For portability */ (/* Из соображений портируемости */). Это свидетельствует о том, что данный заголовочный файл для Linux или согласно SUSv3 не требуется, но, поскольку некоторым другим (особенно старым) реализациям он может понадобиться, нам приходится включать его в портируемые программы.

Перейти на страницу:

Похожие книги