C был сделан, чтобы сделать написание компилятора легко. Это делает много вещей, основанных на этом одном принципе. Указатели существуют только для облегчения написания компилятора, как и заголовочные файлы. Многие вещи, перенесенные в C ++, основаны на совместимости с этими функциями, реализованными для облегчения написания компилятора.
На самом деле это хорошая идея. Когда C был создан, C и Unix были своего рода парой. C портировал Unix, Unix запускал C. Таким образом, C и Unix могли быстро распространяться с платформы на платформу, тогда как ОС, основанная на сборке, должна была быть полностью переписана для переноса.
Концепция указания интерфейса в одном файле и реализации в другом - вовсе не плохая идея, но это не то, что представляют собой заголовочные файлы Си. Они просто способ ограничить число проходов, которые компилятор должен выполнить через ваш исходный код, и позволяют ограниченную абстракцию контракта между файлами, чтобы они могли обмениваться данными.
Эти элементы, указатели, файлы заголовков и т. Д. На самом деле не дают никаких преимуществ перед другой системой. Прилагая больше усилий к компилятору, вы можете скомпилировать ссылочный объект так же легко, как указатель на точно такой же объектный код. Это то, что сейчас делает C ++.
C отличный, простой язык. У него был очень ограниченный набор функций, и вы могли написать компилятор без особых усилий. Портирование это вообще тривиально! Я не пытаюсь сказать, что это плохой язык или что-то в этом роде, просто основные цели C при его создании могут оставить остатки на языке, которые сейчас более или менее ненужны, но будут сохраняться для совместимости.
Кажется, что некоторые люди на самом деле не верят, что C был написан для порта Unix, поэтому здесь: ( из )
Первая версия UNIX была написана
на языке ассемблера, но Томпсона
Предполагалось, что это будет написано
на языке высокого уровня.
Томпсон впервые попытался использовать в 1971 году
Фортран на PDP-7, но сдался
после первого дня. Затем он написал
очень простой язык, который он назвал B,
который он получил на PDP-7. Это
работал, но были проблемы.
Во-первых, потому что реализация была
интерпретировать, это всегда будет
медленный. Во-вторых, основные понятия B,
который был основан на слово-ориентированных
BCPL, просто не были подходящими для
байт-ориентированная машина как новая
PDP-11.
Ричи использовал PDP-11 для добавления типов
к B, который некоторое время назывался NB
для «нового Б», а затем он начал
написать компилятор для него. "Таким образом
Первая фаза C была действительно эти два
фазы в короткой последовательности, во-первых,
некоторые языковые изменения от B, действительно,
добавление структуры типа без слишком
много изменений в синтаксисе; и делать
компилятор, "сказал Ричи.
«Второй этап был медленнее», - сказал он.
переписать UNIX на C. Thompson
началось летом 1972 года, но было
две проблемы: выяснить, как бежать
основные подпрограммы, то есть, как
переключить управление с одного процесса на
другой; и сложность в получении
правильная структура данных, так как
оригинальной версии C не было
структур.
"Сочетание причин, вызванных
Кен сдастся за лето "
Ричи сказал. «За год я добавил
структуры и, вероятно, сделали
код компилятора несколько лучше -
лучший код - и так далее
лето, когда мы сделали
согласованные усилия и на самом деле сделали повтор
вся операционная система в Си. "
Вот прекрасный пример того, что я имею в виду. Из комментариев:
Указатели существуют только для облегчения написания компилятора? Нет. Указатели существуют, потому что они - самая простая абстракция над идеей косвенности. - Адам Розенфилд (час назад)
Вы правы. Чтобы реализовать косвенное обращение, указатели являются простейшей из возможных абстракций. Ни в коем случае они не являются простейшим для понимания или использования. Массивы намного проще.
Проблема? Чтобы реализовать массивы так же эффективно, как указатели, вам нужно добавить ОГРОМНУЮ кучу кода в ваш компилятор.
Нет причины, по которой они не могли бы создать C без указателей, но с таким кодом:
int i=0;
while(src[++i])
dest[i]=src[i];
потребуется много усилий (со стороны компиляторов), чтобы выделить явные дополнения i + src и i + dest и заставить его создать тот же код, что и это:
while(*(dest++) = *(src++))
;
Факторинг этой переменной "i" после факта - ЖЕСТКИЙ. Новые компиляторы могут это делать, но тогда это было просто невозможно, и ОС, работающей на этом дрянном оборудовании, требовалась небольшая оптимизация, подобная этой.
Теперь лишь немногие системы нуждаются в такой оптимизации (я работаю на одной из самых медленных платформ - кабельных телевизионных приставках, и большинство наших вещей - на Java), и в редком случае, когда вам это может понадобиться, новые компиляторы Си должны быть достаточно умны, чтобы самостоятельно выполнять такие преобразования.