Комментарии 136
Да, мы — бяки и заставили вас запутаться.
Ну лично у меня статья только раздражение вызвала из-за этого. Не знаю, может кому-то такая уловка и по душе.
C99: 7.4.1.10 The isspace function
The standard white-space characters are the following: space (' '), form feed ('\f'), new-line ('\n'), carriage return ('\r'), horizontal tab ('\t'), and vertical tab ('\v'). In the «C» locale, isspace returns true only for the standard white-space characters.
Ловить ошибке в коде, к которому кто-то приписал спереди
#define true false
— это не для белых людей, извините.P.S. То есть статический анализатор, конечно, тут молодец, но вообще идея заменять стандартные функции… за такое по рукам надо бить не в функции EatWhitespace, а там, где
#define
написан…Не ужили ещё кто то пользуется IDE в которых макросы не выделяются другим цветом?
Upd: по традиции под статьёй единорога надо упомянуть про раст, там все макросы заканчиваются на "!".
isspace
— это тоже макрос. Вот такой:#define isspace(c) __isctype((c), _ISspace)
Но он стандартам соотвествует. Можно навести мышкой и увидить, что «тут что-то не то», конечно — но на каждую букву наводить мышкой не будешь… Впрочем статическому анализатору хорошо бы ругнуться на этапе переопределения стандартного макроса.
То есть то, что он поймал ошибку — это неплохо, плохо что вообще кто-то переопределяет стандартные функции и ему за это ничего не делают…
Для меня любой макрос это сразу знак что жди сюрпризов. Стараюсь их вообще не использовать. В коде на си плюс плюс их практически не вижу. Большинство вопросов решается темплейтами. Чтобы сэкономить пару слов вводить макрос тоже смысла нету, а если и есть то они обычно пишутся капсом чтобы не спутать с названием функции, и опять же IDE все подсвечивает. Почему в glibc isspace определили как макрос хотя во всех доках это функция из int в int, и что за такты процессора они на этом экономят я искренне недоумеваю. Со спецификой си не знаком, видел один раз ООП на макросах в гномовской g-lib, сочувствую.
inline
.GCC с --std=c90 прекрасно работает с __inline__ или glibc собирается чем-то кроме gcc не поддерживающем это расширение gcc?
Поэтому ответ должен быть немного глубже.
Действительно все дело в оптимизации и довольно много кейсов когда вызов функции значительно замедляет работу. Например вам нужно удалить/заменить пробелы на что-то в большом объеме текста (простой lut даст прирост скорости в 2 раза при грамотной организации цикла) и тогда есть смысл сначала узнать доступна ли ли табличная/каноничная реализация isctype, что и делает макрос с fallback на inline либо extern int isctype(int, int) реализацию в glibc…
Отсюда макросы. А по скорости в современных компиляторах разницы нету.
т.е. разрабы glibc, жертвуют нормально подсветкой синтакиса, оборачивают все аргументы в запасные скобочки, расставляют переносы строк через "\" потому что 30 лет назад не было inline?
Но как уже писали выше, GNU libc компилируется GCC.
On most architectures, GCC 5 or later is required to build the GNU CВы говорите про первый абзац, но в случае с .h-файлами важен второй.
Library. (On powerpc64le, GCC 6.2 or later is still required, as
before.)
Older GCC versions and non-GNU compilers are still supported when
compiling programs that use the GNU C Library.
RETURN VALUE
fgetc(), getc() and getchar() return the character read as an unsigned char cast to an int or EOF on end of file or error.
Edit:
P.S.: Пробежался взглядом по статье. Всётаки, со времён появления man, его отсутствие в системе, — настоящее увечье.
Переопределение стандартных функций является плохой практикой.
До сих пор с содроганием вспоминаю как в одном проекте на JS, кто то взял и в конец одной либы дописал пару специфических вызовов. Пол дня пришлось убить чтобы понять где зарыта магия и почему если поменять версию либы на более новую, ошибок нет но и работать ничего не работает.
Поведение макроса было бы куда веселее в таком виде:
for (; isspace (c = getc (InFile)) && ('\n' != c););
copyStream(readStream(inputStream));
Лень пробел нажать, или на перфокарты запись идет и места нет? Давайте тогда и между словами пробелы не ставить, это же пустая трата времени) И что самое смешное — ладно бы это всего касалось, но после операторов (неожиданно), пробелы ставятся в большинстве случаев. Есть ли какое-либо объяснение этому кроме как что это бездумное употребление каких-то пережитков прошлого?
UPD: Я ОЧЕНЬ медленно пишу комментарии.
UPD: Я ОЧЕНЬ медленно пишу комментарии.Ахах, в смысле отвечаете не сразу, или печатаете долго?) Ничего, у нас тут не чат, я и сам отвечаю по мере возможности)
… первый элемент должен иметь индекс 1 ...
«первый элемент» — порядковый номер;
«индекс 1» — индекс;
Порядковый номер и индекс не обязаны совпадать.
… например, из трех элементов, то логично предположить что и общее количество должно равняться трем. Ан нет, двум (3 — 1) ...
опять путаница…
Количество элементов — 3
Индекс последнего элемента — 2
SQL был разработан сильно раньше, так что неудивительно, что он использует менее удобную, но более исторически правильную нумерацию. Когда-то компьютеры заставляли вообще работать в десятичной системе счисления (знаменитый ЭНИАК никакой другой не знал, и даже 8086, при всей своей примитивности, имел специальные команды для этого) — но мы всё-таки перешли в программировании к двоичной, как более логичной… то же самое и с индексами.
P.S. В этом смысле американцам проще: картошку они вешают в футах, а когда что-то рассчитать нужно — переходят в СИ, так что идея, что индексы в массиве обязательно должны нумероваться так же, как мешки картошки им даже в голову не приходит.
О, спасибо, но ведь он и объясняет почему мы считаем с единицы, а с нуля-то по какой логике?Вообще-то он объясняет почему так. Достаточно подробно. Вначале объясняет почему лучше использовать полуинтервалы как в C++ (включающие левый конец, но не включающие правый), потом замечает что при таком подходе у нас будет либо полуинтервал от 0 до N, либо от 1 до N+1. Последнее выглядит, прямо скажем, странно.
SQL был разработан сильно раньше, но со временем-то почему вдруг с какой-то стати решили, что с нуля удобнее?Когда накопился опыт и стало понятнее, что с нуля действительно удобнее. Формулы проще получаются.
«Удобнее» — это следствие, но должна иметься причина.Причина простая: ноль — это ничего, а единица — уже что-то. Для перехода от последовательности чисел к первому элементу вроде как мы ничего не должы бы делать — но при записи a[1] какжется что мы что-то делаем.
Дейкстра приводит пример языка Mesa, где были предусмотрены сразу все возможные варианты… вариант с нуля (включая нуль) до N (не включая N) работает лучше — в большинстве случаев (хотя и не всегда).
Это как я на Гитхабе в issues спрашивал почему спецификация JSON подразумевает, что ключи объекта идут не по порядку добавления, а рандомом, на что получил ответ, что если они будут идти в порядке добавления, то это уже будет не JSON.Ну это же, блин, логично! JSON — это JavaScript Object Notation, а то, что вы предлагаете уже никак не будет JavaScript объектом! А поскольку у JSON одно из важнейших свойств — это неизменность спецификации (не бывает JSON 1.0, JSON 2.0, JSON X или JSON Advanced), то понятно, что предложенного вами варианта не будет. Уж не говоря о том, что этот подход нелогичен (в том же смысле в каком нелогична нумерация с единицы): для того, чтобы ключи объекта можно было возвращать в порядке добавления вам их нужно будет хранить в двух структурах в памяти и работы с ними станет медленее — а нафига это нужно?
Спецификация Javascript лежит на сайте tc39.github.io, а не developer.mozilla.org :-)
Такие полуинтервалы хорошо работают при интерпретации только по возрастанию. В обратном направлении — начинается издевательство над здравым смыслом. Вот пример из питоновской range(), в которой как раз их и делали:
>>> range(0,5) [0, 1, 2, 3, 4]
ok, а если наоборот? «Дэти, эта невазможна понят, эта нада запомнит»:
>>> range(4,-1,-1) [4, 3, 2, 1, 0]
А если бы рядом с подобным полуоткрытым была функция для простого закрытого — таких издевательств не было бы. Или универсальная с флагами для открытости/закрытости обеих сторон.
А ещё у нас язык к этому не приспособлен, и это хорошо видно на том же C++: везде, где в STL написано end, должно было быть другое слово — например, limit, потому что end всеми не-программистами будет понято как последний элемент.
То же и с нумерацией: мы не можем переломать естественный язык и потребовать называть первый нулевым. Как минимум нужны дополнительные уточнения о режиме счёта.
> Когда накопился опыт и стало понятнее, что с нуля действительно удобнее. Формулы проще получаются.
Может, в 1970-м это имело значение. Сейчас трансляторы достаточно мощные, чтобы это скомпенсировать, а соответствие ожиданиям человека важнее для получения безошибочного кода.
> для того, чтобы ключи объекта можно было возвращать в порядке добавления вам их нужно будет хранить в двух структурах в памяти и работы с ними станет медленее — а нафига это нужно?
Нужно. Именно для человека: хотя бы чтобы можно было легко сравнивать два объекта в типовых условиях.
Да, иногда для этого требуется лексикографическое упорядочение ключей. Но практика показала, что insertion order достаточен для подавляющего большинства случаев, и его формализация стала весьма распространённым явлением. Оно есть в JS, оно есть в Python начиная с 3.6 (и закреплено официально с 3.7), и наверняка будет продолжаться и дальше.
И насчёт «станет медленнее» — опыт реализации в Python показал, что если замедление и есть, то оно ничтожно.
И насчёт «станет медленнее» — опыт реализации в Python показал, что если замедление и есть, то оно ничтожно.Вы бы ещё реализацию на brainfuck'е сюда приплели. Python — это такой язык, где скорость не важна. Вообще. Если вы хотя бы задумываетесь над тем, что что-то медленно работает, то это что-то нужно переписать на другом языке. Потому неудивительно, что там разработчики могут позволить себе разные странности.
Нужно. Именно для человека: хотя бы чтобы можно было легко сравнивать два объекта в типовых условиях.Вот там где вы хотите сравнивать — там и отсортируйте. JSON — оказался фактически идеалом во многих ситуациях потому, что он прост и эффективен. Если вы что-то делаете «для человека» и на эффективность вам наплевать — есть много более удобных альтернатив.
Может, в 1970-м это имело значение. Сейчас трансляторы достаточно мощные, чтобы это скомпенсировать, а соответствие ожиданиям человека важнее для получения безошибочного кода.«Большой переход» произошёл в 1990е, а не в 1970е. И сейчас уже, если говорить об ожиданиях, то скорее стоит ожидать, что последовательность будет x₀, x₁, x₂, ... — а не что массивы с нуля будут нумероваться.
А если бы рядом с подобным полуоткрытым была функция для простого закрытого — таких издевательств не было бы. Или универсальная с флагами для открытости/закрытости обеих сторон.Почитайте Дейкстру ещё раз, чёрт побери. Пробовали — не работает. Потому что C++-стайл интервалы реально удобны, если интервалы возрастают, а поскольку этот вариант встречается намного чаще других — то люди, встречая интервалы другого типа, их путают.
А ещё у нас язык к этому не приспособлен, и это хорошо видно на том же C++: везде, где в STL написано end, должно было быть другое слово — например, limit, потому что end всеми не-программистами будет понято как последний элемент.Это нормально. У любой профессии есть сленг — и часто простые, обыденные, слова в этом сленге значат не совсем то, что в быту. Программирование — не исключение.
1. Важна, и реально проверяется и оптимизируется.
2. JavaScript вы поставили в ту же категорию? Если бы было так, для него не делали бы движков типа V8. И в результате в JS делают insertion order, даже зная, что это даст потерю производительности.
> JSON — оказался фактически идеалом во многих ситуациях потому, что он прост и эффективен. Если вы что-то делаете «для человека» и на эффективность вам наплевать — есть много более удобных альтернатив.
Для «прост и эффективен» для машины JSON как раз не годится по определению — он таков для человека. Для машины лучше бы подошло что-то вроде ASN.1 BER или структур линуксового netlink.
А раз сделали человекочитаемость — то оказалось, что и порядок ключей важен настолько, что попытки его убрать дали откат обратно под давлением.
> Почитайте Дейкстру ещё раз, чёрт побери. Пробовали — не работает. Потому что C++-стайл интервалы реально удобны, если интервалы возрастают, а поскольку этот вариант встречается намного чаще других — то люди, встречая интервалы другого типа, их путают.
Читал. Это у вас профессиональное «когда молоток в руках, всё вокруг — гвозди»: если писать под C++ STL или аналог с его подходами, то вы и не будете ничего кроме [begin;end) видеть вокруг.
Реально же оказалось, в терминах того же Питона, что range(a,b+1) приходится писать чаще, чем range(a,b). А если бы были rangecc(a,b) и rangeco(a,b) — не пришлось бы костылировать на ровном месте.
> Это нормально. У любой профессии есть сленг — и часто простые, обыденные, слова в этом сленге значат не совсем то, что в быту. Программирование — не исключение.
Этот сленг в таком виде только у C++ и ещё, возможно, пары инвалидов. Остальные даже в программировании его очень неохотно принимают.
А раз сделали человекочитаемость — то оказалось, что и порядок ключей важен настолько, что попытки его убрать дали откат обратно под давлением.
Вот только текущий порядок ключей в JS — 1, 2, 3, foo :-)
2. JavaScript вы поставили в ту же категорию? Если бы было так, для него не делали бы движков типа V8. И в результате в JS делают insertion order, даже зная, что это даст потерю производительности.С ним очень неприятная история произошла: он также был разработан, как язык, для которого производительность не важна (а «тяжёлые» вычисления должны были выполняться в плагинах), а потом плагины «отсекли» и в результате «зерно стали возить по воздуху».
Для «прост и эффективен» для машины JSON как раз не годится по определению — он таков для человека. Для машины лучше бы подошло что-то вроде ASN.1 BER или структур линуксового netlink.Если говорить об эффективности, но нужно на какие-нибудь Cap-n-Proto смотреть. Но паркинг всего этого гораздо меньше отличается по сложности от парсинга JSONа, чем парсинг JSONа от какого-нибудь XML. Зато JSON — один и его парсер для любого языка пишется за день. Ну два — если язык сильно крив.
То есть в конечном итоге оказалось, что в оригинальной спецификации ключи идут в порядке добавления?)Как тут уже заметили: оригинальная спецификация — это-таки ECMA-262, 1999й год, никакого «порядка добавления» там нет.
Из вашего описания что-либо понять сложно, но если кто-то полагается на то, что объекты возвращаются из JSON в определённом порядке — то нужно соответствующий компонент исправить/передалать, а не делать форки библиотек.
FBReader, кстати, хороший пример, читалка такая, поддерживается всеми платформами, которыми только может поддерживаться, причем полноценно, начиная с Symbian и Blackberry, и заканчивая чуть ли не Бадой. Хочется познакомиться с разрабом и узнать у него чем он занимается по жизни, что имеет столько свободного времени, ибо лично я сам разраб и знаю сколько времени занимает программирование.
P.S. Хороший пример, надо будет запомнить.
- номер элемента массива K, в который входит этот байт
- номер байта k внутри этого элемента
Если считать от 1, то формулы будут такими:
K = (n - 1) / s + 1
k = (n - 1) % s + 1
Если считать от 0, то формулы будут такие:
K = n / s
k = n % s
С того момента, как сталкиваешься с этой арифметикой, все становится очевидно. Операции с временем — действительно хороший пример, потому что всем понятен.
Операции с временем — действительно хороший пример, потому что всем понятен.Как видим не всем. Людям, которые думать не хотят ничего не поможет.
Людям, которые думать не хотят ничего не поможет
Если речь обо мне, то я попросил рассказать о причинах, а не о следствии (сутки начинаются с 00:00 — следствие, почему они начинаются с 00:00 — причина). До сих пор ответа не получил, без пищи для размышления думать просто не о чем, как бы ни хотелось.
Но это по отношению к протяжённым сущностям всех видов, и то есть отклонения («1960-е годы» это не до 01.01.1960, а начиная от него). Перенос же этих правил на точечные объекты — а элементы массива/списка/etc. следует рассматривать именно так — однозначно не производится, и оттого, что «третий километр» можно рассматривать как цельный не пройденный ещё километр по счёту 3, начиная с 1, не мешает его точно так же рассматривать как по счёту 2, начиная с 0, потому что мы полных 3 километра ещё не намотали.
Собственно все аргументы подходов типа «0-е число» основаны именно на единообразности представления _частичной_ реализации протяжённой сущности при любой точности, с округлением через усечение, и от того, что усечение просто удобно — отбросил цифры и получил нужный результат. Формально математически это действительно так. Осталось понять, насколько эта формальность удобна в остальных вопросах.
Формально математически это действительно так. Осталось понять, насколько эта формальность удобна в остальных вопросах.
Вот я о чем и говорю, по мне дак массив — это не отрезок, а хранилище, поэтому я не с проста про мешки пример привел, ибо первый мешок — это первый мешок, а не нулевой. Но за трактовку спасибо, уж что есть — то есть, что уж теперь…
Вот пусть компьютеры и занимаются этой арифметикой, они хорошо это делают. Если компилятор соптимизирует при этом for (i=1;i<=N;++i) в for(i=0;i<N;++i) и внутри себя перестанет вычитать ту единицу — его дело и его право!
Людям же надо делать так, как удобно для людей. Вы не переделаете естественные языки и мышление так, чтобы счёт везде (не в компьютере) начинался с 0.
Ну а для тех случаев, когда действительно удобнее считать с 0, можно ввести и синтаксис в духе var t: array[0..999] of integer. Нужно такое системщикам — пусть рисуют;))
(Да, я сам системщик, и я тут жуткий предатель своего клана.)
Где как. Я регулярно встречаюсь с необходимостью именно такого.
> Уже можно спокойно обойтись конструкциями типа array.foreach() или for (v: array).
Ага, только потом начинается for v: slice(array, sub_begin, sub_length) или ещё что посложнее. И вот тут все эти индексы всплывают снова.
Вы не переделаете естественные языки и мышление так, чтобы счёт везде (не в компьютере) начинался с 0.А зачем переделывать естественные языки? Достаточно переделать профессиональный. Де-факто это уже произошло.
Нужно такое системщикам — пусть рисуют;))Извините, но «системщики» сделали C — для себя. Как им было удобнее. А если кто-то решил его использовать для чего-то ещё — ну так это его выбор, никто ж не заставляет.
Де-факто это произойдёт, когда возникнет новый набор порядковых числительных. Пока же приходится оперировать громоздкими конструкциями типа «второй при счёте с нуля».
> Извините, но «системщики» сделали C — для себя. Как им было удобнее.
Ну вот и создают альтернативы с другими подходами.
нулевого года нет вообще, что сильно мешает делать правильные рассчёты
Я не знаю, что вам мешает делать правильные расчёты, но нулевой год есть (спросите любого астронома), его ещё называют "первый год до нашей эры". (А ещё есть нулевой год до нашей эры — он же первый год нашей эры.)
Ни разу не видел такого понимания такой записи в математике. Можете привести какой-то авторитетный источник?
Зато пробел тут является как раз историческим явлением и остался в таких записях, как «sin x» вместо «sin(x)» — раньше всё так писали. А сейчас пробел в этой роли (а не скобки) — принципиальный синтаксический элемент математизированных языков вроде Haskell.
Скобки скобкам рознь. В обычной математческой нотации пробелы вокруг скобок не ставятся. То же самое и в программировании:
(a + b) * sin(c)
— правильно
(a + b)*sin(c)
— неправильно
(a + b) * sin (c)
— неправильно
Количество пробелов это вопрос только привычки, удобства, скорости распознования.
Сам использую нотацию ( a + b ) * sin ( c ) (да пробелов не жалею)
В обоих случаях это возможно, в обоих случаях результат — так себе.
Если вы хотите просто доехать из точки A в точку B (чёрт, опять математика, да?), то без знания того, как работает двигатель вам можно и обойтись, а если хотите принять участие в ралли Даккар — то нужно будет не просто понять это «в общих чертах», но и научиться его регулировать «в поле».
Если вы хотите написать программу, которая вам три числа сложит (хотя зачем вам числа складывать, раз математику вы не знаете?) — то без знания математики вам можно и обойтись, а если программа что-то делает с нетривиальными объёмами данных — то уже нет.
без знания математики вам можно и обойтись, а если программа что-то делает с нетривиальными объёмами данных — то уже нет.
А примеры можно привести? Одно дело спортивное программирование for fun, а другое дело повседневная разработка.
А примеры можно привести? Одно дело спортивное программирование for fun, а другое дело повседневная разработка.Пресловутого Шлемиэля можно вкрутить куда угодно, если не думать. Я как-то работал с программой создания DVD — и видя, что у неё на создания двуслойного DVD уходит час (при том, что однослойный создаётся за 15 мин) я очень хорошо понимал, что её создал кто-то, кто разбирался в видео, но решил, что для програмирования — математика не нужна. Я даже мог бы, примерно, объяснить как написать тот цикл, который автор запрограммировал непаравильно — но, увы, исходников от программы не было…
А как вы собрались «оптимизировать код» без математики — для меня полная загадка. Переписывать на ассемблер? Или на GPU перевести?
Что вы будете делать, если вы понятия не имеете — как время вашей программы будет себя вести при переходе от DVD-5 к DVD-9 и далее к разрым стогигабайтным Blu-Ray'ам? И точно ли то, что вы сделаете что-то ускорит.
Тот факт, что создание качественных, быстрых и надёжных программ себя не окупает — да, таки имеет место быть. Иначе бе пресловутый Slack уже давно обанкротился бы.
Но, тем не менее, подход «а теперь для решения задачи, которую когда-то мы решали на C64 — купите пожалуйста рабочую станцию со 128GB оперативки и RAID SSD» работает не всегда. Иногда (к сожалению достаточно редко) заказчики всё-таки задают вопросы на тему «а почему ваше поделие жрёт столько ресурсов и нельзя ли с этим что-нибудь сделать?»…
Аррррр, пробелы перед скобками, аж душа радуется.
А не слишком ли вы эмоционально относитесь к оформлению кода? В разных проектах — разные требования к расстановке пробелов и прочему оформлению. Если вы так переживаете из-за пробелов, что с вами будет, когда вы прочитаете в coding style guide'е, скажем, про расстановку фигурных скобок? :)
Кстати давно меня интересует, да все как-то речь не заходила, почему в 95% случаев перед скобками никто не ставит пробелов?
У вас тут две закавыки:
1. 95% вы, очевидно, взяли из собственного опыта. Потому что у меня, например, опыт обратный: 95% кода, в который я смотрю каждый день, написан именно с пробелом перед открывающей скобкой.
2. Цель пробелов (и вообще whitespace'ов) в коде — облегчить понимание кода для человека. Пробелами визуально отделяют значимые части кода. Но делать это можно разными способами: до открывающей скобки или внутри скобок:
— if (a) или
— if( a ).
Лично мне более приятен второй вариант, но пишу я все равно так, как сказано в гайдах.
И кстати, с появлением редакторов с подсветкой синтаксиса можно вообще пробелы не ставить — редактор сам визуально выделит ключевые места. Некоторые граждане этим злоупотребляют.
Ведь ни у кого даже и мысли не возникает не ставить их на письме, ведь что это такое?
Пфф… Вы когда последний раз в чатиках всяких были? Там сплошь и рядом пробелы ставят от балды или вообще не ставят. И ничего, массовых волнений не наблюдается.
И что самое смешное — ладно бы это всего касалось, но после операторов (неожиданно), пробелы ставятся в большинстве случаев.
Вызов функции неотделим от ее аргументов. Поэтому ставить пробел между именем функции и открывающей скобкой — значит, отделять ее визуально от ее аргументов, что не очень логично. Даже в тех конторах, где пробел перед открывающей скобкой прописан в гайдах, пробел между именем функции и ее аргументами обычно не ставится (субъективное утверждение, основанное на индивидуальном опыте).
Операторы же — отдельная песня, их нужно визуально выделять. Они, как правило, коротки (if, for, do, while), и без отбивки пробелами могут потеряться в тексте. Поэтому их и выделяют.
Есть ли какое-либо объяснение этому кроме как что это бездумное употребление каких-то пережитков прошлого?
Оформление кода должно помогать человеку правильно воспринять текст программы. А поскольку восприятие у людей неоднозначное и субъективное, постольку и единых правил оформления кода не существует. Попытки унифицировать оформление были неоднократно (см. питон), но вывести единый и универсально-понятный стиль пока никому не удалось.
Ну вообще мне довелось столкнуться с местом, где применялся откровенно дурной стиль просто потому, что главному начальнику так хотелось. Там ещё и другие проблемы были — категорический запрет на описание происходящего в стиле doxygen, настаивание на негрепабельных именах типа a, b, e, и так далее, запрет на осмысленные комментарии в CVS…
так что местные законы стиля до какой-то меры терпимы, но выше неё — нет, лучше не связываться с такими.
Но порог у каждого свой.
> Потому что у меня, например, опыт обратный: 95% кода, в который я смотрю каждый день, написан именно с пробелом перед открывающей скобкой.
Это проприетарный код или открытый?
> Цель пробелов (и вообще whitespace'ов) в коде — облегчить понимание кода для человека.
Или, надо таки упомянуть, однозначность парсинга — например, в C последовательность
a/*b
требует пробела, несмотря на все задумки программиста. Или vector<vector<int>>
до C++11. Но в последнем случае вообще диверсией было изначально использовать <> для этой цели (и нам с её последствиями жить ещё лет 50).> Попытки унифицировать оформление были неоднократно (см. питон), но вывести единый и универсально-понятный стиль пока никому не удалось.
Питон не самый показательный (на самом деле обычно код на нём следует PEP8 чуть менее, чем везде). Вот `go fmt` тут ближе. Но, честно говоря, их выбранный стиль не сильно паршив :)
Местами они рекомендуются — например, в классическом стиле GNU будет именно так:
copyStream (readStream (inputStream));
ещё долго писал с пробелами внутри, когда-то больше всего нравилось:
copyStream( readStream( inputStream ) ); sin( x + y * ( c - 1 ) );
но в итоге вернулся к стандартному, просто задолбало стучать клавишей пробела :)) он таки оказался оптимальным для чтения и написания.
А ваш сарказм таки неуместен.
> после операторов (неожиданно), пробелы ставятся в большинстве случаев
А это отдельная тема. Если обратите внимание на новые языки (Go, Swift...), там скобки вокруг вложенных тел обязательны (даже при одном операторе в них), а вокруг условий в if, while — нет, то есть
if a + b > c { run(); }
к первому есть очень серьёзные причины (задолбались отлаживать, и грамматика проще), ну а второе само из этого получается.
просто задолбало стучать клавишей пробелаКогда можно ожидать что Вы задолбаетесь «стучать клавишей пробела» в обычной переписке, где пробелов больше в разы?)
А ваш сарказм таки неуместенПеречитал свои комменты, но так и не смог понять где там сарказм, вроде совершенно серьезно пишу. Наверное оттого и минусы — что-то домыслили, чьи-то чувства заделись, и пошло-поехало. Но минусовать уже пошли даже тех, кто доказывает что это все пошло из математики, видать народ уже сам запутался. Приехали(
Ну вот пассажи типа такого
>> Лень пробел нажать, или на перфокарты запись идет и места нет? Давайте тогда и между словами пробелы не ставить, это же пустая трата времени)
или даже последнего
> Когда можно ожидать что Вы задолбаетесь «стучать клавишей пробела» в обычной переписке, где пробелов больше в разы?)
Может, филологи это как-то иначе бы назвали, но мне что-то не приходит на ум.
И я не минусовал (нет прав, но даже если бы были, за это бы минус не ставил).
По сути:
> Когда можно ожидать что Вы задолбаетесь «стучать клавишей пробела» в обычной переписке, где пробелов больше в разы?)
Никогда, наверно — там они таки функциональны. А вот внутри скобок — нет, и перед скобкой — как-то тоже (просто эстетически сравнил подходы — не увидел преимущества у пробела между именем функции и скобкой).
Нормально ошибка ловится взглядом, но для этого, наверное, надо не знать стандартную библиотеку С или успеть за 20 лет её забыть.
Взгляд споткнулся как раз о isspace(c) && ('\n' != c)
. Про isspace прочитать ещё не успел, исходил из названия и персонального здравого смысла. Если символ пробельный (собственно пробел или, в крайнем случае, табуляция), то он не может быть одновременно переводом строки. Соответственно, объединение по И выглядит подозрительно. Я предположил, что, возможно, имелось в виду ИЛИ; а даже если нет, то тут в любом случае какая-то фигня.
В условии содержится логическая ошибка. На примере "пробела" она очевидна. Код уже неправильный, и рассматривать его поведение дальше на других наборах данных просто нет смысла. Сначала надо исправить.
Я не заметил бы ошибку, если бы функция назвалась iswhitespace. Но она называется так, как называется. ((c)==' ' || (c) == '\t')
— примерно так я и представлял себе её реализацию. Авторы MC тоже.
Об этом и говорю. Чтобы видеть ошибку (не важно, кто в ней виноват), надо забыть или не знать стандартную библиотеку С, в которой сэкономили на слове white внутри isspace.
iswhitespace
эта функция называться никак не могла. Предположить же, что пропуск пробельных символов — это что-то новое, оригинальное, порождение 90х — это нужно иметь очень больное воображение.Если символ пробельный (собственно пробел или, в крайнем случае, табуляция), то он не может быть одновременно переводом строкиПеревод строки считается пробельным символом. Именно поэтому добавили исключение.
// C99
extern inline int my_isspace(int ch) {
return (ch == ' ') || (ch == '\t');
}
Так бы и компилятор пожаловался, если бы встретил название из стандартной библиотеки.
Не скажу конкретно про этот случай, но tidy казалось бы тоже умеет в такой ворнинг. Я не к тому, что вы не молодцы. А к тому, что показывать такие вещи нужно всегда в разрезе конкурентов, т.к. статические анализаторы для C/C++ в текущем временном отрезке доступны в ассортименте, и имеются бесплатные аналоги.
Гораздо интереснее было бы сравнивать diff на не false possitive с основными соревнующимися товарищами. Как минимум с clang-tidy.
Я зарёкся делать сравнения :). Чем тщательнее мы их делали, тем больше нас обвиняли в… как бы это помягче сказать то… В предвзятости и неадекватности сравнений! Можно конечно кому-то заплатить, чтобы он написал независимую статью. Но только тогда скажут, что она проплаченная :).
Предлагаю написать такую заметку. Вам или любому желающему. Я серьезно буду рад и благодарен. Только просьба не повторять подобные недоработки при сравнении. Или такие :).
Про Clang могу только сказать, что каждый раз проверяя код компилятора, мы находим там ошибки (1, 2, 3).
Что ещё… Cppcheck? Он вообще не работает :). Недавно хотели добавить его в ночные прогоны, чтобы и он помимо других инструментов, код нашего анализировал проверял. Он просто не парсит множество файлов (мы пишем на современном C++). Пришлось выбросить.
Про Clang могу только сказать, что каждый раз проверяя код компилятора, мы находим там ошибкину теперь вы просто обязаны написать статью об ошибках в своём коде
Q: Проверяете ли вы код PVS-Studio при помощи PVS-Studio?
A: Конечно! Более того, в случае обнаружения ошибок, список виновных предаётся огласке с их последующим отлучением от холодильника с мороженым.
habr.com/ru/company/pvs-studio/blog/431086
Всё уже отвечено до нас.
Всё уже отвечено до насно я не задавал вопросов!
И авторы нас активно убеждают (я склонен им здесь поверить), что регулярное использование статического анализатора не оставляет ошибкам, которые он отлавливает, возможности добраться до момента, когда они накопятся на статью.
И авторы нас активно убеждают (я склонен им здесь поверить), что регулярное использование статического анализатора не оставляет ошибкам, которые он отлавливает, возможности добраться до момента, когда они накопятся на статью.Совершенно верно. Но однажды был случай, когда по недосмотру часть кода не проверялась. Результатом стала вот эта заметка :). Проверяем исходный код плагина PVS-Studio с помощью PVS-Studio.
- Имя макроса совпадает с идентификатором стандартной библиотеки
- Имя макроса совпадает с любым уже имеющимся идентификатором
- Вместо макроса рекомендуется использовать inlinе функции и константы (вроде, в современном C они уже появились?)
P. S. Я не из мира С, так что сильно не критикуйте, если что-то не в кассу.
Для тех, кто хочет поиграть в детектива: найди ошибку в функции из Midnight Commander