Личные инструменты

Pure C

Материал из Lurkmore

(Перенаправлено с Си)
Перейти к: навигация, поиск

По техническим причинам запрос «С#» перенаправляется сюда.

Halt! Страница огорожена от Легиона.
Хочешь высказаться? Добро пожаловать в обсуждение.

C (Си) — язык программирования, разработанный придуманный по приколу в расовой пиндосской компании Bell Labs в начале 1970-х годов Деннисом Ритчи. Является на сегодняшний день фактически самым низкоуровневым из языков высокого уровня, и, как следствие, предоставляет достаточно гибкие возможности по использованию ресурсов компьютера благодаря повсеместному использованию указателей и операторов приведения типа. Но на том всё и заканчивается: ООП, динамика, метапрограммирование — всё это реализовали в родственниках и потомках. Cреди программистов носит неофициальный титул «кроссплатформенного ассемблера». Ответственность за корректную работу программы целиком и полностью лежит на программисте, за что Си ненавидим быдлокодерами и, что важно, их начальством. Хорошо мотивированного project manager'а, писавшего когда-то в патлатой молодости на Java, легко можно ввести в ступор, предъявив часть проекта на Си.

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

Содержание

[просмотр] Мёртвый язык

Многие почему-то считают, что Cи мёртв. Когда-то на нём писался практически весь софт, и понятие «быть программистом» однозначно включало в себя «знать Си». Сейчас, конечно же, это не так, и Си успешно вытеснили практически отовсюду. Но красноглазики не унывают, и до сих пор многие кошерные софтинки (зачастую с весьма навороченным пользовательским интерфейсом) пишутся на голом Си (Wireshark, например). Но из-за того, что практически единственным вменяемым для такого рода джедайства фреймворком является GTK, на подвиг отправляются исключительно закоренелые гномосеки. Си никогда не умрёт, пока есть микроконтроллеры и нужно писать драйвера.

Есть, конечно, некоторые проблемы. Бородатые олдфаги, единственные, кто умеет писать ядра операционок, драйвера и системные службы, демонстративно отказываются учить что-то ещё. На самом деле, любой уважающий себя сишник знает не только С++, но и ещё с десяток других языков, главным образом для того, чтобы их обсирать. А на Си они любят писать потому, что код в таком случае получается короче и прямее. Поэтому ядра и драйвера в их пространстве пишутся только на Си, и ни одного на Perl’е и, тем более, PHP. Это злостный цинизм и несправедливая конкуренция. А системные службы написаны на Си чуть менее, чем все. Кое-кто ехидно предполагает, что наличие хоть какого-нибудь вменяемого exceptioning’а в Си могло бы исключить появление BSOD в 90-х. Но всем похуй.

[просмотр] Си и объекты

В середине 80-х некто Страус Трупп (наст. имя Bjarne Stroustrup) решил продвинуть дальше идею кросскомпилируемого ассемблера. Бородачи, не сподвигнувшиеся выучить ООП [1] (а некоторые из них про него и не слышали, искренне считая все технологии после 1981 г. унылым говном), разжигают холивар, который, как правило, сводится к необходимости описывать каждый чих в ООП с одной стороны и необходимость изобретать уйму велосипедов для хоть какой-нибудь объектности с другой. Однако, как показывает практика, там, где задача предрасполагает к объектности сама по себе, не использовать готовый инструментарий в подавляющем большинстве случаев глупо.

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

