LINUX.ORG.RU

Язык Си - никогда не поздно удивляться


1

2

Как вы думаете, какой результат напечатает программа?

#include <stdio.h>

int main()
{
  int a=0,b,c=0,d;
  b = a++ + a++ + ++a;
  d = c+ ++c + ++c;
  printf("a=%d b=%d c=%d d=%d\n", a,b, c,d);
  return 0;
}

Может быть тема и для development, но результат настолько поразил, что руки сами набрали talks.

Перемещено mono из talks

★★★

Последнее исправление: alman (всего исправлений: 1)
Ответ на: комментарий от alman

Компилятор полного си, даже ансишного, довольно сложен и ненужен. «Для себя» достаточно взять простое подмножество языка. В любом случае, сначала надо освоить семантику языка (а где семантический анализ в твоей схеме?), чтобы такие вопросы не возникали.

http://c-faq.com/expr/evalorder2.html

unsigned ★★★★
()

90% людей поражает результат этого листинга! ШОК, ФОТО! Мокрые сишечки без регистрации и СМС

anonymous
()
Ответ на: комментарий от anonymous

mono, или кто тут модерирует, может уже стоит выкинуть tcl-tk-lisp-lor-scala-faq (все равно их никто не читает) и запилить си-фак для таких одаренных? Запустите туда доктора, он вам нагенерит контента, а дальше всех алманов будете отправлять в фак, чтобы не тратить время зря. Профит?

Идеи можно взять из c-faq.com

anonymous
()
Ответ на: комментарий от anonymous

Достаточно просто дочитать любой учебник по C/C++, где написано, что нечитабельный код вообще нужно выкидывать.

anonymous
()
Ответ на: комментарий от anonymous

Достаточно отправлять их в фак и банить, вопросы их подростокового развития нас мало касаются.

anonymous
()
Ответ на: комментарий от Kroz

Примерно так

b = a++ + a++ + ++a

  • <a=0; b=0>
  • b = a++ + a++ + ++a = (a++ + a++) + ++a = (a + a) + ++a = (0 + 0) + ++a = 0 + (++a) = 0 + 1 = 1
  • <a=1; b=1>
  • a++
  • <a=2; b=1>
  • a++
  • <a=3; b=1>

d = c+ ++c + ++c

  1. <c=0; d=0>
  2. d = c+ ++c + ++c = (c + (++c)) + ++c = (c + 1) + ++c = (1 + 1) + ++c = 2 + (++c) = 2 + 2 = 4
  3. <c=2; d=4>
justAmoment ★★★★★
()
Ответ на: комментарий от Manhunt

И тот факт, что на нём до сих пор продолжают играть, говорит о том насколько туга аудитория Си-кодеров.

Не смеши мои тапки, это не «Си-кодеры», а безграмотные студенты или переучивающиеся питонщики.

anonymous
()
Ответ на: Примерно так от justAmoment

То есть процессинг происходит не последовательно как в математике, а «по уровням»:
Уровень 1: подстановка значений переменной
Уровень 2: вычисление ++x, затем опять подстановка
Уровень 3: вычисление всей формулы
Уровень 4: вычисление x++

Вроде так.
Спасибо!

P. S. От компилятора зависит?

Kroz ★★★★★
()
Последнее исправление: Kroz (всего исправлений: 2)
Ответ на: комментарий от unsigned

«Для себя» достаточно взять простое подмножество языка

Ссылку на формальную спецификацию этого подмножества — в студию!

Manhunt ★★★★★
()
Ответ на: комментарий от anonymous

безграмотные студенты или переучивающиеся питонщики

Пишущие код на Си, фулл-тайм за деньги. А в мировом масштабе сюда еще нужно добавить индийских крестьян.

Manhunt ★★★★★
()
Ответ на: комментарий от Manhunt

«Для себя» достаточно взять простое подмножество языка

Ссылку на формальную спецификацию этого подмножества

Зачем тебе формальная - линтер напишешь? А в остальном - MISRA C, например. Другое дело, что писать на таком подмножестве будет тоскливо.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Зачем тебе формальная

Пока она неформальная, нельзя с уверенностью сказать, что подмножество действительно не слишком сложное :)

PS я не про синтаксис

Manhunt ★★★★★
()
Последнее исправление: Manhunt (всего исправлений: 1)
Ответ на: комментарий от hibou

от собственного невежества к свету знаний.

какой смысл в этом знании?

lazyklimm ★★★★★
()
Ответ на: комментарий от alman

Всё гораздо хуже. Решил как-то «запилить» «карманный» компилятор. На лексический анализатор ушло три дня, а потом из лексем стал строить дерево синтаксического разбора. Уже три месяца продолжаю его строить.

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

