Как стать автором
Обновить

Комментарии 61

У них у всех есть (возможно субъективные) недостатки.
D мне нравится больше всех, у него наименее ломающий шаблоны (после С и С++) синтаксис и нет жесткого навязывания стиля программирования, как в Go и Rust. Но и D не лишен недостатков.
Если не ошибаюсь, то в C99 или C11 инициализировать массивы можно с помощью {0}.
Было бы славно дополнить статью поправками в свете свежих стандартов С от специалистов по этому языку.
Для конкатенации строк используется strcat() и strncat(), причём всё это выглядит гораздо красивее.
sizeof() — это не функция, а одноместная операция.
В структурах можно инициализировать отдельные элементы через имена, начиная с C99.

Хочешь посмотреть на красивый C — скачай исходники Git'а и посмотри.
strcat и strncat — просто копируют содержимое одного буфера в другой с учётом нулевых байтов, при этом в целевом буфере уже должна быть предварительно выделена память для такого копирования, иначе травма бедренной артерии гарантирована. В статье рассмотрен общий случай, когда у нас есть два буфера заранее неизвестной длины и нам нужно создать третий как соединение первых двух, и не ломая старые.

Про структуры поправлю, спасибо.
Я имел в виду вот этот фрагмент.
Код
// Append "hello" to s
char hello[] = "hello";
char *news;
size_t lens = s ? strlen( s ) : 0;
news = (char *) realloc( s , ( lens + sizeof( hello ) + 1 ) * sizeof( char ) );
if( !news ) error( "out of memory" );
s = news;
memcpy( s + lens , hello , sizeof( hello ) );



Это просто быдлокод какой-то.
1)
sizeof(char) всегда равно единице по стандарту, поэтому длина строки всегда равна количеству символов в ней плюс один. То есть умножение на sizeof(char) нужно вообще убрать, потому что это умножение на 1.
2)
Возвращаемое из realloc() значение к char * приводить не надо, потому что по стандарту присваивание указателя на void работает в обе стороны без приведений.
3)
Для вычисления размера новой строки нужно использовать strlen(). Здесь ты не использовал, написал какую-то запутанную хрень, из-за чего там закралась ошибка, которой ты не заметил — ты выделил на один байт больше, чем нужно. (Ты вычислил sizeof(hello), что уже включает в себя нулевой байт.)
4)
Вот как раз использование memcpy() вместо strcat() и показывает, что ты нихрена не знаешь в C, даже стандартную библиотеку.
Хоть я и не писал этого кода, позволю себе объяснить вам, почему он написан именно так:

1. Это сделано для единообразия со всеми остальными типами. Без «бессмысленного sizeof» легко поменять char на какой-нибудь wchar_t и забыть домножить где-нибудь на 4.

2. Без понятия, зачем там приведение. Возможно в старых версиях стандарта это было необходимо. Убрал его, чтобы оно вас не смущало. Код не сильно упростился.

3. Да, размер строки может быть меньше размера буфера, так что правильнее использовать тут strlen без вариантов.

4. memcpy гораздо быстрее, чем strcat, так что если длина первой строки заранее известна, то лучше использовать именно memcpy.

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

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

Без понятия, зачем там приведение.

Такое приведение требуется в С++. Часто те, кто учил только C++, думают, что они автоматически узнают C таким образом, и тянут в него соответствующие конструкции.
Особенно часто (практически всегда) распространена ошибка при определении функции main().

memcpy гораздо быстрее, чем strcat, так что если длина первой строки заранее известна, то лучше использовать именно memcpy.

Код должен быть ясным в первую очередь, а быстрым он должен быть во вторую.
Если код неясный, то в нём легко закрадываются ошибки (ты пропустил такую ошибку, выделив на один байт больше).
И что ты предлагаешь отказаться от strcat()? С какой стати?

Было бы замечательно, чтобы вы вместо ты-ты-тыкания через каждое слово

Я в инете больше 15 лет, ты ещё компа не знал, я уже чатился. Для того, чтобы следить за разговором, существуют модераторы. В инете всегда было обращение на ты, всегда. Только после 2000 в инет стали приходить всякие пенсионеры, которые требовали к себе особого отношения, не зная, где какая кнопка на клавиатуре. А молодняк, который приходил в то же время, думал, что это общепринято. Поэтому считай, что это проверка на опыт.
Нет, нужно не просто поменять код, но и сделать пулл-реквест.

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

