Си является одним из наиболее широко используемых языков в мире. На его долю приходится огромная доля существующего кода, и он продолжает использоваться для огромного количества нового кода. Он пользуется популярностью среди пользователей, настолько широко портирован, что возможность запуска C является для многих неофициальным определением платформы , и его поклонники хвалят за то, что он «маленький» язык с относительно чистым набором функций.
Так где же все компиляторы?
На рабочем столе есть (реально) два : GCC и Clang. Подумав об этом несколько секунд, вы наверняка вспомните, что Intel тоже существует. Есть горстка других, слишком непонятных для обычного человека, чтобы назвать их и почти повсеместно не заботящихся о поддержке недавней языковой версии (или часто даже четко определенного языкового подмножества, просто «подмножество»). Половина членов этого списка - исторические сноски; большинство остальных очень специализированы и все еще не реализуют полный язык. Очень немногие действительно кажутся открытыми.
Scheme и Forth - другие маленькие языки, которые так любят их поклонники - вероятно, имеют больше компиляторов, чем настоящие пользователи. Даже что-то вроде SML имеет на выбор более «серьезные» реализации, чем C. Принимая во внимание, что объявление о новом (незаконченном) компиляторе C, нацеленном на проверку, на самом деле видит некоторые довольно негативные ответы, и ветеранские реализации пытаются получить достаточно участников, чтобы даже догнать C99.
Почему? Реализация C так сложно? Это не C ++. Имеют ли пользователи просто весьма искаженное представление о том, к какой группе сложности они относятся (т.е. что они на самом деле ближе к C ++, чем к Scheme)?
Ответы:
Сегодня вам нужен реальный компилятор C, чтобы быть оптимизирующим компилятором , особенно потому, что C больше не является языком, близким к аппаратному, потому что текущие процессоры невероятно сложны ( вышли из строя , конвейерны , суперскалярны , со сложными кэшами и TLB , следовательно, нуждающийся в расписании инструкций и т.д ...). Современные процессоры x86 не похожи на процессоры i386 прошлого века, даже если они оба могут выполнять один и тот же машинный код. Посмотрите, что C не является языком низкого уровня (ваш компьютер не быстрый PDP-11), статья Дэвида Чисналла.
Мало кто использует наивные неоптимизирующие компиляторы C, такие как tinycc или nwcc , поскольку они создают код, который в несколько раз медленнее, чем может дать оптимизирующий компилятор.
Кодирование оптимизирующего компилятора сложно. Обратите внимание, что и GCC, и Clang оптимизируют некое «исходное от языка» представление кода (Gimple для GCC, LLVM для Clang). Сложность хорошего компилятора C не находится на этапе анализа!
В частности, создание компилятора C ++ не намного сложнее, чем создание компилятора C: анализ C ++ и преобразование его в некоторое внутреннее представление кода является сложным (потому что спецификация C ++ сложна), но хорошо понятна, но части оптимизации еще более сложны. сложный (внутри GCC: оптимизация среднего уровня, нейтральность исходного языка и целевого процессора, составляют большую часть компилятора, а остальная часть балансируется между интерфейсами для нескольких языков и фонами для нескольких процессоров). Следовательно, большинство оптимизирующих компиляторов C также способны компилировать некоторые другие языки, такие как C ++, Fortran, D, ... Части GCC, специфичные для C ++, составляют около 20% от компилятора ...
Кроме того, C (или C ++) настолько широко используется, что люди ожидают, что их код будет компилируемым, даже если он не совсем соответствует официальным стандартам, которые недостаточно точно определяют семантику языка (поэтому каждый компилятор может иметь свою собственную интерпретацию этого). Посмотрите также на проверенный CompCert C-компилятор и статический анализатор Frama-C , которые заботятся о более формальной семантике C.
Оптимизация - это феномен длинного хвоста : реализовать несколько простых оптимизаций легко, но они не сделают компилятор конкурентоспособным! Вам необходимо реализовать множество различных оптимизаций, а также организовать и разумно их объединить, чтобы получить конкурентоспособный компилятор. Другими словами, реальный оптимизирующий компилятор должен быть сложным программным обеспечением. Кстати, и GCC, и Clang / LLVM имеют несколько внутренних специализированных генераторов кода C / C ++. И то, и другое - огромные звери (несколько миллионов строк исходного кода, скорость роста которых составляет несколько процентов в год) с большим сообществом разработчиков (несколько сотен человек, работающих в основном полный рабочий день или по крайней мере половину рабочего дня).
Обратите внимание, что нет (насколько мне известно) многопоточного C-компилятора, даже если некоторые части компилятора могут выполняться параллельно (например, внутрипроцедурная оптимизация, распределение регистров, планирование инструкций ...). И параллельной сборки с
make -j
не всегда достаточно (особенно с LTO ).Кроме того, трудно получить финансирование на кодирование компилятора C с нуля, и такие усилия должны длиться несколько лет. Наконец, большинство компиляторов C или C ++ на сегодняшний день являются свободным программным обеспечением (больше не существует рынка для новых проприетарных компиляторов, продаваемых стартапами) или, по крайней мере, являются монопольными товарами (такими как Microsoft Visual C ++ ), и для компиляторов почти требуется свободное программное обеспечение ( потому что они нуждаются в участии многих различных организаций).
Я был бы рад получить финансирование для работы над компилятором C с нуля как свободное программное обеспечение, но я не настолько наивен, чтобы верить, что это возможно сегодня!
источник
(there is no more a market for proprietary compilers
Расскажите об этом команде Visual Studio ...Я хотел бы оспорить ваше базовое предположение, что существует только небольшое количество реализаций языка Си.
Я даже не знаю C, я не использую C, я не член сообщества C, и все же, даже я знаю гораздо больше, чем несколько упомянутых вами компиляторов.
Прежде всего, существует компилятор, который, вероятно, полностью затмевает как GCC, так и Clang на настольном компьютере: Microsoft Visual C. Несмотря на достижения OSX и Linux на настольных компьютерах, а также долю рынка, которую iOS и Android «украли» В отличие от бывших традиционных пользователей настольных компьютеров, Windows по-прежнему является доминирующей настольной ОС, и большинство программ Windows C для настольных компьютеров, вероятно, скомпилированы с использованием инструментов Microsoft.
Традиционно каждый производитель ОС и каждый производитель чипов имели свои собственные компиляторы. Microsoft, как поставщик ОС, имеет Microsoft Visual C. IBM, как поставщик ОС, так и поставщик микросхем, имеет XLC (системный компилятор по умолчанию для AIX и компилятор, с помощью которого компилируются и AIX, и i / OS). , У Intel есть свой компилятор. У Sun / Oracle есть собственный компилятор в Sun Studio.
Кроме того, существуют производители высокопроизводительных компиляторов, такие как PathScale и The Portland Group, чьи компиляторы (и библиотеки OpenMP) используются для перебора чисел.
Цифровой Марс также все еще в бизнесе. Я считаю, что Уолтер Брайт обладает уникальным отличием, будучи единственным человеком на планете, который сумел создать компилятор С ++ производственного качества (в основном) сам.
И последнее, но не менее важное: у нас есть все проприетарные компиляторы для встроенных микроконтроллеров. IIRC, каждый год продается больше микроконтроллеров, чем продаются настольные, мобильные, серверные, рабочие станции и мэйнфреймы за всю историю комбинированных вычислений. Так что это определенно не нишевые продукты.
Почетное упоминание обращается к TruffleC , интерпретатору C (!), Работающему на JVM (!), Написанной с использованием среды интерпретатора Truffle AST, которая всего на 7% медленнее, чем GCC и Clang (в зависимости от того, что быстрее в любом конкретном тесте) по всему Тест на знание компьютерных языков, причем быстрее, чем на микробенчмарках. Используя TruffleC, команда Truffle смогла получить свою версию JRuby + Truffle для выполнения расширений Ruby C быстрее, чем фактическая реализация C Ruby!
Итак, это 6 реализаций в дополнение к тем, которые вы перечислили, и я могу назвать их на макушке, даже ничего не зная о C.
источник
Сколько компиляторов вам нужно?
Если у них разные наборы функций, вы создаете проблему переносимости. Если они коммодитизированы, вы выбираете «по умолчанию» (GCC, Clang или VS). Если вы заботитесь о последних 5% производительности, у вас есть эталонный тест.
Если вы занимаетесь языком программирования для отдыха или в исследовательских целях, скорее всего, это будет более современный язык. Отсюда распространение игрушечных компиляторов для Scheme и ML. Хотя OCaml, похоже, набирает обороты для не игрушечных неакадемических целей.
Обратите внимание, что это сильно зависит от языка. По сути, Java имеет набор инструментов Sun / Oracle и GNU. В Python есть различные компиляторы, ни один из которых не пользуется уважением по сравнению со стандартным интерпретатором. Rust и Go имеют по одной реализации. C # имеет Microsoft и Mono.
источник
1000 * 0
все еще0
.int
, и требует, чтобы разные компиляторы интерпретировали один и тот же исходный код по-разному.6g
/8g
/… toolchain и gccgo). Раньше также была очень интересная коммерческая реализация, называемая erGo, которая была: а) родной реализацией Go для Windows в то время, когда ни gccgo, ни оригинальный компилятор Go не работали очень хорошо на Windows, б) компанией, ставящей на Go, долго еще до того, как он стал 1.0, и в) первая реализация Go написана на Go (gccgo и 6g / 8g написаны на C). Однако и проект, и компания исчезли еще до того, как вышли из закрытой бета-версии.C / C ++ является уникальным среди скомпилированных языков в том смысле, что он имеет 3 основных реализации общей спецификации.
В соответствии с правилом отклонения всего, что не используется много, каждый другой скомпилированный язык имеет 0 к 1.
И я думаю, что javascript - единственная причина, по которой вам нужно указывать «скомпилированный».
источник
uint16_t a=48000u; unsigned uint32_t b=(a*a)/2;
как присвоениеb
значению 8192. Некоторые определяют его как присвоение 1152000000. Большинство в настоящее время рассматривают его как неопределенное поведение и, скорее всего, сохранят 3299483648, но не дают никаких обещаний в этом отношении.2
или,2u
по-видимому./2u
? Определяется переполнение без знака (как по модулю 2 ^ N для N, определенного реализацией), но деление не может даже переполниться.int
, но чей продукт не будет соответствовать этому типу. Приведение этого результата к unsigned int, вероятно, изменит интерпретацию полученного значения, но не отменит неопределенного поведения от предыдущего вычисления.Так какой у вас целевой язык?
Компиляторы SML часто нацелены на C или что-то вроде LLVM (или, как видно из вашей ссылки, JVM или JavaScript).
Если вы компилируете C, это не потому, что вы собираетесь в JVM. Вы идете к чему-то хуже, чем C. Гораздо хуже. И затем вы получаете возможность дублировать этот незначительный ад несколько раз для всех ваших целевых платформ.
И конечно, C - это не C ++, но я бы сказал, что он ближе к C ++, чем Scheme. У него есть собственное подмножество неопределенной поведенческой злости (я смотрю на вас размером встроенных типов). И если вы испортите эти мелочи (или сделаете это «правильно», но неожиданно), то у вас есть десятилетия существующего кода на жизненно важных системах, которые скажут вам, насколько вы ужасны. Если вы испортите SML-компилятор, он просто не будет работать - и кто-то может заметить. Когда - нибудь.
источник
int
что они будут 32 или 64- битными, но могут быть и 16-битными. Нетрудно получить число вне диапазона,[−32767, +32767]
аint
переполнение - UB. Такжеchar
/short
повышаетсяint
илиunsigned int
зависит от того,int
может ли представлять каждое значение исходного типа, что может дополнительно инициировать преобразование изint
в,unsigned int
если операнды имели разные типы и были преобразованы по-разному, плюс потенциально другое преобразование, когда вы присваиваете результат переменной ,