Главная » Ядро Linux » Размер машинного слова и типы данных

0

Машинное слово   (word)  — это  количество данных,  которые процессор  может обработать за  одну  операцию. Здесь  можно  применить  аналогию документа, состоящего  из  символов   (character,  8 бит)  и  страниц  (много слов).   Слово—  это  некоторое количество битов, как  правило 16, 32 или  64.  Когда  говорят о  "n-битовой" машине, то чаще  всего  имеют  в виду  размер  машинного слова.  Например, когда  говорят, что процессор Intel  Pentium — это  32-разрядный процессор, то обычно имеют  в виду размер  машинного слова, равный 32 бит, или  4 байт.

1 Это нормальная ситуация при  разработке ядра.  Если  что-либо должно  быть  сделано,  то это должно  быть  сделано  хорошо !  Разработчики ядра  неохотно  переписывают большие  участки  кода  даже во имя  совершенства.

Размер  процессорных регистров общего  назначения равен  размеру  машинного слова этого  процессора. Обычно разрядность остальных компонентов этой  же аппаратной  платформы в точности равна размеру машинного слова.  Кроме того, по крайней  мере  для аппаратных платформ, которые поддерживаются ОС  Linux, размер адресного пространства  соответствует размеру  машинного слова2.  Следовательно, размер  указателя равен  размеру  машинного слова.  В дополнение к этому, размер типа  long языка  С также  равен  размеру  машинного слова.  Например, для аппаратной  платформы Alpha размер  машинного слова  равен  64 бит.  Следовательно, регистры, указатели и тип  long имеют  размер  64 бит. Тип  in t для этой  платформы имеет размер  32 бит.  Машины платформы Alpha могут обработать 64 бит— одно  слово  с помощью одной  операции.

Слова,  двойные  слова  и путаница

Для некоторых  операционных систем  и процессоров стандартную  порцию  данных не называют машинным  словом.  Вместо  этого,  словом  называется  некоторая  фиксированная порция данных, название  которой  выбрано случайным  образом  или имеет исторические корни.  Например,  в некоторых  системах  данные  могут  разбиваться  на байты (byte — 8 бит),  слова (word — 16 бит), двойные  слова (double  word — 32 бит)  и четверные  слова  (quad  word — 64 бит),  несмотря  на то что на самом  деле система  является 32-разрядной. В этой  книге  и вообще  в контексте операционной системы  Linux под  машинным  словом  понимают  стандартную  порцию  данных  процессора, как обсуждалось ранее.

Для каждой  аппаратной платформы, поддерживаемой операционной системой Linux, в файле  <asm/types.h> определяется константа BITTS_PER_LONG,  которая равна  размеру  типа  long языка  С и совпадает с размером машинного слова системы. Полный список всех поддерживаемых аппаратных платформ и их размеры машинного  слова приведены в табл. 19.1.

Стандарт языка  С явно  указывает, что размер  памяти, которую  занимают переменные стандартных типов  данных, зависит  от аппаратной реализации3, при  этом также  определяется минимально возможный размер  типа.  Неопределенность размеров  стандартных типов  языка  С для  различных аппаратных платформ имеет  свои положительные и отрицательные стороны. К плюсам  можно  отнести  то, что для стандартных типов  языка  С можно  пользоваться преимуществами, связанными с размером  машинного слова, а также  отсутствие  необходимости явного  указания размера. Для ОС Linux размер  типа  long гарантированно равен  размеру  машинного слова. Это не совсем  соответствует стандарту  ANSI  С, однако  является стандартной практикой  в ОС Linux.  Как  недостаток можно  отметить, что при разработке кода нельзя рассчитывать на то, что данные  определенного типа  занимают в памяти определенный  размер.  Более  того, нельзя  гарантировать, что переменные типа int занимают столько  же памяти, сколько и переменные типа  long4 .

2 Разме р адресуемо й  памят и  може т быт ь  меньш е  максимальног о  значени я   машинног о слова. Например , для 64-разрядных аппаратных платфор м разме р указателя  ранен  64 бит, однако  только

48 бит можно  использовать для адресации. В дополнени е к этому, общее  количество физическо й памяти  может  быть больше  максимального значени я машинного слова, как, например , эт о имеет место при наличии расширени я  Intel  PAE.

3 За исключением размера  типа  char , которы й всегда равен  8 бит.