Любопытно, кроме C++ у Си есть ещё один обратно-совместимый родственник: Objective-C, в котором попытка реализовать объектно-ориентированное программирование до конца увенчалась успехом. Яблочники даже на нём пишут свои поделия (в том числе и интерфейс к iPhone. Но почему-то отклика в массах это не нашло.

Си отличается крайней шустростью (быстрее только ассемблер и за столетия допиленный до совершенства фортран), то есть, конечно, шустростью отличаются программисты. Гений всегда готов написать на Cи или асме так, что будет тормозить на любом самом быстром кластере. И Cи предоставляет ему в этом просто невероятное море возможностей. Например, возможность невозбранно выстрелить себе в ногу. Только для этого надо указать на участок памяти, где лежит нога, по смещению наложить структуру, пройтись по её полям и прямым преобразованием типов (динамического тут нету) передать данные функции «выстрелить». Если что-то произойдёт не так, дадут циферку с номером ошибки. Или не дадут, если функция void. Да, try-catch конструкций тут тоже нет. Ну, то есть, если вы, конечно, хотите, то есть long jump… и даже вроде как есть библиотеки с готовыми реализациями исключений а-ля C++. тысячи их, и все говно.

[просмотр] Лютая, бешеная ненависть

ТруЪ Си люто бешено любим многими, но также и люто бешено ненавидим еще бо́льшими. Похоже, что середины здесь нет и никогда не будет.

Для начала можно упомянуть тот факт, что в C (и во всех производных языках) 1/3 будет равно 0. То есть выражение 1/3==0 истинно, а вот 1/3.0==0 — нет. При этом == как оператор равенства и знак равенства как оператор присваивания до сих пор взрывает неподготовленный специальным образом мозг чуть менее, чем напрочь, по ходу и в наше время являясь источником массы трудноуловимых ошибок у умников, которые не искореняют и даже не читают варнинги.

Во вторую очередь он ненавидим професси-аналами. Они его люто, бешено ненавидят по целому ряду причин.

Во-первых, потому, что отладка в нем может быть сильнейшей еблей мозгов, особенно когда чего-то выходит из своих границ и естественно входит в границы чего-то другого. Сейчас (на самом деле давно уже) стало полегче, а в старые добрые DOS-овские времена запуск некошерного кода зачастую приводил к полному зависанию ящика с необходимостью нажимать «Any Key» и ненажимание кнопки «Save» (в общем-то, кнопки тогда были не везде и обычно надо было давить Ctrl+S, F2 или чего еще) до запуска оной некошерной программы каралось ее некошерным перенабиванием и перепрограммированием в кошерную.

Кроме выхода за границы недозволенного была еще такая штука, как утечка памяти. Это вообще не ловилось никакими отладчиками, и нужно было долго (иногда очень) и вдумчиво (иногда очень) вчитываться в текст такой некошерной программы, чтобы понять, куда эта блядская память течет[2]. Опать-таки теперь сильно полегчало. И не потому, что професи-аналы стали круче, а потому, что памяти стало в 9000 раз больше и сейчас никого ниибёт. А в старые DOS-овские времена любой професси-анал легко мог доказать, что 640К явно ни для чего не достаточно.

Следующая замечательная вещь — рекурсия. И если продвинутый професси-анал мог даже объяснить, как считается C(m, n) рекурсивной функцией, то отладить рекурсивную прогу из более, чем трех строчек было выше его професси-анальных возможностей. Хороший, годный компилятор умеет оптимизировать хвостовую рекурсию, но сам язык этого не гарантирует.

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

  • double (*(*f)(double(*)(double)))(double) — указатель f на функцию, принимающую указатель на функцию, принимающую и возвращающую действительное число, возвращающую указатель на функцию, принимающую и возвращающую действительное число.
  • int (**f)(char *с) — двойной указатель на функцию, принимающую строку и возвращающую целое число
  • int *(*f)(char *с) — указатель на функцию, возвращающую указатель на целое
  • библиотечная void (* signal(int __sig, void (* __func)(int))) (int) из signal.h возвращает указатель на функцию.

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

Такая лютая, бешеная ненависть к фундаментальным понятиям языка не могла пройти незамеченной всякими Майкрософтами. Венцом мелкософтовской ненависти к труЪ Си является появление С#, который на самом деле собственная версия Жабы.

[просмотр] Эзотерика

int i=8, a1, a2;
for (a1=a2=1; i>2; a1=(a2+=a1)-a1)
/*
быдлокодеры думают что это мозгоебалка для школьника,
а на самом деле а1=а2, а не быдло незабывает что такое +=
*/

i--;

Вычисление i-го числа из ряда Фибоначчи с непредсказуемым поведение программы в итоге. из серии «я знаю что в циклах в С/С++ можно писать всякую эзотерическую поебень».

!(n & (n-1))

Проверка: является ли n степенью 2.

"abcd"[0]

Классика: достаем нулевой символ из строки. Нумерация элементов массива начинается с нуля.

printf("%s",sizeof('C')==sizeof(int)?"C":"C++");

Один из способов проверки С или С++, помимо идентификатора __cplusplus. Алсо, многие реализации С до C99 не признают однострочных комментариев // языка С++, что может быть использовано для различия двух братских языков.

#include <math.h>
 
result = (use_cos ? cos : sin)(M_PI);

Выбор функции.

while( *dst++ = *src++ ) ;

Копирование строк.

m(f,a,s)char*s;
{char c;return f&1?a!=*s++?m(f,a,s):s[11]:f&2?a!=*s++?1+m(f,a,s):1:f&4?a--?
putchar(*s),m(f,a,s):a:f&8?*s?m(8,32,(c=m(1,*s++,"Arjan Kenter. \no$../.\""),
m(4,m(2,*s++,"POCnWAUvBVxRsoqatKJurgXYyDQbzhLwkNjdMTGeIScHFmpliZEf"),&c),s)):
65:(m(8,34,"rgeQjPruaOnDaPeWrAaPnPrCnOrPaPnPjPrCaPrPnPrPaOrvaPndeOrAnOrPnOrP\
nOaPnPjPaOrPnPrPnPrPtPnPrAaPnBrnnsrnnBaPeOrCnPrOnCaPnOaPnPjPtPnAaPnPrPnPrCaPn\
BrAnxrAnVePrCnBjPrOnvrCnxrAnxrAnsrOnvjPrOnUrOnornnsrnnorOtCnCjPrCtPnCrnnirWtP\
nCjPrCaPnOtPrCnErAnOjPrOnvtPnnrCnNrnnRePjPrPtnrUnnrntPnbtPrAaPnCrnnOrPjPrRtPn\
CaPrWtCnKtPnOtPrBnCjPronCaPrVtPnOtOnAtnrxaPnCjPrqnnaPrtaOrsaPnCtPjPratPnnaPrA\
aPnAaPtPnnaPrvaPnnjPrKtPnWaOrWtOnnaPnWaPrCaPnntOjPrrtOnWanrOtPnCaPnBtCjPrYtOn\
UaOrPnVjPrwtnnxjPrMnBjPrTnUjP"
),0);}
 
main(){return m(0,75,"mIWltouQJGsBniKYvTxODAfbUcFzSpMwNCHEgrdLaPkyVRjXeqZh");}

Тут и так все понятно:

#include <stdio.h>
main (int t, int _, char *a)
{
return!0<t?t<3?
main(-79,-13,a+main(-87,1-_,main(-86,0,a+1)+a)):1,t<_?main(t+1,_,a)
:3,main(-94,-27+t,a)&&t==2?_<13?main(2,_+1,"%s %d %d\n"):9:16:t<0?t<-72?
main(_,t,"@n'+,#'/*s{}w+/w#cdnr/+,{}r/*de}+,/*{*+,/w{%+,/w#q#n+,/#{l+,/n\
{n+,/+#n+,/# ;#q#n+,/+k#;*+,/'r :'d*'3,}{w+K w'K:'+}e#';dq#'l q#'+d'K#!\
/+k#;q#'r}eKK#}w'r}eKK{nl]'/#;#q#n'){)#}w'){){nl]'/+#n';d}rw' i;# ){nl]!\
/n{n#'; r{#w'r nc{nl]'/#{l,+'K {rw' iK{;[{nl]'/w#q#n'wk nw' iwk{KK{nl]!/\
w{%'l##w#' i; :{nl]'/*{q#'ld;r'}{nlwb!/*de}'c ;;{nl'-{}rw]'/+,}##'*}\
#nc,',#nw]'/+kd'+e}+;#'rdq#w! nr'/ ') }+}{rl#'{n' ')# }'+}##(!!/"
)
:t<-50?_==*a?putchar(31[a]):
main(-65,_,a+1):
main((*a=='/')+t,_,a+1):
0<t?main(2,2,"%s")
:*a=='/'||main(0,main(-61,*a,
"!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m .vpbks,fxntdCeghiry"
),a+1);
}

Тоже программа. А в C++ и C99 вышеприведённые примеры работать не будут, ибо нет неявного int.

ОС на один лист? Легко! Поддерживает многозадачность, гуй (c мышкой). Имеется загрузчик программ, встроенный интерпретатор команд и текстовый просмотрщик.


Компилировать gcc-3.4, полученная программа при запуске сгенерирует ядро, которое нужно запустить grub'ом. Ещё нужен fs.tar

[просмотр] См. также

[просмотр] Примечания

  1. ООП закладывалось еще в 60-е, когда его толком и реализовывать-то было не на чем, поэтому его и не замечали.
  2. Справедливости ради нужно отметить, что тем же самым страдают все остальные языки общего назначения, в которых не реализован механизм автоматической сборки мусора. А особо одарённые быдлокодеры умудряются устраивать memory leaks даже в мусоросборной Жабе путём формирования так называемых «островов» в памяти — коллекций связанных между собой объектов, которые, однако, уже не используются самой программой.


Источник — «http://lurkmore.ru/Pure_C»