На выходе из дерева синтаксического разбора будет генерироваться ассемблерный исходник.

Вот так вот сразу? Из синтаксического дерева, без каких либо преобразований? Еще глупее.

Откровенно говоря, я не уверен, что не заброшу этот проект - слишком сложная задача.

Может, тебе вообще программировать тогда не стоит? Эта задача проще чем 99.99% всего, что пишут индусокодеры.

И, кстати, самая тупая ошибка, которую совершают тебе подобные - это начать писать компилятор с парсера (то есть, с самой тупой и незначительной части). Ты что, убогой драконьей книгой обкурился, что ли?

anonymous
()
Ответ на: комментарий от Kroz

То есть процессинг происходит не последовательно как в математике, а «по уровням»:

Наоборот, в математике «многопроходной расчёт»: сначала выставляются приоритеты всем операциям, потом на каждом следующем проходе выполняются операции одного уровня/приоритета над соседними операндами. Выполняется столько проходов, сколько нужно, до тех пор, пока не кончатся операции.

Здесь же расчёт идет слева направо, желательно в один проход. Операции пост-инкремента откладываются на «далёкое потом» и не влияют на результат вычисления выражения. Операции пре-инкремента вычисляются только в том момент, когда до них дойдёт очередь при проходе слева направо. Переменная, изменённая в результате выполнения пре-инкремента, получает новое значение, которое влияет на последующие вычисления, но предыдущие результаты вычислений с участием этой переменной не пересчитываются.

justAmoment ★★★★★
()
Ответ на: комментарий от anonymous

Это ведь ограничение компилятора в возможностях оптимизации.

Какие именно возможности оптимизации ограничиваются, если бы порядок вычисления был задан?

abacaba
()
Ответ на: комментарий от abacaba

Какие именно возможности оптимизации ограничиваются, если бы порядок вычисления был задан?

Как минимум все, связанные с особенностями ILP (то есть, корректный instruction scheduling). Если порядок не определен, легче распараллелить независимые вычисления. Если порядок определен, они становятся зависимыми, и параллелить их уже нельзя.

anonymous
()
Ответ на: комментарий от anonymous

Как минимум все, связанные с особенностями ILP (то есть, корректный instruction scheduling). Если порядок не определен, легче распараллелить независимые вычисления. Если порядок определен, они становятся зависимыми, и параллелить их уже нельзя.

Если вычисления действительно независимы, их можно распараллелить, даже если порядок определён.

abacaba
()
Ответ на: комментарий от Chaser_Andrey

скобки тут не устранят UB ибо (тут есть побочный эф) и скобки не зададут порядок ( можно себе представить реализацию где скобки(<выр,N>) не унарная «оффиксная(аргумент[ы] внутри операции) „операция“ а бинарная со вторым аргументом номером которые задают желаемый(предпочтительную ab или ba если компилятор может оба варианта допустить) порядок между „допустимо одновременными“ аргументами)

qulinxao ★★☆
()
Ответ на: комментарий от abacaba

Если вычисления действительно независимы, их можно распараллелить, даже если порядок определён.

Если там есть reads/writes, то они не независимы при определенном порядке. Если же семантика языка явным образом говорит, что порядок не определен даже при наличии сайд-эффектов, то их можно оптимизировать, считая, что пользователь знает, что делает, и что сайд-эффекты независимы.

anonymous
()
Ответ на: комментарий от Manhunt

Elements of Programming

Appendix B. Programming Language Sean Parent and Bjarne Stroustrup This appendix defines the subset of C++ used in the book. To simplify the syntax, we use a few library facilities as intrinsics. These intrinsics are not written in this subset but take advantage of other C++ features. Section B.1 defines this subset; Section B.2 specifies the implementation of the intrinsics.

оно и для С (да да (С++==С) true but (Cold=C,C++,Cold==C++)false)

9 страниц? полегчало?

qulinxao ★★☆
()
Ответ на: комментарий от justAmoment

1. алго

Наоборот, в математике «многопроходной расчёт»: сначала выставляются приоритеты всем операциям, потом на каждом следующем проходе выполняются операции одного уровня/приоритета над соседними операндами. Выполняется столько проходов, сколько нужно, до тех пор, пока не кончатся операции.

этот(1) алгоритм если и начто и годен то тока на понимание(что бы не значило)

