Напишите sizeof(int), и на современной машине вы почти наверняка получите 4. Логично: int – это 32 бита.Только вот в стандарте C этого нигде не написано.Более того, существовали машины, где int занимал 16 бит, и такие, где 36. Многие считают это главным проколом создателей языка. Но стоит заглянуть в 1970-е, и картина меняется.Давайте вспомним, какие компьютеры тогда были, зачем придумали int и почему это решение дожило до C23. Читать далее
Уровень сложностиСредний
Время на прочтение15 мин
Охват и читатели10K
Ретроспектива
Перевод

Гибкие целочисленные типы в C не были ошибкой проектирования. Именно благодаря им язык добился переносимости в мире 12-, 18-, 36- и 60-битных компьютеров.
Многие разработчики, изучающие язык C, приходят из таких языков, как Python, JavaScript, Java, C#, Swift и другие.
И новичкам не требуется много времени, чтобы понять: многие вещи, которые они воспринимали как данность в своем основном языке, в C вовсе не гарантируются. Довольно часто мы ловим себя на таких вопросах:
Сколько бит эта переменная занимает в памяти?
Какой паддинг (выравнивание) у этой структуры?
Нормально ли это поле выровнено в RAM?
Еще один обряд инициации для начинающих сишников – это понять, как использовать и как вообще работает оператор sizeof.
Видеть, как программа выводит 4, когда у нее запрашивают sizeof(int), кажется вполне логичным, учитывая, что на большинстве современных машин знаковый int действительно занимает 4 байта в памяти.

sizeof(int): 4 байта
К сожалению, мне также приходится говорить моим студентам, что когда я только начинал учиться программировать, если я запрашивал sizeof(int), моя 386-я машина выдавала 2 байта!

sizeof(int): 2 байта
И вот примерно здесь мы начинаем дискуссию о том, что нативные целочисленные типы в C не имеют фиксированного размера. Типы языка вроде char, int, short и long не дают никаких гарантий насчет того, сколько именно байт они занимают в памяти.
Поскольку в коде нам обычно нужны фиксированные размеры, мы обычно предлагаем студентам подключать заголовочный файл STDINT.H, чтобы использовать нормальные типы с фиксированным размером, такие как:
int8_t: знаковые целые, ровно 8 бит
uint8_t: беззнаковые целые, ровно 8 бит
int16_t: знаковые целые, ровно 16 бит
uint16_t: беззнаковые целые, ровно 16 бит
int32_t: знаковые целые, ровно 32 бита
uint32_t: беззнаковые целые, ровно 32 бита
и т. д.
Хедер <STDINT.H> завезли как часть стандарта C99 (вышедшего в 1999 году), и он помогает программистам гарантировать, что их переменные будут занимать точное количество байт вне зависимости от компилятора и архитектуры машины, под которую мы всё это собираем.
В кругах программистов довольно распространено мнение, что платформозависимые целочисленные типы в C были дизайнерским проколом.