4 На самом  деле, для 64-разрядных аппаратных платформ , которы е поддерживаются ОС  Linux, размеры  типов  in t и  lon g не  совпадают. Размер  тип а int  равен  32 бит, а размер  типа  lon g — 64 бит. Дл я хорош о знакомых 32-раphядных аппаратных платфор м оба типа данных  имеют  разме р 32 бит.

Таблица 19.1 . Поддерживаемые аппаратные платформы

Аппаратная платформа                   Описание                                          Размер машинного слова

alpha arm cris h8300

I386

ia64 m68k m86knommu mips

mips64 parisc ppc ppc64 s390

sh spare sparc64 um

v850

x8_ 64

Digital Alpha

ARM и StrongARM CRIS

H8/300

Intel x86

IA-64

Motorola 68k

m68k без устройства MMU MIPS

64-разрядная MIPS

HP PA-RISC PowerPC POWER

IBM S/390

Hitachi SH SPARC UltraSPARC Usermode Linux v850

X86-64

64 бит

32 бит

32 бит

32 бит

32 бит

64 бит

32 бит

32 бит

32 бит

64 бит

32 бит, или 64 бит

32 бит

64 бит

32 бит, или 64 бит

32 бит

32 бит

64 бит

32 бит, или 64 бит

32 бит

64 бит

Ситуация еще более запутывается тем, что одни  и те же типы данных  в пространстве  пользователя и в пространстве ядра  не  обязательно должны  соответствовать друг другу. Аппаратная платформа sparc64  предоставляет 32-разрядное пространство пользователя, а поэтому  указатели, типы  in t и long имеют  размер  32 бит.  Однако в пространстве ядра для аппаратной платформы размер  типа  in t равен  32 бит, а размер указателей и типа  long равен  64 бит.  Тем  не менее  такая  ситуация не является обычной.

Всегда необходимо помнить о следующем.

• Как  и требует стандарт  языка  С, размер  типа char всегда равен  8 бит (1 байт),

• Нет  никакой гарантии, что  размер  типа  in t для всех поддерживаемых аппаратных  платформ будет равен  32 бит, хотя сейчас  для всех платформ он равен  именно этому числу.

• То же касается и типа  short , который для всех поддерживаемых аппаратных платформ сейчас  равен  16 бит.

• Никогда нельзя  надеяться, что тип  long или указатель  имеет некоторый заданный  размер.  Этот  размер  для  поддерживаемых аппаратных платформ  может быть равен  32, или  64 бит.

• Так  как  размер  типа  lon g разный для  различных аппаратных платформ,  никогда  нельзя предполагать,  что  sizeo f (int.)     ==  sizeo f (long) .

• Точно  так  же нельзя предполагать, что  размер  типа  int  и размер  указателя  совпадают.

Скрытые типы данных

Скрытые  (opaque)  типы  данных  — это  те  типы, для  которых не  раскрывается их  внутренняя  структура, или  формат.  Они   похожи   на  черный ящик,  насколько это можно реализовать в языке программирования С.  В этом  языке программирования нет  какой-либо  особенной поддержки для  этих  типов. Вместо  этого, разработчики определяют новый  тип  данных   через  оператор  typedef ,  называют его  скрытым и надеются на  то, что  никто не  будет  преобразовывать этот  тип  в  стандартный тип данных  языка С.  Любые  использования данных  этих  типов  возможны только   через специальные интерфейсы,  которые также  создаются разработчиком. Примером может  быть  тип  данных   pid_t , в котором хранится информация  об  идентификаторе процесса.  Размер этого  типа  данных  не  раскрывается, хотя  каждый может  смошенничать,  использовать размер   по  максимуму и  работать   с  этим  типом, как  с  типом int.  Если  нигде  явно  не  используется размер  скрытого типа  данных, то размер  этого типа  может  быть  изменен, и  это  не  вызовет никаких  проблем. На  самом  деле  так уже  однажды случилось: в старых  Unix-подобных  операционных системах тип  pid_ t был  определен как  ahort .

Еще  один  пример скрытого типа  данных  — это  тип  atomic_t .  Как  уже  обсуждалось  в главе  9, "Средства синхронизации  в ядре",  этот  тип  содержит данные целочисленного типа, с которыми можно выполнять атомарные операции. Хотя  этот  тип и  соответствует типу  int, использование скрытого типа  данных  позволяет гарантировать, что  данные этого  типа  будут  использоваться только   в  специальных функциях, которые выполняют атомарные операции. Скрытые типы  позволяют скрыть размер типа  данных, который не  всегда  равен  полным 32 разрядам, как  в случае  платформы SPARC.

