Смекни!
smekni.com

"Ох волна моя, волна, ты как С++ мощна"

Почти Пушкин

Касательно мощности C/С++.Да, действительно это очень мощные языки ,но их мощность заключается в их средствах низкого уровня,а они при разработке прикладных программ часто неприменимы.

Мощность - это, конечно, хорошо,но часто опасно.

Пример: #define int long синтаксически верно, но может привести к катастрафическим последствиям (хотя, к примеру, при переносе программ с одной платформу на другую это может понадобиться). Или оператор goto. То, что он не включен в Java, многие считают очень большим благом. Goto - это мощная возможность, но, как показал еще в семидесятых годах Дейкстра, мягко говоря, "не рекомендованная" к использованию. Тем не менее это возможность, и она может быть не лишней. Я считаю, что подобные низкоуровневые конструкции должны присутствовать, но ими не следует злоупотреблять. В тех редких случаях, когда лично я его использовал, это была попытка развития плохоспроектированной программы.

"Чтобы сделать карьеру программиста за границей нужно знать два языка: английский и C++"

Российский аспирант, побывавший в Вене.

"С точки зрения теоретического программирования язык си - это Фортран 80 - ых. (Против такого уничижительного определения не возражал и автор языка Си - Д. Ритчи). Этот язык, сочетающий в себе многие преимущества языка высокого уровня и ассемблера, дал программистам, по образному выражению некоторых, педаль газа, но заблокировал педаль тормоза. На Си компьютер может "мчаться" быстро, но рискованно. То есть Си, насаждая ссылочно - ассемблерное программирование, как бы имеет вектор в сторону, противоположную той, которая определяется теорией и методологией языков программирования.

Поэтому и Си++ - это довольно странное сочетание некоторых черт ООП (здесь и далее - объектно - ориентированное программирование) и процедурного программирования"

К.Т.Н. Соловьев А.Е.

"Cи++ представляет собой интересный эксперимент по адаптации возможностей объектной технологии к традиционному языку программирования. ... поскольку Си++ - язык, требующий весьма интенсивной критики. Он представляет собой не слишком удачную реализацию объектно - ориентированной технологии, и поэтому его недостатки просто необходимо подвергать критическому анализу... Си++ приносит всем колоссальное разочарование - он вобрал в себя все плохие и старые средства, а также привнес в объектную технологию абсолютно ненужную сложность. Зачем нужен язык, насквозь пропитанный низкоуровневыми конструкциями? ".

Ян Джойнер

Далее по тексту "Наиболее верный путь к успеху - использование чистого объектно - ориентированного языка, обладающего интерфейсом с языком Cи или с другими низкоуровневыми языками. Это обеспечит хорошие поддержку и сопровождение, переносимость и качество", что в принципе можно наблюдать на примере любого средства 4GL(того же Delphi) поддерживающего стандартные средства взаимодействия Windows такие как Dll,Dde, Ole. Простейший пример - обращение из Delphi программы к Win API(ведь Windows написан на Си(9X) и C++(NT)).

Изначально созданный для разработки ОС Unix, язык C получил широкое распространение. Это наложило очень сильный отпечаток на язык.

Как возник язык С? Вначале был CPL: он был создан в середине 60 - х годов.

Язык не получил широкого распространения, но в процессе его создания появилась масса идей. Язык был беcтиповый, как и положено ассемблеру (ещё PDP 7).

Новая упрощенная версия языка называлась Basic CPL или BCPL. На нем была реализована MULTICS. Но в результате ее размеров и раздутости ей потребовалась замена.

Часть идей из MULTICS была взята разработчиками Unix. К примеру, иерархическая файловая система. Замечу, что в прямом предшественнике DOS-CP/M её не было, как и в первой версии DOS.

Доработали язык - получился B.

Разработали ОС - получилась Unix

Си разрабатывался как Кроссплатформенный ассемблер PDP 11 (многие опытные программисты знают его по отечественным аналогам), является некоторой смесью ассемблера с Паскалем, этим обедняются многие его особенности.

К примеру:

Отсутствует возможность напрямую работать с данными, не поддерживающимися процессором PDP (множества, строки, etc).

Присутствие явно PDP - ориентированных конструкций:

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

Постинскремент и прединскремент. На x86, к примеру, это ничего не дает. И A=B++ и A:=B; inc(b); приведут к командам ассемблера MOV a,b; inc b (естественно, непосредственно в коде это будут не имена переменных, а, к примеру, регистры).

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

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

Изменяющиеся от платформы к платформе размеры типов данных.

Строки, оканчивающиеся нулем, позаимствованные из ассемблера (директива .asciz ассемблера PDP)

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

Наличие множества "подводных камней"

scanf("%d %d",&n,&ar[n]);