Будем честны, в этом есть доля правды. Большинство разрабов, использующих C на современных системах, именно так и скажут. int равен 16 битам на одной машине и 32 битам на другой, long занимает 64 бита на Linux, но 32 на 64-битном Windows, и все это породило десятилетия багов переносимости. Так что, учитывая, что сегодня почти каждый CPU представляет собой 64-битную железку, умеющую в 8, 16, 32 и 64-битную арифметику… почему бы C просто сразу не зафиксировать размеры с самого начала?
По сути, мы тут пытаемся судить дизайнерские решения 1970-х годов по меркам 2020-х! C создавался как портабельный язык системного программирования, который мог бы эффективно мапиться на самые разные компьютерные архитектуры. Гибкие размеры типов не были недосмотром; именно так C и добился этой самой переносимости.
Имейте в виду, что цель C по «переносимости» означала совсем не то, что джавовое обещание переносимости в духе «write once, run anywhere». И чтобы понять почему, надо вспомнить, чем было понятие «компьютер», когда C только проектировался.
❯ Мир до того, как 8-битные байты победилиСегодня мы многое принимаем как данность. Почти любая машина, которую вы пощупаете, имеет:
8-битные байты
Побайтово адресуемую память
32- или 64-битные регистры
Дополнительный код для знаковых чисел
Общепринятую модель памяти
В 1960-х и 70-х ничего из этого гарантировано не было. Индустрия еще не пришла к единому стандарту, и размеры машинных слов были какими угодно:
Машина | Размер слова | Примечания |
|---|---|---|
DEC PDP-8 | 12 бит | Дико популярный мини-компьютер |
DEC PDP-7 | 18 бит | Где на ассемблере родился UNIX |
DEC PDP-11 | 16 бит | Побайтовая адресация; родина C |
DEC PDP-10 / DECSYSTEM-20 | 36 бит | Символы часто упаковывались по 7 или 9 бит |
Серия Honeywell 6000 | 36 бит | 9-битные символы; ранняя цель для C |
UNIVAC 1100 / Unisys 2200 | 36 бит | Арифметика в обратном коде (ones’-complement), 9-битные char’ы; компилятор C для нее есть даже сегодня |
IBM 7090 / 7094 | 36 бит | 6-битные кодировки символов |
SDS 940, ICL 1900, Harris | 24 бита | ICL использовал 6-битные символы |
Семейство Burroughs B5000 | 48 бит | Тегированная стековая архитектура |
CDC 6600 | 60 бит | 6-битные символы, побайтовой адресации нет вообще |
Cray-1 | 64 бита | Пословная адресация; в C |
Data General Nova | 16 бит | Пословная адресация; байтовые указатели имели другое представление, чем указатели на слова |
Intel 8086 | 16 бит | Сегментированная память; |

Миникомпьютер PDP-8 от DEC
С символами тоже не было никакого единообразия. Были 6-битные наборы символов, 7-битный ASCII, 9-битные байты на 36-битных машинах и EBCDIC на мейнфреймах IBM. Отрицательные числа могли храниться в дополнительном коде, обратном коде или в виде прямого кода со знаковым битом. Некоторые машины умели адресовать отдельные байты. Другие адресовали только слова целиком, так что «указатель на символ» должен был представлять собой адрес слова плюс смещение.
❯ Откуда взялись типы в CЯзык, который хотел быть одновременно эффективным и переносимым между всеми этими машинами, не мог делать слишком много предположений.
Философия целых чисел в C становится понятнее, если взглянуть на его предков.
BCPL (Мартин Ричардс, 1967) и B (Кен Томпсон, примерно 1969) были бестиповыми языками. Там существовал только один вид значения: машинное слово. Переменная просто хранила слово. Вы могли трактовать ее как int, адрес или битовую маску в зависимости от примененного оператора. На машинах с пословной адресацией, под которые эти языки писались, это было элегантно и шустро.
Затем Bell Labs получила PDP-11. PDP-11 был с побайтовой адресацией, 16-битными словами и вот-вот должен был получить аппаратный блок плавающей точки. Деннис Ритчи в своей работе «The development of the C language» (1993) описывал, насколько плохо модель языка B «всё есть слово» ложилась на эту машину. Работа с символами была неуклюжей, указатели приходилось масштабировать между адресами слов и байтов, а значения с плавающей точкой в одно слово попросту не влезали.

