Б. Страуструп - Дизайн и Эволюция C++. 2006 (1160775), страница 13
Текст из файла (страница 13)
Позтому программисты либо вообще игнорировали предупреждения компилятора, либо все же смотрели на них, но добрых чувств явно не испытывали. Итак, предупреждения используются для того, чтобы как-то компенсировать сложности, которые не удается устранить путем изменения языка из-за требования совместимости с С, а также для облегчения перехода с С на С++. Вот пример; Почему С? ПИИИИИИП «С, конечно, не самый чистый язык из всех существующих и не самый простой для применения, так почему же так много людей им пользуютсят' Вот причины: сг гибкость. С применим к большинству предметных областей и позволяет использовать почти любую технику программирования. В языке нет внутренних ограничений, не дающих написать программу определенного вида; д эффективность.
Семантика языка «низкоуровневою, то есть фундаментальные понятия С непосредственно отображаются на фундаментальные понятия традиционного компьютера. Следовательно, можно без особого труда эффективно воспользоваться аппаратными ресурсами из С-программы; а доступность.
Возьмите любой компьютер, от крохотной микромашины до огромной супер-ЭВМ. Почти наверняка для него найдется компилятор С достойного качества, и он будет поддерживать стандарт языка и библиотек. Библиотеки и инструментальные средства также имеются, поэтому программисту редко приходится проектировать новую систему с нуля; сз переносимость.
Конечно, написанная на С программа не переносится но другую машину или операционную систему автоматически. Может быть, осуществить данную процедуру даже не очень просто. Но обычно это получается, и перенос даже очень больших программных систем, принципиально машинно-зависимых, технически и экономически реален. По сравнению с этими важными преимуществами недостатки С вЂ” например, причудливый стиль объявлений или небезопасносгь некоторых языковых конструкций — второстепенны и уже не столь существенны.
При проектировании «лучшего С» необходимо компенсировать проблемы, встречающиеся при написании, отладке и сопровождении кода, не жертвуя при этом достоинствами С. С++ сохраняет все преимущество С и совместим с ним, пусть даже и не идеален и имеет несколько усложненные язык и компилятор.
Однако проектирование языка с нуля не обязательно гарантирует его совершенство, о компиляторы С++ не уступают компиляторам С по скорости и качеству кода и превосходят их в области обнаружения и диагностики ошибок». Во время работы над С цг11Ь С!аваев я еще не сумел бы дать такую отшлифованную формулировку, но она правильно отражает суть того, что я и тогда считал важным в С и не хотел терять в С ту!сЬ С!аваев. Рааса! считался игрушечным языком [Кегш8Ьап, 1981], поэтому более простым казалось добавить контроль типов к С, чем включать в Рааса! возможности, необходимые для системного программирования.
В то время я очень боялся совершить ошибки, в результате которых дизайнер — из-за неправильно понятого патернализма или просто по незнанию— создает язык, непригодный для реальной работы в важных областях. Прошедшие десять лет показали, что, взяв за основу С, я сумел остаться в основном русле системного программирования, как и намеревался. Плата — сложность языка — оказалась велика, но нс непомерна. В качестве альтернативы С и источника идей для Се+ я рассматривал [Вггоцзгпзр, 1984с] такие языки, как Мог]ц1а-2, Аг!а, ЯшаПга!Ь, Меза [М(ссЬе!1, 1979] и С1а.
Но лишь только С, 51шц!а, А!8о!68 и в одном случае ВСР1. оставили заметный след в С++ образца 1985 г. Из 51шц!а я позаимствовал классы, из А18о168 — перегрузку операторов (см. раздел 3.6), ссылки (см. раздел 3.7) и возможность объявлять переменные в любом месте блока (см, раздел 3.11.5), а у ВСРП вЂ” обозначение // для комментариев (см. раздел 3.11.1). Были и другие причины избегать резких расхождений со стилем С.
Достаточно серьезным вызовом мне представлялось уже само объединение сильных сторон С как Язык С вт/!Ф С1аввез ИИИИИИП1 языка системного программирования с возможностями 5]шц!а по организации программ. Добавление нетривиальных возможностей из других источников легко могло бы привести к появлению конгломерата типа «чего изволите» вместо целостного языка.
Приведу цитату из работы 15ггоцзггцр, 1986]: кПеред языком программирования стоят две взаимосвязанные задачи: дать программисту средство дпя описания действий, которые нужно выполнить, и предоставить набор понятий, пользуясь которыми он мог бы размышлять о том, что надо сделать. В идеале дпя решения первой задачи нужен язык, кбпизкий к машине», на котором все важнейшие аппаратные особенности выражаются просто и эффективно и в то же время достаточно понятно для программиста. Язык С в основном дпя »того и проектировапся.
Для решения второй задачи идеально подошел бы язык, «бпизкий к решаемой пробпемею, в котором непосредственно и без искажений выражались бы понятия предметной области. Возможности, добавленные к С в С++, проектировались исходя именно из этой целию. Как и в предыдущем случае, я бы не сумел дать такую формулировку во время ранних этапов работы над С ьу!й С!аззез, но общая идея понятна.
Отход от известных н проверенных временем методов программирования на С и 5]пш!а следовало отложить до приобретения достаточного опыта работы с С ьу!й С!аззез и С++. Еще предстояло провести немало экспериментов. Я верю и верил, что проектирование языка — не просто следование заранее определенным принципам, а искусство, требующее опыта, экспериментирования н компромиссов. Включение в язык важной особенности должно быть обдуманным действием, основанным на опыте. Новой возможности необходимо сочетаться с уже имеющимися и не противоречить представлениям о том, как может использоваться язык. На развитие С++ после 1985 г. влияли Ас]а (шаблоны, см.
главу 15; исключения, см. главу 16; пространства имен, см. главу 17), С!ц (исключения, см. главу 16) и М!. (исключения, см. главу 16). 2.8. Проблемы синтаксиса Мог ли я устранить наиболее досадные недостатки синтаксиса и семантики языка С до того, как С++ стал общедоступным языком программирования? Мог ли я добиться этого, не отбросив в сторону некоторые полезные свойства, затрагивающие пользователей С ту!й С!аззез, «утонувших» в своей среде, которую часто противопоставляют идеальному миру, или сделать этот язык несовместимым с другими, что неприемлемо для программистов на С, желающих перейти на С цг!й С!аззе57 Думаю, нет. В некоторых случаях я пытался устранить недостатки, но вынужден был отказаться от внесенных изменений, получив от возмущенных пользователей множество нареканий.
2.8Л. Синтаксис объявлений в языке С Больше всего в С мне не нравился синтаксис объявлений. Наличие одновременно префиксных и постфиксных операторов объявлений — источник многих недоразумений. Например: 1пс *р[10]; /* массив из 10 указателей ма !пс или */ /* указатель на массив из 10 ьпс? */ Проблемы синтаксиса 461ИИИЮ Разрешение опускать спецификатор типа (по умолчанию считается, что это фпс) также приводит к сложностям. Например: /* стиль С (предлагалось запретить): */ /* неявно; тип 'а' равен 1пг */ /* неявно; возвращает Тпс */ // предлагалось в С ньсЬ С1аззез: зсагъс Тпс а," Тпс г(); Негативная реакция пользователей на изменения в этой области была очень сильна.
Они настолько ценили «краткость» С, что отказывались пользоваться языком, который требовал явно писать спецификаторы типов. Я отказался от изменения. Не думаю, что здесь вообще был выбор. Разрешение неявного фпс — источник многих проблем в грамматике С++.
Замечу, что давление шло со стороны пользователей, а не административных органов или кабинетных экспертов по языкам. Наконец, спустя десять лет, комитет АХЗ1/1БО по стандартизации Се+ (см. главу 6) решился запретить неявныи спс. А значит, еще через десяток лет мы, возможно, от него и избавимся.
Но с помощью инструментальных средств или предупреждений компилятора отдельные пользователи уже сейчас могут начать защищаться от вызванных неявным 1пг недоразумений, например, таких: уота Г(сопзг Т)," // константный аргумент типа Т или // аргумент с именем т типа сопвг Тпс? // (на самом деле первое) Однако синтаксис определения функции с указанием типов аргументов внутри скобок использовался в С зу((]) С!аваев и Се+ и позднее был одобрен комитетом АХЗ1 С: г(а,ы сьаг ь; /* определение функции в стиле каа */ ( /» */ ) Тпс Г(ьпс а, сЬаг Ь) // определение функции в стиле С»+ ( // ) Я рассматривал и возможность введения линейной нотации для объявлений.
В С применяется прием, когда объявление имени имитирует его использование, а в результате получаются объявления, которые трудно читать и записывать, и шансы, что человек илн программа спутают объявление и выражение, растут. Неоднократно отмечэлосгк проблема с синтаксисом объявлений в С заключается в том, что оператор объявления * («указатель на») — префиксный, а операторы объявления (] («массив») и () («возвращающая функция») — постфиксные. Это заставляет использовать скобки для устранения двусмысленности: /* стиль С */ 1пг» у(10]; /* массив указателей на 1пс */ Тпг (*р)(10]; /* указатель на массив Тпс */ Язык С чч[Ф С)аввев ПИИИИИИВ // радикальное изменение: н: [10)->1пс ; // массив указателей на [пс р: ->[10]1пс) // указатель на массив ьпс // менее радикальное изменение: ьпс н(10]->) // массив указателей на ьпл 1пл р->[10]; // указатель на массив гпл Менее радикальный вариант имел то преимущество, что постфиксный оператор объявления -> мог сосуществовать с префиксным оператором * в течение переходного периода.
А по его завершении оператор объявления * и лишние скобки можно было бы просто убрать из языка. Польза от этой схемы заметна: скобки потребовались бы только для записи объявления функции, поэтому возможность путаницы и грамматические тонкости просто исчезли бы (см. также [пег])[, 1981)). Если бы все операторы объявления были постфиксными, то объявления могли бы читаться слева направо. Например, ьпл т (онат) -> [10) -> (йоиЫе) ->; означало бы функцию г, возвращающую указатель на массив указателей на функции, возвращающие указатель на Епе. Попробуйте написать это на стандартном С/С++! К сожалению, я не довел данную идею до конца и так и не сделал полную реализацию. Пользователи вынуждены строить определения сложных типов с помощью гуре(]ег: суре«]еГ 1пл* Рло1(с(оцЫе); // // // // // функция, принимающая с)оцЫе и возвращающая указатель на 1пл массив иэ 10 указателей на Рсо1 т принимает спал и возвращает указатель на Ч10 сурепеГ Рсо1* Ч10(10) Ч10 * Г(спал); В конце концов, я решил оставить все как есть, обосновав это тем, что любое изменение синтаксиса лишь увеличит (по крайней мере, временно) путаницу.
И хотя старый синтаксис — сущий подарок для любителей придираться по пустякам и желающих высмеивать С, для программистов на С он большой проблемы не составляет. Все же я не уверен, что поступил правильно. Ведь от нелогичного синтаксиса С страдаю и я, и другие разработчики компиляторов С-~+, составители документации, разработчики инструментальных средств. Пользователи, конечно, могут изолировать себя от таких проблем, довольствуясь только малым, простым для понимания подмножеством синтаксиса объявлений С/С++ (см.
раздел 7.2), собственно, так они и поступают. 2.8.2. Тэти структур и имена типов Для удобства пользователей в С++ было введено одно синтаксическое упрощение, потребовавшее, правда, дополнительной работы для разработчиков компиляторов и вызвавшее некоторые проблемы совместимости с С. В С имени Вместе с Дугом Макилроем, Эндрю Кенигом, Джонатаном Шопиро и другими я решил ввести постфиксный оператор «указатель на> -> как альтернативу префиксному *; ЯВИ ИВШИИ Проблемы синтаксиса структуры, так называемому тэгу, всегда должно предшествовать ключевое слово зсгисс. Например: вггнсс ьпггег а; /* в с 'аггнсг' необходимо */ В С ччг)) С!аязея меня это ие устраивало, поскольку получалось, что синтаксически определенные пользователем типы можно было отнести ко «второму сорту».