понедельник, 11 апреля 2011 г.

11.1. Использование стандартных типов языка Си


Использование стандартных типов языка Си
Хотя большинство программистов привыкли свободно использовать стандартные типы, такие как int и long, написание драйверов устройств требует некоторой осторожности, чтобы избежать конфликтов типов и неясных ошибок.

Проблема в том, что вы не можете использовать стандартные типы, когда необходим "2-х байтовый наполнитель" или "что-то, представляющее 4-х байтовые строки", потому что обычные типы данных Си не имеют одинакового размера на всех архитектурах. Чтобы показать размер данных различных типов Си, в файлы примеров, представленных на FTP сайте O'Reilly, в каталог misc-progs была включена программа datasize. Это пример запуска программы на системе i386 (последние четыре показанных типа будут введены в следующем разделе):

morgana% misc-progs/datasize
arch   Size: char short int long ptr long-long u8 u16 u32 u64
i686           1    2    4    4   4     8       1   2   4   8

Программа может быть использована, чтобы показать, что целочисленные long и указатели имеют различные размеры на 64-х разрядных платформах, что демонстрирует запуск программы на другом компьютере с Linux:

arch   Size: char short int long ptr long-long u8 u16 u32 u64
i386           1    2    4    4   4     8       1   2   4   8
alpha          1    2    4    8   8     8       1   2   4   8
armv4l         1    2    4    4   4     8       1   2   4   8
ia64           1    2    4    8   8     8       1   2   4   8
m68k           1    2    4    4   4     8       1   2   4   8
mips           1    2    4    4   4     8       1   2   4   8
ppc            1    2    4    4   4     8       1   2   4   8
sparc          1    2    4    4   4     8       1   2   4   8
sparc64        1    2    4    4   4     8       1   2   4   8
x86_64         1    2    4    8   8     8       1   2   4   8

Интересно отметить, что архитектура SPARC 64 работает с 32-х разрядным пространством пользователя, имея там указатели размерностью 32 бита, хотя они и 64 бита в пространстве ядра. Это может быть проверено загрузкой модуля kdatasize (доступного в каталоге miscmodules файлов примеров). Модуль сообщает информацию о размерах во время загрузки используя printk и возвращает ошибку (то есть, нет необходимости его выгружать):

kernel: arch   Size: char short int long ptr long-long u8 u16 u32 u64
kernel: sparc64        1    2    4    8   8     8       1   2   4   8

Хотя вы должны быть осторожны при смешивании различных типов данных, иногда для этого бывают веские причины. Одной из таких ситуаций является адресация памяти, которая особо касается ядра. Хотя концептуально адреса являются указателями, управление памятью зачастую лучше выполняется с использованием типа беззнакового целого; ядро обрабатывает физическую память, как огромный массив, и адрес память является просто индексом внутри массива. Кроме того, указатель легко разыменовывается; при непосредственной работе с адресами памяти вы почти никогда не хотите их разыменовывать таким образом. Использование целочисленного типа мешает такому разыменованию, что позволяет избежать ошибок. Таким образом, обычные адреса памяти в ядре, как правило, unsigned long, эксплуатируя тот факт, что указатели и целые long всегда одного и того же размера, по крайней мере, на всех платформах в настоящее время поддерживаемых Linux.

Кому это интересно, стандарт C99 определяет для целочисленной переменной типы intptr_t и uintptr_t, которая может содержать значение указателя. Однако, эти типы почти не использовались в ядре версии 2.6.

Комментариев нет:

Отправить комментарий

Примечание. Отправлять комментарии могут только участники этого блога.