Деннис Ритчи и Кен Томпсон работают на PDP-11/20 в Bell Labs
Система типов C и была создана, чтобы устранить это несовпадение. char дал доступ к байту. А int сохранил дух машинного слова из BCPL: натуральное целое число данной машины. Эта идея стала частью языка. Даже сегодня в стандарте C (C11 §6.2.5) сказано:
«Обычный объект типа
intимеет естественный размер, предполагаемый архитектурой среды исполнения».
И это осознанное решение. int никогда не задумывался как «строго 32 бита». Он означал: «то, с чем этой конкретной машине работать быстрее и удобнее всего».
Настоящая проверка боем случилась в 1977 и 1978 годах, когда Ритчи и Стив Джонсон портировали UNIX и C на Interdata 8/32 – 32-битную машину, которая сильно отличалась от PDP-11. Они написали об этом в статье «Portability of C programs and the UNIX system» (Bell System Technical Journal, 1978). Примерно в то же время Portable C Compiler (pcc) Джонсона сделал перенос C на новые архитектуры практической реальностью, и C разошелся по огромному количеству разного железа.
В первом издании книги «Язык программирования C» (Керниган и Ритчи, 1978) есть таблица, в которую я люблю тыкать людей. В ней приведены размеры типов на четырех машинах, на которых C уже тогда работал:
Тип | DEC PDP-11 | Honeywell 6000 | IBM 370 | Interdata 8/32 |
|---|---|---|---|---|
| 8 бит | 9 бит | 8 бит | 8 бит |
| 16 | 36 | 16 | 16 |
| 16 | 36 | 32 | 32 |
| 32 | 36 | 32 | 32 |
| 32 | 36 | 32 | 32 |
| 64 | 72 | 64 | 64 |
В 1978 году C уже вполне крутился на машинах с 16-битными, 32-битными и 36-битными интами, а также с 8- и 9-битными char’ами. Гибкие размеры были заложены с самого старта, и это работало. Один и тот же язык и практически те же самые исходники компилировались нативно и эффективно под всё это железо.
❯ Почему гибкие размеры были полезныПредставьте, что C потребовал бы, чтобы int был строго 32-битным, в дополнительном коде и с переполнением по кругу, как это сделано во многих современных языках. Вот какую цену за это пришлось бы заплатить.
Каждая операция с int требовала бы двух машинных инструкций вместо одной. Сложение двух 32-битных значений на PDP-11 означает вызов ADD для младших слов, за которым следует ADC (сложение с переносом) для старших. Сравнения, сдвиги и умножения становятся еще тяжелее. Каждый индекс массива и каждый счетчик цикла жрал бы в два раза больше регистров и в два раза больше инструкций.
int i;
for (i = 0; i < n; i++) {
total += table[i];
}С «нативным» int этот цикл компилируется в операции с одним регистром на PDP-11, IBM 370, Honeywell 6000 или Cray. А с жестко забитым 32-битным int версия для PDP-11 работала бы примерно в два раза медленнее – притом, что PDP-11 как раз и была машиной, под которую C изначально писался!
Фиксированный 32-битный int здесь выглядит пожалуй еще хуже, потому что само железо шире этого типа. Чтобы соблюдать точный 32-битный wraparound при переполнении, компилятору пришлось бы навешивать маску почти после каждой арифметической операции:
/* во что превратилось бы "a = a + b" для соблюдения точной 32-битной семантики */
a = (a + b) & 0xFFFFFFFF;
/* ...плюс ручное расширение знака с 31-го бита, если a знаковый */А это лишние инструкции на каждое сложение, вычитание и умножение, плюс 4 бита впустую в каждом машинном слове. Если же позволить int быть 36-битным – оверхед равен нулю.
Если бы язык требовал дополнительного кода и соответствующего поведения при переполнении, то каждая знаковая операция на машине с обратным кодом требовала бы программной эмуляции. C обошел это, разрешив все три представления знака (дополнительный код, обратный код и знаковый бит) и объявив знаковое переполнение неопределенным поведением (UB).
❯ 4. На машинах без 8-битных байтов (CDC, PDP-10, DSP с пословной адресацией)Сегодня люди часто думают, что это UB сделали в угоду компиляторным оптимизациям. Но изначально это было сделано для того, чтобы не навязывать специфику одной конкретной машины всему остальному железу.
C требует, чтобы char содержал как минимум 8 бит (CHAR_BIT >= 8), а не строго 8. На 36-битной машине четыре 9-битных char’а идеально ложатся в одно слово без остатка. На машине, которая может адресовать только слова целиком, char может просто быть размером в слово.
Именно поэтому C никогда не обещал, что все указатели будут иметь одинаковый вид в памяти. На Data General Nova типы char * и int *, указывающие на одно и то же место, имели разный набор бит. Правила C относительно приведения указателей (и необходимость явных кастов и void *) появились как раз из-за таких машин.

