Иван Савватеев @SIISII
Микроконтроллеры, цифровая электроника, ОС…
Information
- Rating
- 1,749-th
- Location
- Солнечногорск, Москва и Московская обл., Россия
- Date of birth
- Registered
- Activity
Specialization
Embedded Software Engineer
Lead
Микроконтроллеры, цифровая электроника, ОС…
А у американцев в том же 1967-м пошла в серию одна из машин CDC -- не помню точно, какая именно модель, но зато помню, что она имела первый в истории суперскалярный процессор и, естественно, была многократно сложней БЭСМ-6. И ничего, работала-с. Так что никакой фантастики в создании сложных систем "в древности" нет. Правда, квалификация тогдашнего среднего разработчика и современного различалась, подозреваю, даже не в разы, а на порядки.
Не знаю, как современная версия GPL, а старые версии налагали крайне жёсткие ограничения -- не менее жёсткие, чем у проприетарного софта. Фактически, они делали невозможным использование того же Линуха во многих коммерческих проектах (хотя всё равно использовали, просто тщательно прятали концы в воду, чтобы, например, не раскрывать те модификации, которые вносили в Линух). А вот лицензия BSD, кажется, реально свободная: используй как хошь, в т.ч. можешь модифицировать, не открывая твой код, и т.д. и т.п.
Угу, то была VAX/VMS.
Ну, про это я писать не стал, поскольку сие касается программирования, а не внутреннего устройства конкретной модели.
Сама по себе статья, конечно, полезна. Но:
очень много ошибок в плане русского языка;
не совсем корректная отсылка к целым числам в плане знака числа: целые-то хранятся в дополнительном коде, а вещественные -- в прямом, о чём стоило б сказать явным образом; кроме того, у вещественных есть знак мантиссы (собственно знак числа), а есть знак порядка (замаскированный из-за использования смещённого порядка);
некоторый бардак с хронологией, из-за чего возникает впечатление, что некоторые игры не работали на некоторых видюхах в 1960-70-е, хотя сие имело место, на самом-то деле, в 2000-х, и не из-за формата представления вещественных чисел как такового (IEEE 754 уж давно стандартом стал), а из-за разного набора обеспечиваемых аппаратных возможностей. DirectX, конечно, в каждой своей версии требует наличия некоего минимума, но производители вольны добавлять необязательные возможности по своему усмотрению;
не нашёл упоминания нормализации чисел. Вообще, думаю, неплохо было бы пошагово расписать выполнение арифметических операций, чтоб читателю было бы понятнее, как числа обрабатываются машиной;
можно было б для полноты картины упомянуть, что вещественные числа не всегда представляются как в степени 2 -- например, в Системе 360 используется степень 16, из-за чего при равном числе битов диапазон много шире, а вот точность хуже;
говоря о IEEE 754, неплохо б сказать, что лишь часть стандарта обязательна к реализации. Так, в зависимости от платформы выбор способа округления может предоставляться, а может и не предоставляться, ненормализованные числа могут поддерживаться, а могут превращаться в нуль, и т.д. Понятно, что статья вводная, но упомянуть о потенциальных проблемах стоило б, чтоб, кому оно интересно или надо, стал бы копать вглубь (и знал бы, в какую именно сторону).
А с чего взяли, что секционные микросхемы Am29xx (превратившиеся у нас в серию 1804) -- по лицензии Интел? Сама Интел их не выпускала; у неё был свой секционный комплект i3xxx (у нас превратился в серию 589), но он ничего общего, кроме секционности, с АМДшным не имел.
Ну так потому Микрософт и взлетела, что её шеф, даже не будучи сам великим программистом, разбирался в этом виде деятельности и мог грамотно нанимать специалистов. В принципе, то же самое относится к любой технической компании. HP тоже была крута, пока ей рулили Хьюлетт и Паккард Ну а в чём разбираются финансисты, кроме как в распиле бабла? (Понятно, что бывают исключения -- но они лишь подтверждают правило)
"Еще раз: вы не сможете нормально размещать экземпляры таких непрозрачных структур на стеке или внутри других объектов."
(не пойму, как здесь делать цитаты...)
1) Это не всегда нужно -- например, правильней может быть хранение именно указателя на объект, а не самого объекта.
2) С эффективностью это не очень-то связано. Если Вы передаёте в функцию сам объект, Вы как раз теряете в эффективности, а если всегда передаётся только указатель, то зачем хранить объект в стеке? Особенно объект потенциально долгоиграющий, который должен сохраняться при выходе из функции, где он создаётся, а соответственно, создаваемый в динамически выделяемой памяти, а не в стеке? (То же открытие классического файла).
"Инкапсуляция к этому отношения не имеет вообще."
Имеет. То, что функции не связаны между собой параметрами, не означает, что между ними нет никакой внутренней связи. Скажем, несколько функций, выводящих разную информацию через один и тот же отладочный интерфейс.
Я ж и говорю: это может быть неудобно/костыльно. Надо из задачи исходить. Скажем, если нужно реализовать несколько связанных между собой достаточно низкоуровневых функций -- типа классического ввода-вывода в стиле C, -- то нет никакой нужды объединять их в класс, достаточно непрозрачной структуры а-ля FILE и хранения указателя на неё для передачи в качестве параметра. Если нужны несколько функций, связанных только назначением, но не параметрами, тогда и структуры такой не требуется -- просто несколько объявлений лежат вместе в одном заголовке, и всё.
Ну, если брать уж совсем общие случаи, то да -- кроссплатформенного решения нет, придётся писать ручками или тащить реализованное кем-то другим для конкретных платформ.
Что же до ссылки на пример неправильного разбора, то, на первый взгляд, проблема в реализации библиотеки, а не в принципиальной невозможности сделать правильный разбор -- т.е. имеет место баг или недоработка, что можно (и нужно) исправить в следующей версии. Но честно скажу, что глянул бегло, не вникая.
Ну и, кроме того, даже если я прав и это баг в библиотеке, всё равно остаётся проблема обеспечения кроссплатформенности здесь и сейчас, а не когда все баги исправят, -- так что, решение может быть теоретически кроссплатформенным, а на практике -- не совсем... В общем, надо исходить из задачи и из реального списка необходимых платформ, а не пытаться сделать решение "сферическое в вакууме".
Примерно так, да -- "голые" функции (и публично доступные структуры, необходимые для взаимодействия с ними -- для параметров, например, или, как в Вашем примере, только их объявления, но не определения, для сокрытия их содержимого), а не методы (функции) классов. Разве что, при необходимости всё это можно "завернуть" в отдельное пространство имён. Можно, конечно, все их поместить внутрь недокласса -- но особого смысла не вижу.
В заголовочном файле разместить только интерфейсную часть, а всю реализацию, включая внутренние структуры данных, -- в .cpp. Правда, этот способ может быть неудобным/костыльным, если нужно создать несколько однотипных объектов (по сути, наборов данных), не давая при этом доступа к их внутренней реализации. В такой ситуации более правильным, скорей всего, будет использование "недокласса": class/struct с разделением на public/private, но без виртуальных функций и без наследования.
С типичными современными файловыми системами (FAT, NTFS, EXT...) можно, используя std::filesystem::path, доступный в C++17, о чём тут уже сказали. Вот если нужна работа с древними или нестандартными файловыми системами -- там да, проблематично придумать что-то кроссплатформенное. Но в реальной жизни сейчас такое если и встречается, то крайне редко.
Ну, 8080 действительно был очень популярен, и Z80, хотя и превзошёл его по популярности, был программно совместим с 8080 -- собственно, это и стало одной из причин его популярности. Нередко Z80 использовался именно как более быстрая и удобная для электронщика (одно напряжение питания и готовые управляющие сигналы шины) замена 8080, при этом программы оставались старые, рассчитанные на 8080, и не использовали дополнительные возможности Z80,
Слово с точки зрения электронщика действительно связано с аппаратной реализацией, но оно может не соотносится со словом с точки зрения программиста. ЕС-1020 -- архитектурно 32-разрядная машина (Система 360), однако имеет 8-битовое АЛУ и 18-битовую ширину доступа к ОЗУ (16 информационных и два контрольных разряда). ЕС-1050 -- это тоже 32-разрядная машина (та же Система 360), но основное АЛУ там 64 бита, если память не изменяет, а слово памяти -- 72 бита (8 информационных байтов плюс по одному контрольному биту на каждый байт). Ну и чему тут будет равен размер слова, если исходить из аппаратуры, а не архитектуры (т.е. представления машины с точки зрения программиста)? Плюс исторический контекст влияет. Вот отсюда и весь хаос с этим термином.
Точней, Минск-2, -22 и -32. Ну и добавлю, что путаница может возникать ещё и из-за разного представления машинного слова для программиста и электронщика. Скажем, для программиста Система 360 (ЕС ЭВМ) -- всегда 32-разрядная, однако в зависимости от модели память могла быть организована по-разному (у ЕС-1020 ширина доступа -- 18 бит, из коих два -- контрольные разряды для двух информационных байтов, у ЕС-1035 -- 72 бита: 8 информационных байтов плюс восемь разрядов для контроля и коррекции по коду Хэмминга, и т.п.), поэтому электронщик, рассуждая о памяти, мог использовать термин "слово" по отношению к физическому слову памяти, а не в том значении, в котором его использует программист.
Ну а в Системе 360 или в ARM, которые изначально были 32-разрядными, слово -- именно 32 бита, а 16 бит -- полуслово. Поэтому и путаница с этим термином, но автору статьи явно было лень посмотреть на историю разных архитектур.
На момент появления байта US ASCII была 7-битной кодировкой, насколько помню; 8-битной ASCII стал уже в 1970-80-х. RADIX-50 позволял плотнее упаковывать символы для экономии памяти, что было важно для мини-ЭВМ с их небольшой разрядностью (64 Кбайта адресуемой памяти, если говорить про наиболее популярные PDP-11; VAX можно не рассматривать, ибо это уже вторая половина 1970-х). В то же время, эта кодировка очень ограничивала набор символов: собственно, только большие английские буквы, цифры и ещё несколько знаков, что совершенно недостаточно во многих задачах (из-за этого, кстати, столь ограничен был набор допустимых символов в именах файлов на PDP-11). Кроме того, упаковка-распаковка требовали выполнения дополнительных операций, т.е. прилично снижали производительность.
Хотя сами изложенные факты верны, выводы зачастую довольно бредовые: автор явно не стремился тщательно обдумать собранную информацию, в т.ч. в историческом контексте (тогда, например, сразу стало бы понятно, почему слово в архитектуре IA-32 aka x86 -- это 16 бит, а не 32 или 64). Постараюсь кратко изложить свою точку зрения на причины появления и закрепления 8-разрядных байтов.
Разрядность разных машин, создаваемых для научных расчётов, т.е. для операций с плавающей запятой, определялась до начала разработки машины, исходя из требуемой точности и диапазона представления чисел. Поэтому до конца 1960-х с разрядностью наблюдается полный хаос. Скажем, у нас "Стрела" была 51-разрядной, машины серии "Минск" -- 37-разрядными, БЭСМ-6 и ряд её предков -- 48-разрядными, а вот "уралы" -- 18-разрядными. То же самое было и на Западе. В общем, везде царили полный разброд и шатание, что, очевидно, было неудобно, когда стали задумываться о переносимости ПО по мере развития техники. В то же время, разрядность как таковая не очень важна, важно лишь обеспечить представление нужного диапазона чисел. Соответственно, если достаточно 24 разрядов, то 32 тоже устроят, если последняя величина представляется удобной, исходя из других соображений.
Необходимость в посимвольной обработке информации, а не только в расчётах. Скажем, хотя БЭСМ-6 и уделывала первые модели ЕС ЭВМ по производительности на математических расчётах, в обработке символьной информации она уступала старшим моделям (хотя и обгоняла самые младшие, но только "грубой силой", за счёт намного более высокого быстродействия -- около 1 млн. оп/с против, скажем, примерно 30 тыс. у ЕС-1020). Причина этого как в неэффективной системе команд, так и в адресации памяти только словами (48 бит для БЭСМ-6), что требовало для выделения отдельного символа использования логических и сдвиговых операций. Соответственно, необходима "символьная" адресация памяти, а сам "символ" должен вмещать достаточно информации для представления необходимых знаков. 6 разрядов для этого мало даже для английского языка, 7 разрядов хватает для английского, но мало для двухъязычных систем (скажем, в западноевропейских языках наберётся ещё десятка два различных дополнительных букв, а ведь среди "капиталистов" были ещё и греки, да и про кириллицу наверняка помнили; вот китайцев-корейцев-японцев с их десятками тысяч иероглифов, надо полагать, в расчёт уже не брали). 8-битный символ, исходя из этих соображений, представляется наиболее подходящим.
Популярность обработки двоично-кодированных десятичных данных (BCD), сохраняющаяся на мэйнфреймах IBM до сих пор (z/Architecture). Причин здесь три. Во-первых, если почти всё время занимает человекочитаемый ввод-вывод, а не расчёты, потеря времени на необходимость перевода из десятичной системы в двоичную и обратно (довольно долгие операции!) может не окупиться по сравнению с прямыми вычислениями в BCD (их поддержка "в железе" не так уж и сложна). Во-вторых, чтоб гарантировать правильность усечения/округления результатов вычислений с точки зрения "десятичного" пользователя -- а это критически важно, скажем, в финансовой сфере, где правила учёта вырабатывались веками и, естественно, для десятичной системы -- надо либо выполнять расчёты полностью по правилам десятичной арифметики, либо учитывать и корректировать возможные искажения при использовании двоичной арифметики. В-третьих, полезно иметь возможность обрабатывать десятичные данные переменной длины, хранимые не в регистрах, ограничивающих разрядность данных, а в памяти. С точки зрения обработки BCD адресуемая единица памяти должна иметь размер, кратный 4 битам, -- и тут 8-разрядный байт, удобный для хранения символов, оказывается очень удобен.
Подозреваю, что эти соображения и привели в итоге IBM к появлению 32-разрядной Системы 360 с памятью, организованной из 8-разрядных байтов. Это, естественно, не изменило в одночасье весь "компьютерный ландшафт", но преимущества подобной организации памяти были вполне очевидны, поэтому постепенно и другие фирмы стали реализовывать аналогичный подход -- благо, патентами всё это огорожено не было. Для вещественных чисел, чтобы обеспечить большой диапазон, была принята "шестнадцатеричная" мантисса (данные хранились не по одному биту, а по четыре, и при нормализации производился сдвиг сразу на 4 разряда, что ухудшало точность). О этом в статье говорится, хотя и неочевидным образом для любых читателей, кроме тех, кто знаком с особенностями Системы 360. Добавлю, что в современной z/Architecture сохранены унаследованные от Системы 360 "шестнадцатеричные" вещественные числа (HFP) и добавлены двоичные вещественные, соответствующие современному стандарту IEEE 754 (BFP), а также десятичные вещественные (DFP) -- в дополнение к тоже унаследованным от Системы 360 десятичным целым переменной длины.
Когда я пишу, скажем, недодрайвер для контроллера USB, я временами добавляю комментарии в стиле "что": но они, естественно, описывают не самоочевидные действия, а назначение этих действий применительно к конкретной железяке. Скажем, я пишу, что вот здесь я обрабатываю прерывание по поступлению пакета SETUP, здесь -- по завершению передачи данных и т.д. Хотя, казалось бы, причина прерывания понятна из флага в регистре состояния, который при этом анализируется, и такой комментарий не нужен, я давно уже убедился, что, возвращаясь к собственному коду спустя, скажем, полгода, я уже не помню назначение тех или иных битов регистров контроллера, и мне куда проще понять, что делается, глянув на краткий комментарий, чем открывать даташит в поисках описания нужных битов или же анализировать дальнейший код, чтоб уже из него догадаться, а что здесь происходит. Кроме того, такие комментарии позволяют структурировать код в рамках одной функции (обработчика прерываний, например), визуально отсекая одну часть от другой.
Ну и, конечно, я пишу комментарии в случае отнюдь не очевидных или "лишних" действий -- например, связанных с обходом аппаратных ошибок.