2. даже люди не ищат самую приоритетную в крокодиле а удовлетворяются первой подходящей(т.е или «скобками листом» или вырожением в цепи инф операций чьё сворачивание не меняет всё выражение «A+B*C» т.е чел не делает нумерацию всех , а ограничивается выяснением локального относительного порядка

на компах (1) по причине своей медлености(при простоте прогерства) не используют (2) по причине своей сложносте не прогают.

и поэтому используют (3) или подобные: «дейкстра?» анализируем слева на права пихаем всё в 2 стека аргументы в аргументы операции в операции ( в момент впиха в стек операций проверяем если на стеке круче операция исполняем(замена Nаргументов на стеке аргументов результатом операции) со стека и повторяем попытку в пиха)

в число операций добавлены скобки как "("(самая сильная) гасящая самую слабую операцию (которая ")") . операция ")" не трогает (сама по себе) стек аргументнов,а лиш снимает(с выполнением) со стека операций «верхнюю» "("

зы. ну и всё выражение начальное для простоты оскобачиваем .

так как 1. не эффек

qulinxao ★★☆
()
Ответ на: комментарий от abacaba

проверка независимости подвыражений эквивалента проблеме-основа ( для случая когда подвыражения с побочнками и есть адрессная индексация)

qulinxao ★★☆
()
Ответ на: комментарий от quowah

Лучше скажи когда можно будет харварный L4 увидеть?

Я не знаю. Может быть и не успею.

alman ★★★
() автор топика
Ответ на: комментарий от anonymous

Если там есть reads/writes, то они не независимы при определенном порядке.

Если записи или чтения «не независимы» от порядка вычисления, то всё равно программа работать не будет из-за UB. Поэтому наличие UB в данном случае никак не помогает оптимизации корректных программ.

abacaba
()
Ответ на: комментарий от abacaba

Если записи или чтения «не независимы» от порядка вычисления, то всё равно программа работать не будет из-за UB.

Не тупи. Они могут быть независимыми (обращаться к непересекающимся областям памяти), но компилятор об этом узнать никак не может. А программист - знает, и пользуется этим.

Поэтому наличие UB в данном случае никак не помогает оптимизации корректных программ.

Помогает. Компилятор не может оценить корректность, а программист - может.

anonymous
()
Ответ на: комментарий от qulinxao

Не думал об этом, т.к. стараюсь не использовать voodoo programming

Chaser_Andrey ★★★★★
()
Ответ на: комментарий от anonymous

Не тупи. Они могут быть независимыми (обращаться к непересекающимся областям памяти), но компилятор об этом узнать никак не может. А программист - знает, и пользуется этим.

Программисту дан restrict специально чтобы сообщить о таком случае компилятору.

abacaba
()
Ответ на: комментарий от abacaba

Программисту дан restrict специально чтобы сообщить о таком случае компилятору.

Restrict далеко не всегда можно применить. Он только для примитивных случаев годится.

anonymous
()
Ответ на: комментарий от anonymous

Restrict далеко не всегда можно применить. Он только для примитивных случаев годится.

Покажи пример, где restrict нельзя применить, но UB может чем-то помочь.

abacaba
()
Ответ на: комментарий от anonymous

И, кстати, самая тупая ошибка, которую совершают тебе подобные - это начать писать компилятор с парсера (то есть, с самой тупой и незначительной части). Ты что, убогой драконьей книгой обкурился, что ли?

Ну я листал эту гнигу и не сказал бы, что она совсем уж убога. Выкати мне, пж, список вменяемой литры.

Да что плохого в написании парсера? 99% не могут написал вменяемый парсер, обычно их поделия не работают нормально и тормазят как говно. Пусть, даже если не получится написать конпелятор, то пусть хотябы он напишет парсер, чем хренпоймичто, а потом пойдёт говнякать ничего из своей затеии не вынеся.

Ну и да, написать вменяемый простенький парсер( не говно на какой-то говнолибе(генераторе), а более-менее вменяемый, чтобы он работал примерно так же быстро, как у гцц) очень сложно и его не напишут 99.99% всех кодеров, а не только индусов.

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

superhackkiller1997
()
Ответ на: комментарий от anonymous

да еще и поперёк стандарта.

anonymous
()
Ответ на: комментарий от superhackkiller1997

*Пишем Компилятор Креншоу (стр 100то)

*Язык С Кернигана Ричи (стр 300та)

*Построение компиляторов Вирт (стр 200те)

все три варианта дают определение языка и его полную реализацию

для любителей битиков

*http://homepage.ntlworld.com/edmund.grimley-evans/bcompiler.html Bootstrapping a simple compiler from nothing

qulinxao ★★☆
()
Ответ на: комментарий от superhackkiller1997

Ну я листал эту гнигу и не сказал бы, что она совсем уж убога.

Половина книги - про парсинг (хватило бы трех-четырех страниц на эту неинтересную и не важную тему). Ни слова о современных подходах (того же SSA нет и в помине). Все как-то через жопу и чрезмерно сложно там, где можно легко и просто.

Выкати мне, пж, список вменяемой литры.

http://www.cs.princeton.edu/~appel/modern/

Да что плохого в написании парсера?

То, что это самое незначительное и не важное в компиляторе.

99% не могут написал вменяемый парсер, обычно их поделия не работают нормально и тормазят как говно.

Не с того конца к задаче подходят, и не теми методами пользуются.

anonymous
()
Ответ на: комментарий от abacaba

A[i+c1]++ + A[i+c2]--;

c1 и c2 - аргументы функции, про них ничего компилятор не знает, а программист знает, что i+c1 и i+c2 никогда не пересекутся.

anonymous
()
Ответ на: комментарий от anonymous

Непонятно, как в этом примере компилятор должен определить, какой порядок чтения/записи более оптимальный.

Но указать их независимость тем не менее возможно:

T* restrict a = &A[i+c1];
T* restrict b = &A[i+c2];
(*a)++ + (*b)--;

abacaba
()
Ответ на: комментарий от abacaba

Ну и не извращение ли это? Зачем делать сложным то, что можно сделать просто?

Точно так же я могу сказать, что если хочешь определенного порядка вычисления аргументов - используй промежуточные переменные. Вопрос в приоритете. Разработчики стандарта Си решили, что мой случай приоритетнее чем твой. Смирись.

anonymous
()
Ответ на: комментарий от abacaba

Непонятно, как в этом примере компилятор должен определить, какой порядок чтения/записи более оптимальный.

А какую именно букву в слове ILP ты не понял? Порядка нам тут как раз не надо. Надо, чтобы инструкции исполнялись параллельно. Для VLIW или EPIC это должно быть прописано явно, Си вообще разрабатывали, когда никакого OoO и в помине не было.

anonymous
()
Ответ на: комментарий от anonymous

Половина книги - про парсинг (хватило бы трех-четырех страниц на эту неинтересную и не важную тему). Ни слова о современных подходах (того же SSA нет и в помине). Все как-то через жопу и чрезмерно сложно там, где можно легко и просто.

Через жопу и излишне сложно - это закон нынешнего мейнстрима от этого некуда не деться. А простота - это удел тех, кто понял что такое простота, а для тех, кто не понял - простота == черезжопу.

То, что это самое незначительное и не важное в компиляторе.

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

В этом есть очень большая доля фейла, когда человек без должной практики( не понимает в чем суть любления битов, не понимает триксов и пацанского юза Сишки, боится 90% её фич и т.п.) ЯП начинает пилить конпелятор этого ЯП. Получается говно и этого надо избегать.

Не с того конца к задаче подходят, и не теми методами пользуются.

Да не в этом дело, дело какраз таки в том, о чем я говрил выше - это нулевое умении создавать вменяемые реализации, ибо почти у всех тех, кто интересуется «компиляторостроением» теорицизм головного мозга, который передаётся зелени.

Вон тот же qulinxao им болеет, правда не в терминальной степени, но всё же.

Начинать надо всегда снизу вверх, от реализации к теории. Когда человек понимает как и что можно реализовать, тогда он будет подбирать и правильную теорию, которая реально «коррелирует» с реальным миром. Именно этому и учит парсеростроение, ибо для написании вменяемого парсера тебе нужно знание, которое потом тебе поможет - поэтому ценен не сам парсер, а то, что он оттачивает( если пациет не халтурит).

superhackkiller1997
()
Ответ на: комментарий от anonymous

Ну и не извращение ли это? Зачем делать сложным то, что можно сделать просто?

Нет, не извращение. Те кто хочет оптимальный код, и не такое пишут: http://cellperformance.beyond3d.com/articles/2006/05/demystifying-the-restric...

Simplify expressions. Do not mix memory access with calculations. Use the [ Load --> Update --> Store ] pattern.

- цитата оттуда.

Т.е. UB никакой оптимизации не помогает, просто недоопределённое место в стандарте, оставленное по-видимому для сохранения исторически сложившейся совмести компиляторов друг с другом.

abacaba
()
Ответ на: комментарий от abacaba

Отсутствие определенного порядка вычисления аргументов функции или бинарного оператора - это не «исторически сложившееся», это весьма разумное, удобное и правильное решение.

Если тебе что-то не нравится - то это твои проблемы.

- цитата оттуда.

У них компилятор - говно.

anonymous
()
Ответ на: комментарий от anonymous

Ну и не извращение ли это? Зачем делать сложным то, что можно сделать просто?

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

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

superhackkiller1997
()
Ответ на: комментарий от anonymous

Если тебе что-то не нравится - то это твои проблемы.

Нет, не мои. Проблемы у тех авторов, которые полагаются на UB для «декларации» отсутствия перекрытия в доступе к памяти (что стандартом никак не гарантируется), и пользователей их программ.

abacaba
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.