Миникомпьютер Data General Nova
❯ 5. На мелких 8-битных микроконтроллерах (Z80, 6502, 8080)C не разрешает делать int настолько маленьким, чтобы он совпадал с 8-битными регистрами процессора. Стандарт задает минимальный диапазон от -32767 до 32767, поэтому int должен быть как минимум 16-битным. Тут виден баланс дизайна: размер адаптируется под платформу, но есть нижняя планка, чтобы программист мог хоть на что-то рассчитывать.
Когда ANSI стандартизировал C в 1989 году, эту философию закрепили официально. Вы получаете не точные размеры, а гарантированные минимальные диапазоны, доступные через <limits.h>:
Тип | Гарантированный минимум |
|---|---|
| 8 бит ( |
| 16 бит |
| 16 бит |
| 32 бита |
| 64 бита |
Портабельная программа на C задает вопрос: «какой минимальный тип гарантированно вместит мой диапазон значений?», а не «какой тип имеет размер ровно N бит?». Если вам нужны значения до 100000, вы берете long, потому что long гарантированно вместит их на любой платформе. Если ваши данные влезают в ±32767, int отлично подойдет и будет самым быстрым выбором на любом железе.
В документе ANSI C Rationale «дух C» сведен к нескольким принципам, и два из них имеют прямое отношение к теме:
Доверяй программисту
Делай быстро, даже если это не гарантирует стопроцентную переносимость
C пытался быть переносимым и быстрым, позволяя каждой реализации мапить язык на железо наиболее дешевым путем. Это инженерный компромисс, а не факап.
❯ Пример переносимого C: кодовая база LuaЕсли вы хотите увидеть, как эта философия применяется в реальном современном проекте, гляньте исходники Lua. Lua заводится вообще на всем: от 64-битных серверов до микроконтроллеров и старых экзотических тулчейнов. Lua написана на том, что сами авторы называют «Clean C», – общем подмножестве стандарта ANSI C (C89). Долгое время Lua вообще не зависела от <stdint.h>, и там до сих пор используется классический подход:
«Спроси у компилятора через
<limits.h>, что у него есть, и выбирай типы на основе гарантированных диапазонов».
Вот пара примеров из Lua 5.4:
❯ Проверка, достаточно ли велик int, без использования int32_tВ файле luaconf.h:
/*
@@ LUAI_IS32INT истинно тогда и только тогда, когда int имеет (как минимум) 32 бита.
*/
#define LUAI_IS32INT ((UINT_MAX >> 30) >= 3)Это чистый C89. Код не спрашивает: «является ли int строго 32-битным?», потому что на 36-битной машине этот вопрос не имел бы смысла. Он проверяет: «вмещает ли unsigned int диапазон хотя бы в 32 бита?». И эта штука одинаково корректно отрабатывает на 16-, 32-, 36- и 64-битных интах.
❯ Инструкции виртуальной машины: «хотя бы 4 байта», а не «строго 4 байта»В файле llimits.h:
/*
** тип для инструкций виртуальной машины;
** должен быть unsigned-размером (как минимум) 4 байта (подробности в lopcodes.h)
*/
#if LUAI_IS32INT
typedef unsigned int l_uint32;
#else
typedef unsigned long l_uint32;
#endif
typedef l_uint32 Instruction;Тип называется l_uint32, но обратите внимание на коммент: он должен быть как минимум 32-битным. На машине с 16-битным int код фоллбэчится на long, который по стандарту гарантированно не меньше 32 бит. Декодер инструкций в lopcodes.h выдергивает поля через сдвиги и маски, поэтому любые лишние старшие биты на более широких машинах просто игнорируются.
/* char'ы используются как малые натуральные числа (чтобы char оставался под символы) */
typedef unsigned char lu_byte;
typedef signed char ls_byte;Lua использует unsigned char там, где в современной кодовой базе влепили бы uint8_t. И это валидно везде, включая платформы, где байт равен 9 или 16 битам. Типа uint8_t на таких железках просто не существовало бы.
Типы для учета памяти следуют тому же паттерну: используются size_t/ptrdiff_t, когда int равен 32 битам и больше, и unsigned long/long на 16-битных системах, где size_t может оказаться слишком узким для подсчета общего объема памяти.
Целочисленный тип в Lua настраивается через luaconf.h (LUA_INT_INT, LUA_INT_LONG, LUA_INT_LONGLONG), с опцией LUA_32BITS для слабых платформ:
#if defined(LUA_32BITS) /* { */
/*
** 32-битные целые и float
*/
#if LUAI_IS32INT /* юзаем int, если он достаточно жирный */
#define LUA_INT_TYPE LUA_INT_INT
#else /* иначе берем long */
#define LUA_INT_TYPE LUA_INT_LONG
#endif
#define LUA_FLOAT_TYPE LUA_FLOAT_FLOATПо дефолту используется long long, если компилятор его поддерживает (это чекается через LLONG_MAX), с откатом на long для строгих компиляторов C89, где этого типа нет.
Пожалуй, самый наглядный пример – это функции string.pack и string.unpack в lstrlib.c. Они читают и пишут бинарные инты побайтово, при этом не закладываясь на то, что байт обязан быть строго 8-битным:
/* количество бит в символе */
#define NB CHAR_BIT
/* маска для одного символа (NB единиц) */
#define MC ((1 << NB) - 1)Упаковка целых чисел происходит через постоянное взятие n & MC со сдвигом вправо на NB. Порядок байтов (endianness) разруливается в коде явно, а не тупым кастом указателя на авось. Вот так и пишется бинарный ввод-вывод, который работает на любой валидной реализации C.
«Отсутствие фиксированных типов» не означает «отсутствие контроля над размерами». Вы описываете то, что вам нужно (диапазон, минимальную ширину, байт), чекаете это через
<limits.h>, а реализация сама выбирает наиболее производительный тип.
Именно такой дисциплины дизайн C и ожидал от разработчиков.
❯ Будем объективны: в чем были проблемыЯ не собираюсь делать вид, что гибкие размеры дались бесплатно. Грабли тут вполне реальные:
Люди не писали код так, как это сделано в Lua. Куча сишного кода писалась в расчете на то, что int – это 16 бит (во времена DOS) или 32 бита (позже), народ закладывался на равенство sizeof(int) == sizeof(void *) или кастовал указатели в int. Переход на 32-битные, а затем на 64-битные машины предсказуемо всё это ломал. Язык давал возможность писать переносимо, но не заставлял это делать.
Раскол 64-битных моделей данных. Unix-подобные ОС выбрали LP64 (где long и указатели 64-битные), а 64-битная Windows пошла по пути LLP64 (где long остался 32-битным, а 64 бита получили только long long и указатели). Из-за этого код, использующий long как «большое число» или «число размером с указатель», ведет себя на этих системах по-разному.
Стандартные типы фиксированной ширины завезли слишком поздно. Хедер <stdint.h> появился только в C99, так что на протяжении двух десятилетий каждый проект городил свои typedef’ы вроде u32/INT32, обмазываясь лесами из #ifdef. Это как раз тот воркэраунд, который советуют и сегодня, просто стандарт в итоге сделал его официальным.
Кстати, даже <stdint.h> сохранил оригинальную философию C. Типы точной ширины (int8_t, uint32_t и т.д.) на самом деле опциональны: компилятор предоставляет их только в том случае, если на целевой машине реально есть тип ровно такой ширины, без бит-паддинга и строго в дополнительном коде. При этом обязательными являются типы вроде int_least32_t («наименьший тип размером не менее 32 бит») и int_fast32_t («самый быстрый тип размером не менее 32 бит»). То есть это всё та же идея гарантированных минимумов из ANSI, просто с более понятными именами. Комитет по стандартизации снова отказался делать вид, будто везде в мире байт равен 8 битам.
❯ Как с этим у современных языков (и почему они могут себе это позволить)Примечание. Это не просто дела давно минувших дней. У многих DSP-процессоров, которые производятся прямо сейчас,
CHAR_BITравен 16 или 32 (например, у некоторых чипов от TI и Analog Devices), плюс существуют сишные компиляторы под 36-битную линейку Unisys 2200 с обратным кодом. На таких системахuint8_tбанально отсутствует, а код, написанный по канонам Lua, спокойно собирается и шуршит.
Языки, появившиеся в 1990-х и позже, стартовали в совершенно других условиях. Войны архитектур закончились. 8-битный байт, побайтовая адресация и дополнительный код окончательно победили. Создатели языков могли спокойно зашить эти предположения прямо в базис:
Java (1995) фиксирует вообще всё: byte – 8 бит, short – 16, int – 32, long – 64, всё строго в дополнительном коде и с жестко заданным поведением при переполнении. Java могла пойти на это отчасти потому, что она крутится поверх виртуальной машины. JVM прячет под капот все нюансы конкретного железа, а проблемы эмуляции (если они вообще возникают) – это уже забота самой JVM.
C# следует точно такой же модели внутри среды исполнения .NET.
В Rust вообще нет дефолтного голого int. Там пишут i8, u16, i32, u64, i128 и так далее, явно указывая разрядность. Поведение при переполнении четко определено: в debug-сборках это паника, а в релизных – wrapping по умолчанию, плюс есть явные методы (wrapping_add, checked_add, saturating_add), когда нужно строго конкретное поведение.
Zig идет еще дальше и позволяет задавать инты произвольной ширины, такие как u7, i3 или u48, что дико удобно для битовых полей и работы с регистрами железа. Кроме того, там есть типы c_int, c_long и прочие для интеропа с C, поскольку язык понимает, что сишные размеры плавают.
Go жестко фиксирует типы от int8 до int64, но его базовые int и uint – это 32 или 64 бита, в зависимости от платформы.
Swift делает то же самое: Int там равен размеру машинного слова, наряду с явными Int8–Int64.
И вот последние два пункта весьма показательны. Даже современные языки сохранили концепцию натурального, платформозависимого целого числа: isize/usize в Rust, int в Go, Int в Swift, usize в Zig. Эта идея никуда не делась. Она просто сузилась от «родного слова процессора» до «размера указателя», потому что индексация памяти – это то место, где размер слова все еще критичен.
Так что базовая интуиция создателей C оказалась абсолютно верной. Современные языки сохранили этот подход, просто жестко зафиксировав всё остальное.
Да и сам C в итоге последовал за унификацией железа. Стандарт C23 наконец-то потребовал представления знаковых чисел строго в дополнительном коде (в C++20 сделали то же самое). Комитет смог пойти на это в 2020-х, потому что машины с обратным кодом и знаковым битом, ради которых держали старое правило, стали музейной редкостью. И это правильный порядок вещей: стандарт подстроился под реальность тогда, когда эта реальность окончательно устаканилась.
❯ Переносимость нужна не всегдаПри этом стоит держать в голове, что далеко не всем проектам требуется запредельная портабельность. Иногда мы досконально знаем целевое железо и нам не нужно гадать о размерах типов: процессор – например, MIPS R3000, выравнивание памяти строго такое, какого требует RISC-архитектура MIPS, компилятор берем из оригинального Sony SDK, и мы со стопроцентной уверенностью знаем, сколько байт занимают int, short и long.
Огромная часть сишного кода в реальных проектах пишется именно в таких условиях. В подобных сценариях нет ничего криминального в том, чтобы просто завязаться на нативные типы C. Поскольку такой условный проект пишется исключительно под оригинальную консоль PlayStation, каждый разработчик в команде точно в курсе, сколько байт держит каждый из этих целочисленных типов.
❯ ЗаключениеНу, если только вы внезапно не решите использовать тот же самый код при портировании игры на другие платформы. Именно на эти грабли, собственно, и наступила Psygnosis с исходниками Wipeout для PS1, когда портировала игру под DOS и Windows 😂
Любое инженерное решение нужно оценивать через призму проблемы, которую оно решало, и мира, для которого оно создавалось. Перед C в 1970-х стояла задача быть языком системного уровня, способным заменить ассемблер на машинах с 12-, 16-, 18-, 24-, 32-, 36-, 48-, 60- и 64-битными словами, с 6-, 7-, 8- и 9-битными символами, да еще и с тремя разными способами представления отрицательных чисел – и при этом выдавать бинарник, работающий почти так же быстро, как написанный вручную ассемблерный код.
Забей они тогда жесткие размеры интов – и C стал бы медленным или вовсе нежизнеспособным на половине этого зоопарка. Оставив размеры плавающими и подкрепив их гарантированными минимальными диапазонами, авторы добились того, что C завелся практически везде. Во многом именно поэтому удалось портировать UNIX, и именно поэтому C стал фундаментом, на котором построена почти вся современная системная разработка.
Если вы железно уверены, что ваш код будет крутиться только на современных 64-битных машинах с 8-битным байтом и дополнительным кодом – берите язык, созданный для этого мира, либо подключайте <stdint.h> в C. Но если вам, как и мне, доводится ковырять старые или нестандартные архитектуры, гибкие целые числа в C до сих пор отлично делают ту работу, ради которой их когда-то придумали.
Никакой ошибкой это не было. В переносимости как раз и заключалась вся суть.
❯ Что почитать по темеDennis M. Ritchie, «The development of the C language» (HOPL-II, 1993)
S. C. Johnson and D. M. Ritchie, «Portability of C programs and the UNIX system» (Bell System Technical Journal, 1978)
Kernighan and Ritchie, «The C programming language», 1-е изд. (1978), §2.2
«Rationale for American national standard for information systems, programming language C» (ANSI X3.159-1989)
Исходники Lua 5.4: luaconf.h, llimits.h, lopcodes.h, lstrlib.c

Перейти ↩
Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram‑канале ↩
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | Страсти по RAM | 0 | 9.12 | 03-08-2026 |
| 2 | OPERATION MOONLIGHT 1.0: курс языка C, который я сам себе собрал | 0 | 10.83 | 01-09-2026 |
| 3 | Make STL Cringe Again: Как я динамические строки на C создавал | 0 | 7.92 | 21-08-2026 |
| 4 | [Перевод] Доверьтесь компилятору: C++23 против трюков из 90-х | 0 | 10.4 | 27-07-2026 |
| 5 | Операционная Система на C без знаний C | 0 | 7.27 | 17-07-2026 |
| 6 | Из ядра Linux выпилили strncpy: шесть лет, 362 коммита, одна функция | 0 | 8 | 23-06-2026 |
| 7 | [Перевод] Проектируем с нуля калькулятор на FPGA. Часть 10: Всё работает | 0 | 12.37 | 12-08-2026 |
| 8 | Худший язык программирования всех времён /s | -2 | 6 | 01-07-2026 |
| 9 | Худший язык программирования всех времён /s | -2 | 6 | 01-07-2026 |