C — выбирают не за ясность кода, а за эффективность. Строки в C и так медленнее некуда. Незачем делать их ещё медленнее. А код с memcpy и c strcat отличаются лишь именами функций и необходимостью добавлять волшебную единицу во втором случае. Думаю изначально там и была реазизация с strcat, но потом решили соптимизировать и изменили на memcpy, но забыли стереть лишнюю единицу, которая в данном случае является magic number.

Ого, как много. Куда уж мне до вас. Выдыхайте чаще :-)
Такое
int a[3] = { 0 }; /* { 0, 0, 0 } */
в С99 точно есть, мне кажется с С89 можно было так.
А такое?

int a[3] = { 1 }; /* { 1, 1, 1 } */
Странное сравнение. Если мне нужен «близкий к железу» код, то большинство плюсов D превращаются в минусы.

Если же не нужен, то есть С++.

Радость С в том, что он очень тривиально мапится на ассемблер. (Ну, на большинство ассемблеров для разумных архитектур.) А D с одной стороны вроде какбы тоже дольно низкоуровневый, но вот такие «упрощающие жизнь» штуки рвут представление о хорошем маппинге. Скажем, char.max — это что вообще такое? «Метод класса»? Макрос времени компиляции? Встроенная конструкция языка?

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

Писать «для сахара» отдельный язык мне кажется излишним.
Что такое «char.max» — это скорее вопрос правильной документации к языку. Такие вещи должны быть четко определены — как минимум compile-time или run-time.
Это свойства типа. Константы времени компиляции, проще говоря.
Ну вот глянул я краткое описание C11 и вижу, что часть из плюсов языка D перекочевали в C. Стал ли он от этого дальше от железа?

Про C++ будет в следующей статье :-)

D на самом деле разноуровневый и вы можете программировать на любом из уровней. От типов-сумм до встроенного ассемблера.

>>Стал ли он от этого дальше от железа?

Трудно сказать. Я вот посмотрел на фичи по ссылке, и меня немного смущает только многопоточность, потому что лично я не понимаю, как её простым образом переводить в ассемблер. Другие же фичи по большей части скорее улучшают низкоуровневость, вроде макросов для alignment или atomic.

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

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

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

GCC требует линковки с pthreads, если используется многопоточность/асинхронщина в С++11.
Так что это скорее «вы напишите это один раз, а компилятор разберется, как подружить ваш код с платформой», а не реальная фича компилятора
Ну я это примерно и имел ввиду. Стандарт дает хедер <threads.h>, а потом код уже линкуется к платформозависимой библиотеке. Хотя и новое кодовое слово добавляется (_Atomic), так что и компилятор тут немного в деле будет.
Но при этом все равно остается тот же сборщик мусор и из того, что я читал, все с ним не так просто, если он не нужен. Просто взять и отключить не получится, потому что все в языке построено вокруг факта его наличия. Как минимум, всю стандартную библиотеку надо менять на то, что умеет без него работать. И кажется все это уже в итоге доходит до уровня, когда проще взять просто С++ последний и не пытаться сделать из D то, чем он не является.
нужна нормальная IDE для D — проекты, интеграция с системами контроля версий, визарды…
и не надо разбегаться по разным «веткам»: одни ваяют D через LLVM, другие сами с усами — зачем им это? желание покопаться в ассемблере для разных архитектур? делай через LLVM — люди старались, оптимизировали, занимайся чистым D!
Это к JetBrains, у них неплохо получается.
Есть неплохой аддин для Студии
github.com/BBasile/Coedit

  • multi platform (Windows, Linux).
  • comprehensive project format and two advanced project editors (one for the options and configurations, another for the files).
  • DUB projects are supported too, with a an editor for the properties and an inspector to view and select sources or configurations.
  • all the D compilers are supported.
  • compile and run directly from the UI.
  • single click to compile and execute an unsaved module (aka a runnable module).
  • single click to compile and unittest a module.
  • advanced editor with D2 syntax highlighter, folds, regions, identifier markup, macros, sync-edit, etc.
  • list of the symbols in the module being edited.
  • static libraries manager that supports auto-registration from local DUB projects, from online DUB packages or from Coedit custom project format.
  • todo comments parser and dedicated widget.
  • user-defined tools powered by a string interpolation system.
  • full D Completion Daemon integration (completion, hints, call tips, jump to symbol declaration).
  • mini file browser, dfmt interface, search & replace, etc.
  • selection of 3rd party libraries that can be easily build and integrated to Coedit.
Этот код не скомпилируется:

double.min