Другие  примеры скрытых типов  данных  в ядре  — это  dev_t , gi d _t  и uid_t . При работе  со  скрытыми типами данных  необходимо помнить о  следующем.

• Нельзя предполагать, что  данные скрытого типа  имеют  некоторый  определенный  размер  в памяти.

• Нельзя преобразовывать скрытый тип  обратно в стандартный тип  данных.

Разрабатывать код  необходимо с учетом  того, что  размер  и  внутреннее представление  скрытого типа  данных  могут  изменяться.

Специальные типы данных

Некоторые данные в ядре, кроме  того, что  представляются с  помощью скрытых типов, требуют  еще  и специальных типов  данных. Два примера — счетчик импульсов системного  таймера  jiffie s  и  параметр  flags ,  используемый для  обработки прерываний. Для  хранения этих  данных  всегда  должен   использоваться тип  unsigne d long .

При  хранении и использовании специфических данных  всегда  необходимо обращать  особенное внимание на тот тип данных, который представляет эти данные, и использовать именно его. Часто  встречающейся ошибкой является использование другого  типа,   например типа  unsigne d   int . Хотя  для  32-разрядных аппаратных платформ это  не приведет  к проблемам, на 64-разрядных системах  возникнут проблемы.

Типы с явным указанием размера

Часто  при  программировании необходимы типы  данных  заданного размера. Обычно это  необходимо для  удовлетворения некоторых внешних требований, связанных с аппаратным обеспечением, сетью  или  бинарной совместимостью. Например,  звуковой адаптер  может  иметь  32-разрядный регистр, пакет  сетевого протокола — 16-разрядное поле  данных, а исполняемый файл  8 битовый идентификатор cookie.  В этих случаях  тип, который представляет данные, должен  иметь точно заданный размер.

В ядре типы  данных  явно заданного размера  определены в файле  <asm/types.h>, который включается из файла  <linux/types.h> . В табл.  19.2 приведен полный список таких типов  данных.

Таблица 19.2. Типы данных явно заданного размера

Тип                                    Описание

s8 u8 s16 ul6 s32 u32 s64 u64

байт со знаком байт без знака

16-разрядное целое число со знаком

16-разрядное целое число без знака

32-разрядное целое число со знаком

32-разрядное целое число без знака

64-разрядное целое число со знаком

64-разрядное целое число без знака

Варианты сo знаком используются редко.

Эти типы  данных, с явно  заданным размером, просто  определены с помощью оператора typedef  через  стандартные типы  данных  языка  С.  Для  64-разрядной машины они  могут быть определены следующим образом.

typedef signed char s8; typedef unsigned char u8; typedef signed short s16; typedef unsigned short ul6; typedef signed int s32; typedef unsigned int u32; typedef signed long s64; typedef unsigned long u64;

Для 32-разрядной машины их можно определить, как показано ниже. typedef signed char s8;

typedef unsigned char u8; typedef signed short s16; typedef unsigned short ul6; typedef signed int s32; typedef unsigned int u32; typedef signed long long s64;

typedef unsigned long long u64;

Знак типа данных cha r

В стандарте языка С  сказано, что  тип  данных cha r может быть  со  знаком или  без знака. Ответственность за  определение того, какой вариант типа данных cha r  использовать по  умолчанию, лежит на  компиляторе, препроцессоре или  на  обоих.

Для  большинства аппаратных платформ тип  cha r является знаковым, а диапазон значений данных этого типа от  -128  до  127.  Для  небольшого количества аппаратных платформ, таких как  ARM, тип  cha r по  умолчанию без  знака, а возможные значения данных этого типа лежат в диапазоне от 0 до 255.

Например, для  систем, на  которых тип   cha r  без  знака, выполнение следующего кода приведет к записи в переменную i числа 255  вместо -1 .

char i = -1;

На  других машинах,  где  тип   cha r  является знаковым, этот  код  выполнится правильно и  в переменную i запишется значение -1 . Если действительно нужно, чтобы в любом случае было записано  значение -1 , то  предыдущий код  должен выглядеть следующим образом.

signed char i = -1;

Если в  вашем коде используется тип  данных char , то  следует помнить,  что  этот тип  может на  самом деле  быть  как   signe d   char , так  и  unsigne d   char .  Если необходим строго определенный  вариант,  то  это  нужно явно декларировать.

Источник: Лав,  Роберт. Разработка ядра  Linux, 2-е  издание. : Пер.  с англ.  — М.  : ООО  «И.Д.  Вильяме» 2006. — 448 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии