Обновить

Исторические исходные коды, с которыми должен быть знаком каждый разработчик

Уровень сложностиПростой
Время на прочтение6 мин
Охват и читатели30K
Всего голосов 42: ↑32 и ↓10+30
Комментарии14

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

Достаточно посмотреть свой код, который ты писал год, два, три назад. :)

И что это даст, пролистывание простыней свичей и ифов?

Ну, как же.. void main() работы самого Торвальдса! Напоминает void setup() в моём скетче для ардуины ;)

А где исходный код MSDOS 1.1 и MSDOS 2.0? Тоже интересная часть истории:)

тут надо ещё добавить исходные коды яндекса :)

Мне кажется, или в приведенном коде CERN httpd переполнение буфера при попытке раздать файл размером 100 десятичных гигабайт? Такой исторический код надо закопать и никогда на него не смотреть - это совсем другие языки (даже если это C), совсем другие требования, другая экспертиза. По современным меркам это один сплошной антипаттерн.

Разработчик никому ничего не должен!

А где исходники Doom Engine? Безусловный шедевр

Шедевральная вещь – это исходный код программы-монитора Apple II, написанный Возняком. Я многое в своё время из него почерпнул, разбирая построчно, благо, он был неоднократно опубликован. Например, чтобы пропустить следующую команду размером 2 байта, не тратя ещё 2 байта на минимальную команду перехода, Возняк использовал 1 байт с подходящим кодом команды, который вместе со следующей 2-байтовой командой образовывал безвредную 3-байтовую команду (бывшая команда становилась полем данных новой команды). Так он каждый раз экономил 1 байт за счёт отказа от уровня абстракции ассемблера и работы на уровне голого машинного кода. И весь монитор умещался в ПЗУ размером 2 килобайта (а этот монитор включал набор процедур, как сейчас сказали бы, bios, плюс дизассемблер и собственный командный язык).

1 байт с подходящим кодом команды, который вместе со следующей 2-байтовой командой образовывал безвредную 3-байтовую команду

А можно немного более развернуто? НЯП в эту конструкцию должно быть 2 точки входа, где-то должны быть jmp (ненулевого размера) для перехода?

Мне попадалась интересная конструкция передачи параметров в функцию через PC

call function
.data Hello, World\0
// continue execution here
.label function
pull ax // вынимаем из стека указатель на Hello, world
// обрабатываем строку до \0
// AX теперь указывает на \0, который заодно NOP в 8080
jmp ax 

Экономятся инструкции push перед вызовом функции, pull внутри функции, и jmp вместо ret. Но код вперемешку с данными, никаких early return, никакой кроссплатформенности. Удобно передавать только константные zero-terminated строки. Вряд ли это можно ещё где-то использовать.

Например, так вот (это, правда, из соседнего кода, AppleSoft BASIC):

db57: a9 20        OUTSP           lda     #‘ ’              ;print a space
db59: 2c                           db      #$2C             ;skip over next line
db5a: a9 3f        OUTQUES         lda     #‘?’              ;print question mark
                   ; Print char from A-reg
db5c: 09 80        OUTDO           ora     #$80              ;print A-reg
db5e: c9 a0                        cmp     #$a0              ;control chr?
db60: 90 02                        bcc     LDB64             ;skip if so
db62: 05 f3                        ora     FLASH_BIT         ;=$40 for FLASH, else $00
db64: 20 ed fd     LDB64           jsr     MON_COUT          ;ANDs with $3F (INVERSE), $7F (FLASH)
db67: 29 7f                        and     #$7f
db69: 48                           pha
db6a: a5 f1                        lda     SPEEDZ            ;complement of speed #
db6c: 20 a8 fc                     jsr     MON_WAIT          ;so SPEED=255 becomes A=1
db6f: 68                           pla
db70: 60                           rts

Если мы вызываем подпрограмму OUTQUES по адресу $db5a, то загружаем в аккумулятор код вопросительного знака и уходим дальше в подпрограмму печати произвольного символа из аккумулятора OUTDO, которая находится ниже. А если мы вызываем подпрограмму OUTSP по адресу $db59, то мы загружаем в аккумулятор код пробела, выполняем машинную команду $2c, которая вместе со следующей командой складывается в бесполезную инструкцию тестирования битов bit $3fa9, и опять-таки уходим на код OUTDO. Таким образом, на три точки входа с различными параметрами в печать символа мы потратили всего 5 байтов. Хотя в мнемонике ассемблера мы должны были бы вместо db #$2c поставить двухбайтовый условный переход, например, bne *+2, или даже, рассуждая тупо, трёхбайтовый безусловный – jmp $db5c.

Сам код OUTDO здесь использует подпрограмму монитора MON_COUT для печати символа, но перед этим применяет к коду символа маску, установленному режимами вывода INVERSE и FLASH, а также делает задержку печати, установленную режимом SPEED= (это всё фишки Бейсика).

Интересный пример байтоложества ;) Сэкономлен 1 (один!) байт в одном месте программы. Конечно, когда в ПЗУ всего 2048 байт, это не лишнее, есть даже шедевральный рассказ про последний байт. Но это не масштабитруется; на ПЗУ в 1МБ 1024 байта экономить будет очень дорого.

А как же легендарный алгоритм обратного корня из Quake III Arena?

float Q_rsqrt( float number )
{
	long i;
	float x2, y;
	const float threehalfs = 1.5F;

	x2 = number * 0.5F;
	y  = number;
	i  = * ( long * ) &y;                       // evil floating point bit level hacking
	i  = 0x5f3759df - ( i >> 1 );               // what the fuck? 
	y  = * ( float * ) &i;
	y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//	y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

	return y;
}

В разные времена были разные приоритеты. То на чем экономили 30 лет назад не имеет смысла сейчас.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Информация

Сайт
ispmanager.ru
Дата регистрации
Дата основания
Численность
51–100 человек
Местоположение
Россия