Вопрос в количестве битов в программировании на языке Си

#c #integer #sizeof

#c #целое число #sizeof

Вопрос:

Если я сделаю

int a = 3, тогда 3 будет представлено в двоичном формате с 32 битами.

Если я сделаю

char a = 3, тогда 3 будет представлено в двоичном формате с 8 битами.

Мой вопрос заключается в том, прежде чем выполнять инициализацию значением, сколько битов представлено 3?

(Другими словами, сколько битов имеет «3» в правой части знака равенства)

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

1. Вы не можете сказать наверняка. Вы можете только сказать, что это тип signed int , который может варьироваться в зависимости от вашей системы. Я бы рекомендовал вам #include <stdint.h> иметь возможность определять размер и знак констант, например, используя макрос UINT32_C(3) для представления 3 в виде 32-разрядного int без знака.

2. Я слышал о некоторых реализациях, имеющих int -s со 128 битами и 16 бит char -s (эмулируемых). Проверьте, купив, а затем прочитав последний стандарт ISO C или, по крайней мере, n1570

Ответ №1:

Очень распространено, что int имеет 32 бита, но это не гарантировано. Оно также может быть 16 или 64. Или выше.

Single — 3 это целочисленный литерал типа int .

Ответ №2:

Вы можете проверить это с помощью sizeof operator . Это даст вам размер аргумента в байтах. Просто попробуйте получить размер int , a и 3 .

 #include <stdio.h>
int main()
{
    int a = 3;
    printf("%ldn", sizeof(a)); // gives 4 bytes (32 bit) on my PC 
    printf("%ldn", sizeof(int)); // gives 4 bytes (32 bit) on my PC 
    printf("%ldn", sizeof(3)); // gives 4 bytes (32 bit) on my PC 

    return 0;
}
 

Кроме того, 3 имеет тип int . Таким образом, его размер равен размеру int .

Ответ №3:

Размер объекта типа int определяется реализацией, стандарт предъявляет только требование, которое INT_MAX не должно быть меньше 32767 , чем это 2 ^ 15 - 1

Если в вашей системе размер объекта типа int равен 4, то целочисленная константа like 3 будет занимать блок памяти, равный 4 байтам.

Обратите внимание на то, что, например, символьная целочисленная константа также имеет тип int .

Итак, в обоих этих объявлениях

 char a = 3;
 

и

 char a = '3';
 

константы 3 и '3' имеющие тип int занимают 4 байты, если sizeof( int ) равно 4 .

Ответ №4:

Называется 3 целочисленной константой и имеет тип, очень похожий на любую именованную переменную. Это всегда тип, int если введенное число может поместиться внутри int . В противном случае, если оно не может поместиться, компилятор попытается поместить его в a long , тогда long long .

Существуют различные довольно сложные правила для того, как это делается, я не буду упоминать здесь все грязные детали — те, кто интересуется этим, могут проверить таблицы в стандарте C 6.4.4.1. Для среднего программиста, вероятно, достаточно знать, что мы также можем принудительно использовать целочисленную константу без знака с помощьюдобавление U суффикса или принудительное long добавление L суффикса. Это 3U или 3L или комбинация 3UL . (Нижний регистр u и l тоже работает.)

На реальных компьютерах int всегда имеет размер 2 или 4 байта. long имеет размер 4 или 8 байт. Пример с 64-разрядного компьютера Linux с 4 байтами int и 8 байтами long :

 #include <stdio.h>
  
int main (void)
{
  printf("%zun", sizeof(int));        // 4
  printf("%zun", sizeof(3));          // 4
  printf("%zun", sizeof(3L));         // 8
  printf("%zun", sizeof(2147483647)); // 4, fits int
  printf("%zun", sizeof(2147483648)); // 8, doesnt fit
}
 

https://godbolt.org/z/3675zv

Ответ №5:

Вопрос «сколько битов представлено 3?» на самом деле сложный. Если мы сможем найти 3, мы сможем ответить на него. Итак, вопрос: где 3?

Что на самом деле происходит, так это:

 int a = 3;
 

это то же самое, что:

 int a;
a = 3;
 

Компилятор гарантирует, что для переменной будет 4 байта a свободного места (он делает это во время компиляции), а затем он также помещает в программу инструкцию, которая сохраняет число 3 в этом пространстве при запуске программы.

Мы можем использовать этот полезный онлайн-инструмент для компиляции программы и посмотреть, какой ассемблерный / машинный код фактически выводит компилятор: https://godbolt.org/z/a9Pohn

В этом случае я вошел в программу:

 int main() {
    int a;
    a = 3;
}
 

и скомпилировал его с помощью «x86-64 gcc 10.2», без оптимизации. Вот скомпилированный код (как ассемблерный, так и машинный):

 main:
 55                     push rbp
 48 89 e5               mov rbp,rsp
 c7 45 fc 03 00 00 00   mov DWORD PTR [rbp-0x4],0x3
 b8 00 00 00 00         mov eax,0x0
 5d                     pop rbp
 c3                     ret 
 

Если мы сможем прочитать сборку, мы увидим, что инструкция, которую компилятор выбрал для вставки в программу для инициализации переменной a , была mov DWORD PTR [rbp-0x4],0x3 . И в машинном коде это записано c7 45 fc 03 00 00 00 . Инструкция — это то, откуда берется число 3.

Длина инструкции составляет 7 байт. c7 45 сообщите процессору, что это за инструкция («поместите определенное число в определенную позицию в кадре стека»). fc это позиция во фрейме стека. И 03 00 00 00 это конкретное число, которое оно туда помещает (в формате с малым порядковым номером). Это число 3 в исходном коде. Таким образом, в этом случае оно занимает 4 байта.


Обратите внимание, что это не всегда одно и то же. Если мы компилируем для процессора ARM вместо x86-64, то это соответствующие инструкции

 mov r3, #3
str r3, [fp, #-8]
 

К сожалению, godbolt не показывает нам машинный код, но мы можем посмотреть инструкцию MOV # в руководстве ARM, в котором говорится, что длина инструкции составляет 4 байта, а перемещаемое число занимает всего 2 из этих байтов! Остальные биты автоматически обнуляются. Если вы используете число, которое не умещается в 2 байта, очевидно, что оно использует другую инструкцию.

Обычно мы не говорим о размерах инструкций, поскольку они различаются намного больше, чем размеры данных. int a; всегда резервируется 4 байта (если в вашей системе int 4 байта), но инструкция, которая помещает определенные биты в это пространство, может иметь разные размеры.


Даже на x86-64 числа могут занимать разное количество места. Если я это сделаю return 0; , компилятор преобразует это в xor eax, eax ( 31 c0 ) . 0 В этой инструкции вообще нет числа! ( 31 c0 это все типы инструкций, без данных)