Для числел с плавающей точкой требуется использовать свойство .min_normal — это сделано во избежание недопониманий о том, что это не является минимумом в том же смысле, что и у целых чисел.
Поправил, спасибо. Эта статься довольно старая, так что этот момент не нашёл в ней своё отражение.
Спасибо за статью. Мне кажется, что было бы интересно сюда же добавить сравнение с Rust.
И до него очередь дойдёт :-)
НЛО прилетело и опубликовало эту надпись здесь
Если речь идет об отладке, то для превращения enum в строку можно просто использовать std.conv.to:
assert(std.conv.to!string(Colors.red) == "red")

Или, используя неявные функции,
import std.conv;

assert(Colors.red.to!string == "red");
В статье речь про отображение энума на произвольные строки, а не просто на одноимённые. А так, да, проще так:

assert( Colors.red.to!string == "red" );
А в C++ что мешает вынести весь сахар в одну либу и ей пользоваться — boost тому пример. Или написать свою бибилиотеку с сахаром с нуля с блекджеком и… ну вы поняли. Зачем мне тогда нужен D?
Тем что подобная библиотека будет где-то сбоку от языка и до возможностей D дотягивать все равно не будет.
отличная шпаргалка!
А вы не подскажете, что вообще на D написано полезного на сегодняший день?
Имеется ввиду из библиотек или какие проекты его используют?
И так и так
Однако для языка, которому столько лет, не так много знаковых проектов.
Для языка, в пиар которого не вкладывалась ни одна крупная корпорация — довольно много ;-)
Это голословное заявление. Давайте факты.
Интересно, какого рода вы ожидаете от меня фактов?
Мне кажется, что для D поезд уже ушел. Он бы круто выстрелил в тот момент, когда не было ещё C++11, а сейчас он уже не выглядит особо инновационным по сравнению с Swift, Rust, Scala, но при этом он заметно сложнее Go. Тем более, что на первых двух вполне можно системный софт делать.

Идея пилить D2 — была фатальной ошибкой.
Я все таки уверен, что D просто не хватило крепкого плеча корпорации. Go — тут тебе и гугл, и феномен докера, и хейт вокруг дизайна. Swift — вообще без вариантов. Rust — таки тащат, как могут, хотя язык по сложности превосходит все вместе взятые. А D — видеть этот пост про 5к строк от фейсбука — с одной стороны это достижение, а с другой это выглядит до того печально, что это похоже одно из наибольших достижений языка. А корпорация возможно бы решила другую проблему — ответить на вопрос, зачем же D нужен. Все остальные нашли свою нишу, а D все эти годы так и болтается непонятно где.
Интересно знать, чего же я такого плохого написал, что аж три минуса получил? D не станет от этого живее и не получит поддержки громкого имени, которое ему жизненно необходимо.
И какие же инновации есть у Swift, Rust, Scala, Go? Go вообще какой-то примитивный. Писать на нем после D откровенно неудобно. Rust хорошо подходит лишь для низкоуровневых задач, Scala — про нее слышу все реже и реже, как и про решения на ней. Инновации в С++11 могут радовать только тех кто на других языках не писал, в которых все это уже есть лет 15 как. При сколько там современный стандарт С++ занимает 1000? 1500 страниц? Вы уверены что все программисты смогут его прочитать, понять и правильно использовать?

Пожалуй сейчас из интересных языков только Swift остается.
Вот как раз swift ничего интересного и не содержит, в отличие от всяких Go и Rust. Первый — из-за рантайма и подхода к ООП. Второй из-за управления памятью. Swift просто пачка всем известных идей со странным синтаксисом не как у всех. Про Scala не знаю, но его преимущество кажется в совместимости с JVM. Примерно как в F# прямо.
синтаксис там, кстати, по большей части удобный и продуманный, но сам язык просто хорошо сделанный.
НЛО прилетело и опубликовало эту надпись здесь
Я несколько раз задумывался над тем, чтобы уйти от С в разработке ядра Фантома. Думал и про D. Но остановило то, что в стандартной поставке gcc его нет. И в cygwin/mingw не входит. :(
А как же LLVM?
А что LLVM? В clang есть d фронт??

(Кстати, я и сишным-то фронтом clang ядро собрать не могу...)
В качестве фронта используется DMD: http://wiki.dlang.org/LDC
Ну что, на какой системный язык переходим?
C
C++
D
Go
Rust

А обзорной статьи сравнивающей все эти языки не напишете?

Для этого надо в них всех как следует разобраться. Боюсь не найду столько свободного времени :-(

Какие из этих знаете было бы интересно сравнить.

D хорошо, C++ уже забыл, да и изменился он уже за 10 лет, C видел лишь в страшном сне, c Go игрался недавно, про Rust много слышал, но не пробовал.

Жаль :(
Потому что на вопрос "на какой системный язык переходим?", без сравнения ответить не получится.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории