Почему предописания необходимы? [дубликат]

19
задан Community 23 May 2017 в 12:30
поделиться

6 ответов

Краткий ответ заключается в том, что вычислительная мощность и ресурсы увеличивались экспоненциально между временем, когда был определен C, и временем, когда появилась Java 25 лет спустя.

Более длинный ответ ...

Максимальный размер блока компиляции - блока кода, который компилятор обрабатывает в одном фрагменте - будет ограничен размером память, которая есть у компилирующего компьютера. Чтобы обработать символы, которые вы вводите в машинный код, компилятор должен хранить все символы в таблице поиска и ссылаться на них, когда он встречается с ними в вашем коде.

Когда в 1972 году был создан язык C, вычислительные ресурсы были гораздо скуднее и дороже - память, необходимая для одновременного хранения всей символьной таблицы сложной программы, просто не была доступна в большинстве систем. Фиксированное хранилище также было дорогостоящим и чрезвычайно медленным, поэтому такие идеи, как виртуальная память или хранение частей символьной таблицы на диске, просто не позволили бы выполнить компиляцию в разумные сроки.

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

Это также избавило компилятор от необходимости выполнять два прохода для каждого исходного файла: первый для индексации всех символов внутри, а второй для анализа ссылок и их поиска. Когда вы имеете дело с магнитной лентой, где время поиска измерялось в секундах, а скорость чтения измерялась в байтах в секунду (а не в килобайтах или мегабайтах), это было очень важно.

C ++, созданный почти 17 лет спустя, был определен как надмножество C и, следовательно, должен был использовать тот же механизм.

К тому времени, когда в 1995 году появилась Java, в обычных компьютерах было достаточно памяти, поэтому хранение символьной таблицы даже для сложного проекта уже не было серьезным бременем. А Java не была разработана для обратной совместимости с C, поэтому не было необходимости принимать устаревший механизм. C # также не был перегружен.

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

42
ответ дан 30 November 2019 в 02:39
поделиться

Прямые объявления в C ++ - это способ предоставить метаданные о других частях кода, которые могут использоваться компилятором в текущем скомпилированном исходном коде, поэтому он может сгенерировать правильный код.

Эти метаданные могут поступать от автора связанной библиотеки / компонента. Однако он также может быть сгенерирован автоматически (например, есть инструменты, которые генерируют файлы заголовков C ++ для COM-объектов). В любом случае, способ выражения этих метаданных в C ++ - это файлы заголовков, которые необходимо включить в исходный код.

C # /. Net также использует аналогичные метаданные во время компиляции. Однако эти метаданные автоматически создаются при создании сборки, к которой они применяются, и обычно встраиваются в нее. Таким образом, когда вы ссылаетесь в своем проекте C # на сборку, вы, по сути, говорите компилятору «ищите метаданные, которые вам нужны и в этой сборке, пожалуйста».

Другими словами, создание и использование метаданных в C # более прозрачно для разработчиков, что позволяет им сосредоточиться на том, что действительно важно, - на написании собственного кода.

Есть и другие преимущества наличия метаданных о коде, связанных со сборкой. Отражение, выдача кода, сериализация на лету - все они зависят от метаданных, чтобы иметь возможность генерировать правильный код во время выполнения.

Аналогом этого C ++ будет RTTI, хотя он не получил широкого распространения из-за несовместимости реализаций.

0
ответ дан 30 November 2019 в 02:39
поделиться

От Эрика Липперта, блоггера по всем внутренним вопросам C #: http://blogs.msdn.com/ericlippert/archive/2010/02/04/how-many-passes.aspx :

В языке C # не требуется, чтобы объявления выполнялись перед использованием, , что опять же оказывает два воздействия на пользователя и на средство записи компилятора. [...]

На писателя компилятора влияет то, что у нас должен быть двухпроходный компилятор. На первом проходе мы ищем объявления и игнорируем тела. После того, как мы собрали всю информацию из объявлений, которую мы получили бы от заголовки в C ++, мы выполняем второй проход по коду и генерируем IL для тел .

Подводя итог, можно сказать, что использование чего-либо не требует объявления этого в C #, тогда как это требуется в C ++. Это означает, что в C ++ вам нужно явно объявлять вещи, и это удобнее и безопаснее делать с файлами заголовков, чтобы вы не нарушали Одно правило определения .

0
ответ дан 30 November 2019 в 02:39
поделиться

Нет, это не избавит от заголовочных файлов. Это устранит требование использовать заголовок для объявления классов/функций в одном и том же файле. Основная причина для заголовков - не объявлять вещи в одном файле. Основная причина заголовков - объявление вещей, которые определены в других файлах.

К лучшему или худшему, правила семантики языка C (и C++) предписывают поведение в стиле "одного прохода". Для примера, рассмотрим такой код:

int i;

int f() { 
     i = 1;
     int i = 2;
}

Функция i=1 присваивает global, а не , определенный внутри f(). Это происходит потому, что в момент присваивания локальное определение i еще не было замечено, поэтому оно не принимается во внимание. Вы можете следовать этим правилам с помощью двухпроходного компилятора, но это может оказаться нетривиальным. Я не проверял их спецификации, чтобы знать с уверенностью, но мое непосредственное предположение заключается в том, что Java и C# отличаются от C и C++ в этом отношении.

Edit: Поскольку в одном из комментариев было сказано, что мое предположение неверно, я немного проверил его. Согласно Java Language Reference, §14.4.2, Java, похоже, следует довольно близким к тем же правилам, что и C++ (немного отличается, но не сильно.

По крайней мере, как я читаю спецификацию языка C#, (предупреждение: файл Word), однако, она отличается. Там (§3.7.1) сказано: "Областью действия локальной переменной, объявленной в объявлении локальной переменной (§8.5.1), является блок, в котором происходит объявление."

Это, похоже, говорит о том, что в C# локальная переменная должна быть видна на протяжении всего блока, в котором она объявлена, поэтому в коде, подобном приведенному мной примеру, присвоение будет локальной переменной, а не глобальной.

Итак, моя догадка была наполовину верна: Java следует (практически0 тому же правилу, что и C++ в этом отношении, а C# - нет.

3
ответ дан 30 November 2019 в 02:39
поделиться

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

C и C ++ старше и были стандартизированы в то время, когда было необходимо сохранять каждый цикл ЦП.

5
ответ дан 30 November 2019 в 02:39
поделиться

Это из-за меньшего размера модулей компиляции в C / C ++. В C / C ++ каждый файл .c / .cpp компилируется отдельно, создавая модуль .obj. Таким образом, компилятору нужна информация о типах и переменных, объявленных в других модулях компиляции. Эта информация предоставляется в форме предварительных объявлений, обычно в файлах заголовков.

C #, с другой стороны, компилирует сразу несколько файлов .cs в один большой модуль компиляции.

Фактически, при обращении к различным скомпилированным модулям из программы C # компилятор должен знать объявления (имена типов и т. Д.) Так же, как и компилятор C ++. Эта информация получается напрямую из скомпилированного модуля. В C ++ эта же информация явно разделена (поэтому вы не можете узнать имена переменных из C ++ - скомпилированной DLL, но можете определить их из сборки .NET).

0
ответ дан 30 November 2019 в 02:39
поделиться