Типы, специфичные для интерфейса |
Предыдущая Содержание Следующая |
Некоторые из наиболее часто используемых типов данных в ядре имеют свои собственные операторы typedef, предотвращая таким образом любые проблемы переносимости. Например, идентификатор процесса (pid) обычно pid_t, вместо int. Использование pid_t маскирует любые возможные различия в фактическом типе данных. Мы используем выражение специфичные для интерфейса для обозначения типов, определённых библиотекой, с тем, чтобы предоставить интерфейс к определённой структуре данных.
Отметим, что в последнее время были определено сравнительно мало новых типов, специфичных для интерфейса. Использование оператора typedef вошло в немилость у многих разработчиков ядра, которые предпочли бы видеть реальную информацию об используемом типе непосредственно в коде, а не скрывающейся за определённым пользователем типом. Однако, многие старые специфичные для интерфейса типы остаются в ядре и они не уйдут в ближайшее время.
Даже тогда, когда нет определённого интерфейсного типа, всегда важно использовать правильный типа данных для совместимости с остальной частью ядра. Счётчик тиков, например, всегда unsigned long, независимо от его фактического размера, так что при работе с тиками всегда должен быть использован тип unsigned long. В этом разделе мы сосредоточимся на использовании типов _t.
Многие _t типы определены в <linux/types.h>, но этот список редко бывает полезен. Когда вам потребуется определённый тип, вы будете находить его в прототипе функции, которую вам необходимо вызвать, или в структурах используемых данных.
Каждый раз, когда драйвер использует функции, которые требуют такого "заказного" типа, и вы не следуете соглашению, компилятор выдаёт предупреждение; если вы используете флаг компилятора -Wall и тщательно удаляете все предупреждения, вы можете быть уверены, что ваш код является переносимым.
Основной проблемой с элементами данных _t является то, что когда вам необходимо их распечатать, не всегда просто выбрать правильный формат printk или printf и предупреждения, которые вы убираете на одной архитектуре, снова появляются на другой. Например, как бы вы напечатали size_t, который является unsigned long на одних платформах и unsigned int на других?
Если вам необходимо распечатать некоторые специфичные для интерфейса данные, наилучшим способом сделать это является приведение типа значения к наибольшему возможному типу (как правило, long или unsigned long) и затем печать их через соответствующий формат. Такой вид корректировки не будет генерировать ошибки или предупреждения, потому что формат соответствует типу, и вы не потеряете биты данных, потому что приведение либо ничего не делает, либо увеличивает объект до большего типа данных.
На практике, объекты данных, о которых мы говорим, обычно не предназначены для печати, так что вопрос распространяется только на сообщения об отладке. Чаще всего коду необходимо только запоминать и сравнивать типы, специфичные для интерфейса, в дополнение к передаче их в качестве аргумента в библиотечные функции или функции ядра.
Хотя _t типы являются правильным решением для большинства ситуаций, иногда правильного типа не существует. Это происходит на старых интерфейсах, которые ещё не были очищены.
Одним неоднозначным моментом, который мы нашли в заголовках ядра, является типизация данных для функций ввода/вывода, которые определены небрежно (смотрите раздел "Зависимость от платформы" в Главе 9). Небрежные типы в основном существуют по историческим причинам, но это может создать проблемы при написании кода. Например, можно попасть в беду, меняя аргументы функций, таких как outb; если бы существовал тип port_t, компилятор бы нашёл этот тип ошибки. |
Предыдущая Содержание Следующая |