Историческая причина объявления перед использованием, включает и разделение заголовка / источника. Нужно найти подходящую ссылку

TLDR: см. Последний абзац этого вопроса.

Я студент факультета компьютерных наук, пытаюсь закончить текст магистерской диссертации о создании транспилятора (пример).

Теперь для этой магистерской диссертации, часть моего текста посвящена сравнению задействованных языков. Одним из языков является C ++.

Теперь я пытаюсь объяснить разницу в семантике импорта / включения и историческую причину, почему C ++ сделал это таким образом. Я знаю, как это работает в C / C ++, поэтому мне не нужно техническое объяснение.

Тщательно изучив Google и Stackoverflow, я предложил несколько пояснений к stackoverflow и другие ссылки на эту тему:

Зачем нужны предварительные декларации?

Что такое предварительные объявления в C ++?

Зачем C ++ нужен отдельный заголовочный файл?

http://en.wikipedia.org/wiki/Include_directive

http://www.cplusplus.com/forum/articles/10627/

https://softwareengineering.stackexchange.com/questions/180904/are-header-files-actually-good

http://en.wikipedia.org/wiki/One-pass_compiler

Почему заголовочные файлы и файлы .cpp в C ++?

И, наконец, последняя, ​​но не менее важная книга Бьярна Страуструпа «Дизайн и эволюция C ++ (1994)» (стр. 34 — 35).

Если я правильно понимаю, этот способ импорта / включения пришел из C и произошел по следующим причинам:

  • Компьютеры не были такими быстрыми, поэтому предпочтительным был компилятор One Pass. Единственный способ, которым это было возможно, — это принудительное использование декларации перед использованием идиомы. Это связано с тем, что C и C ++ являются языками программирования, которые имеют контекстно-зависимую грамматику: им нужны правильные символы, которые должны быть определены в таблице символов, чтобы устранить неоднозначность некоторых правил. Это противоречит современным компиляторам: в настоящее время обычно выполняется первый проход для построения таблицы символов, а иногда (в случае, если язык имеет контекстно-свободную грамматику) таблица символов не требуется на этапе синтаксического анализа, потому что нет двусмысленностей, которые нужно разрешить ,

  • Память была очень ограниченной и дорогой в те дни. Поэтому на большинстве компьютеров невозможно было сохранить всю таблицу символов в памяти. Вот почему C позволяет программистам объявлять прототипы функций и глобальные переменные, которые им действительно необходимы. Заголовки были созданы, чтобы позволить разработчикам сохранять эти объявления централизованными, чтобы их можно было легко повторно использовать в модулях, которым требовались эти символы.

  • Заголовочные файлы были полезным способом абстрагировать интерфейс от реализации

  • C ++ пытался установить обратную совместимость с программным обеспечением и программными библиотеками, написанными на C. Более важно: они фактически использовали для переноса в C (CFront), а затем использовали компилятор C для компиляции кода в машинный код. Это также позволило им с самого начала скомпилировать для множества различных платформ, поскольку каждая из этих платформ уже имела компилятор C и компоновщик C.

Вышеприведенное было иллюстрацией того, что я обнаружил, выполнив поиск в первую очередь;) Проблема в том, что я не могу найти подходящую ссылку на исторические причины для этой стратегии включения, кроме как здесь, на Stackoverflow. И я очень сомневаюсь, что мой университет будет счастлив со ссылкой на стек-поток. Самым близким из приведенных мной является справочник «Дизайн и эволюция C ++», но в нем не упоминаются аппаратные ограничения, являющиеся причиной стратегии включения. Я думаю, этого следовало ожидать, потому что дизайн этой функции исходил от C. Проблема в том, что я пока не нашел хорошего источника, который бы описывал это проектное решение на C, желательно с учетом аппаратных ограничений.

Кто-нибудь может указать мне в правильном направлении?

Спасибо!

1

Решение

Вы правы, потому что C ++ делает это именно потому, что
С сделал это так. Причина, по которой С сделал это, также основана
в истории; в самом начале (Б) не было
деклараций. Если вы написали f()то компилятор предположил
тот f была функция где-то. Который вернул слово, так как
все в Б было словом; не было типов. Когда C был
изобрел (чтобы добавить типы, так как все слово не очень
эффективный с байт-адресными машинами), основной принцип
не изменился, за исключением того, что функция должна была возвращать
int (и принимать аргументы того типа, который вы ему дали). Если оно
не вернулся int, то вам пришлось переслать объявить это с
тип возврата. В первые дни C это было не редкостью, чтобы увидеть
приложения, которые не использовали includeи который просто
переименовано, например char* malloc() в каждом исходном файле, который использовал
malloc, Препроцессор был разработан, чтобы избежать необходимости
повторить одно и то же несколько раз, и в самом начале,
его самая важная особенность была, вероятно, #define, (В начале C,
все функции в <ctype.h>и символьный IO
в <stdio.h> были макросы.)

Что касается того, почему декларация должна предшествовать использованию: основной
причина, несомненно, потому что если бы это не так, компилятор
принять неявное объявление (функция, возвращающая int, так далее.).
И в то время, компиляторы, как правило, один проход, по крайней мере, для
разбор; это считалось слишком сложным, чтобы вернуться в
«исправить» предположение, которое уже было сделано.

Конечно, в C ++ язык не так сильно ограничен
этот; C ++ всегда требовал объявления функций для
например, и в определенных контекстах (в функциях-членах класса, для
пример), не требует, чтобы объявление предшествовало использованию.
(Как правило, однако, я бы рассмотрел в функциях членов класса
быть несоответствующим, избегать по причинам читабельности.
Дело в том, что определения функций должен быть в классе в
Java является основной причиной не использовать этот язык в целом
проектов.)

2

Другие решения


По вопросам рекламы [email protected]