Вы думаете, что будет введено целое n и n - ный элемент масива ar ?

Это очень маловероятно. Скорее всего, все аргументы scanf будут вычислены до того, как операция будет вызвана на выполнение. Подобных побочных эффектов в языке масса.

Другая "особенность"

char

str[50]="qwertyuio";

int a=3;str[++a]=str[++a]=' ';

cout<<str<<"&bsol;n";

str[a++]=str[a++]=' ';

cout<<str<<"&bsol;n";

Результат:

qwe tyuio

qwert uio

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

int i=0,ar[2]={10,11};

i=ar[i++];// А кто сразу скажет чему равно значение i

Хотите еще ? Формат вывода зависящей от типа:

short int x=55;

printf("%d&bsol;n",x);

Если заменить short int на longt int, то придется менять и printf("%d&bsol;n",x) на printf("%D&bsol;n",x)

Пример: предположим, что вместо i<=100 разработчик написал i=100 при синтаксисе C/C++

for (i=0; i=100; i++)

Цикл будет выполняться вечно (вместо 101 раза) т.к.

Отсутствует логический тип данных.

Выраженние i=100 равно 100(т.е. по не ноль - истина).

Поскольку C включает в себя элементы не только процедурного, но и функционального программирования такая конструкция вполне правильна и логична.

По мере развития в C включалось все больше возможностей Изначально язык не имел средств даже для описания констант. Когда Си стал применяться для решения серьезных задач, к нему добавили так называемые "директивы препроцессора", такие, как #define и #include.

С помощью define стали определять константы и inline подпрограммы,

А с помощью #include был реализован, хоть и примитивный, механизм модульности. Популярность функционального программирования тоже сыграла свою роль. В языке появились конструкции из функциональных языков.

Конечно, у этой особенности есть и более достойное применение

if (сh=getchar()!=ESC)

{..}

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

Из минусов также следует отметить не слишком читабельный синтаксис. Подумайте, что больше говорит end loop в АДЕ или "}" в C. Конечно, краткость - это хорошо, но платить за нее такую цену....

Примеры:

Паскаль:

if Screen.Forms[I] is FormClass then begin

C++:

if (dynamic_cast<FormClass*>(Screen - >Forms[I])){

A=(!CL&&!RC)?0 : (!LC?RC:LC)//"Очень понятное выражение"

*++* agrv //"Еще одно очень понятное выражение, при том синтаксически верное"

"Интуитивно понятный" синтаксис прекрасно подчеркивает следующий пример:

int i=5;

int *

constp3=&i;//Указатель константу

const int *

p3=&i;//Указатель на константу

i=5;//Правильно

*p3=5; Неверно! указатель на константу измененную в предыдущей строке.

char (*(*x2 ())[]) () //Срочно позовите криптоаналитика !!!

Или работа с перечислениями:

enum modes { LASTMODE , BW40 , C40, BW80, C80, MONO

} ;

..

modes

e1=C80,e2;

e1=e2*3;

//Очень осмысленный оператор на "ЯПВУ".

//Ведь для "ЯПВУ" нет разницы, что int, что enum, что

bool

А что может значить, по Вашему мнению, команда a=24[ar]; ?

При условии, что int ar[50]; int a; она полностью эквивалентна a:=ar[24];

Как совершенно справедливо замечают поклонники C/C++ эти языки позволяют писать чрезвычайно краткие и выразительные программы. На счет краткости - безусловно.

А вот к какой выразительности может привести краткость, я сейчас покажу:

#include <stdio.h>

#define Q r=R[*p++ - '0'];while(

#define B ;break;case

char*s="Qjou!s&bsol;311^ - g&bsol;311^ - n&bsol;311^ - c&bsol;::^ - q - ma%mO1JBHm%BQ - aP1J[O1HB%[Q<nbj&bsol;

o)*|gps)<<*txjudi)m*|aQdbtf!::::;sfuvso<aQefgbvmu;aQ<m,,a%CQ<csfbla%bQ<aN2!Q&bsol;

&bsol;ndbtf!aP2Q;m>aP2Q<a%!D12J!JGJHJOJQJFJSJJJMHS%HD12D12N3!N4&bsol;nJUJT%UQm>aP4HC%T&bsol;

Qs&bsol;q,,^>m,2<m>aP4HC%SD12N1&bsol;nJNQm>s&bsol;..q^aHC%NHb%GN1!D32P3%RN1UP1D12JPQUaP1H&bsol;

R%PN4&bsol;nQ<g&bsol;(aP3Q(^>aP2Q,2<n&bsol;(aP3Q(^>aP4Hb%OD12D12N2!N3&bsol;nJVP3Q,,<jg)aP3Q=>n&bsol;