Короткая заметка о том, как соотносятся размеры целочисленных типов с разрядностью машины (процессора, контроллера).
Лет 10-15 назад я почему-то думал, что размер int'a (sizeof (int)) равен разрядности машины. Не знаю откуда я это взял, может, я как-то по-своему интерпретировал слова Б.Кернигана и Д.Ритчи:
Но выглядела эта идея довольно красиво — представьте себе, что у вас int всегда имеет размер разрядности машины: 16 — для 286, 32 — для 386 и после, 64 — для Itanium (или кто там был первым среди x86-64?). В последствии, на практике, я увидел, что это не так.
Недавно (неделю-две назад) я решил окончательно разобраться с этим вопросом. Опишу это здесь.
Мои изыскания привели к следующим результатам:
1. Размер int'а никак не связан с разрядностью машины. Стандарт языка C описывает только одно правило соотношения между базовыми типами:
sizeof (short) <= sizeof (int) <= sizeof (long)
по-русски гласящее, что тип short будет либо меньше, либо равен int, который, в свою очередь, либо меньше, либо равен long. На практике, мы видим, что чаще всего размер int'а равен 4 байтам. Но размеры этих типов не определяются стандартом.
2. Да, функцией sizeof () можно определить разрядность машины — только не через размер типа, а через размер указателя на тип (подойдёт любой тип). Именно размер указателя равен разрядности машины, так как разрядность — это не только количество бит, с которыми машина работает за один такт и/или размер инструкции, но и размер поддерживаемого объёма памяти, для адресации которого машина выделяет и оперирует типами соответствующего размера. То есть, чтобы узнать разрядность машины можно воспользоваться sizeof([любой тип]*), например sizeof(int*).
Так как функция sizeof () реализована так, что размерности типов (и прочих констант) подставляются в момент компиляции (compile-time), по сути дела информативность её достаточно мала в силу того, что разрядность процессора задаётся (и может быть ограничена) компилятором и/или операционной системой и результат выполнения её после компиляции будет одинаков при всех последующих запусках. Для определения разрядности машины есть макрос __LP64__ и __LP32__ соответственно (эти макросы означают модель памяти, о 64-ёх разрядной можно почитать здесь 64 bit data models). Макрос использованный в коде, на этапе компиляции развернётся и не будет занимать процессорного времени на этапе выполнения, при этом выполнит задачу sizeof (указатель на тип).
Завершим описанное демонстрацией простенькой программой:
#include "stdio.h"
int main ()
{
printf ("Compiled on ");
#if defined(__LP64__)
printf ("64-bit platform\n");
#endif
#if defined (__LP32__)
printf ("32-bit platform\n");
#endif
printf ("sizeof (char)\t= %d bytes\n", sizeof(char));
printf ("sizeof (short)\t= %d bytes\n", sizeof(short));
printf ("sizeof (int)\t= %d bytes\n", sizeof(int));
printf ("sizeof (long)\t= %d bytes\n", sizeof(long));
printf ("sizeof (float)\t= %d bytes\n", sizeof(float));
printf ("sizeof (double)\t= %d bytes\n", sizeof(double));
printf ("sizeof (int*)\t= %d bytes\n", sizeof(int*));
}
И проверяем:
gcc ./main.c && ./a.out
Compiled on 64-bit platform
sizeof (char) = 1 bytes
sizeof (short) = 2 bytes
sizeof (int) = 4 bytes
sizeof (long) = 8 bytes
sizeof (float) = 4 bytes
sizeof (double) = 8 bytes
sizeof (int*) = 8 bytes
64-ёх битная платформа (определена макросом и вычислением sizeof(int*)), и правило
sizeof (short) <= sizeof (int) <= sizeof (long)
выполняется.
В этой заметке мы использовали байты в качестве единицы измерения. Далее планирую написать о том из чего байты состоят — о битах, и об их разновидностях. Позже разберёмся более детально в так называемых моделях памяти.
В этой заметке мы использовали байты в качестве единицы измерения. Далее планирую написать о том из чего байты состоят — о битах, и об их разновидностях. Позже разберёмся более детально в так называемых моделях памяти.
No comments:
Post a Comment