Pull to refresh

Comments 140

Если в массиве нет элементов, результат выражения равен 0xFFFFFFFFu.


У меня тоже происходит FFFFFFFFFu, когда компилится некоторый код и g++ орёт:
«предупреждение: comparison between signed and unsigned integer expressions [-Wsign-compare]»

Это зло, ребята. Обращаюсь ко всем плюсовикам: «Правьте такой код сразу же, чтобы сэкономить время и нервы клиентам и сотрудникам.»
Наболело…
Не могу удержаться, спрошу: вы сообщили об этом разработчику? а когда будет версия под линукс? а почему так дорого?
если это ирония, то не все поняли)
Повышаем градус долбанутости: когда можно будет купить через Steam?
тогда уж предлагаю на хамблбамбл выйти.
Да, я как-то о такой возможности не подумал. ^_^
А на чём Вы под Android'ом пишете? Хороший редактор для C++ посоветуйте, а то я что-то ничего не нашёл.
особенно меня радует, когда предупреждение компилятора на
if (a=5) {… }
фиксят через
if ((a=5)) {… }

А там надо было ==…
Когда так фиксят — это клиника :)

А вот подобные опечатки сам постоянно допускаю. Особенно, когда часто переключаешься между C++ кодом и PL/SQL, отлаживая проект.
Поэтому не могу писать код вообще, если маячит хоть один варнинг.
чтобы не делать таких опечаток, нужно взять за правило менять переменную и константу местами 5 == a
Не всегда там a==5 или 5==а. Есть выражения чуть сложнее:
if ((i!=j)&&(settingsModel->item(i,0)->text()==settingsModel->item(j,0)->text()))
Это же Qt код, если я не ошибаюсь. А вот такой случай, когда «проблема» в Qt, т.к данный хранятся в QVariant и метод имеет сигнатуру text(): QString, а не text(): const QString / text(): const QString &, что позволило бы отловить случаи присваивания вместо сравнения.

Но если пишешь код сам, то лучше возвращать const объекты / ccылки. Это ещё и возвращаемых значение из операторов + / — / * касается, Скотт Майерс плохого не посоветует.

С++ ошибок не прощает, он беспощаден.
Да, Qt.
Код достался по наследству, требует громадного рефакторинга, который, разумеется, одному не потянуть.
>> лучше возвращать const объекты / ccылки

Лучше не надо. Это сломает move optimization в C++11.
Но точно не сломает RVO (Return Value Optimization), что не уступает move-semantic'е по эффективности.
Область применимости RVO намного уже. Например, если вы напишете что-то вроде vec.push_back(foo()), и foo возвращает const-объект, то как минимум одна копия вам гарантирована. А без const это будет move.
Нет ничего хуже таких выражений в незнакомом коде. В чем проблема добавить пару булевых переменных и сделать его более осмысленным. Например вместо
if (x!=j && is_action_avaible(x, y) && action_type != prev_action_type)

const bool is_field_free = x!=j;
const bool is_current_action_valid = is_action_avaible(x, y);
const bool is_this_new_action = action_type != prev_action_type;
if (is_field_free && is_current_action_valid && is_this_new_action) {
}

Такой код будет доступнее для понимания, более приближен к человеческому языку и в перспективе лишен таких вот ошибок.
Это ещё цветочки, там весь метод на пять строк, так что проблем с пониманием не возникает. Но есть такие мозгодробильные методы, на пять экранов вот таких строк:
Скрытый текст
dbfFile.PutField(dbfFile.GetFieldNo(dbfRecord[count].FieldName), QString::number(round(i_map.value().at(cl).at(count).toDouble()*d_prec)/d_prec,'g',8).toLocal8Bit().data() );

(это одна строка, если что)
Человек писал явно в аврале, не думая о наследниках.
Тем более я не программист, и в C/C++ чистый самоучка. Но больше некому тащить проект.
Человек писал явно в аврале, не думая о наследниках.

Больше похоже на строчку из черновой версии кода — когда его нужно написать, не теряя контекста, чтобы не забыть, что откуда берётся и что когда надо сделать. В этом случае просто не успеваешь вспомнить, как называется функция, выполняющая
QString::number(round(someNumber*d_prec)/d_prec,'g',8).toLocal8Bit().data()

(или какой там фрагмент является часто используемым), и быстрее написать её сразу по коду — тем более, что она делает — понятно с первого взгляда. Потому что поиск или выделение метода — серьёзное переключение контекста. Причёсывание кода, как всегда, оставляем на «после того, как заработает», но тогда, к сожалению, возникают другие задачи, которые нужно сделать вчера.
В аврале такая ситуация возникает с большей вероятностью, но и при рутинной работе она не удивительна.
Да понятно, но от этого не легче.
В конкретном случае этот один громадный метод, на 650 таких вот строк, с циклами и условиями 5-7 уровней вложенности. Простыня, уезжающая за правый край экрана. Но можно же было его разбить на более мелкие части? Тем более есть куски (и довольно много) повторяющегося кода, вынеси которые, ещё пополам можно сократить.
Часто такие условия накапливаются постепенно и перестаешь замечать, что оно становится нечитаемым, если хоть ненадолго выйти из контекста.

Ну и есть противники такого подхода, считающие, что это напрасное выделение памяти и тактов процессора.
Компилятор с этим справится, так что напрасно ничего не выделяется.
Я сейчас не про конкретный язык, а вообще про принцип. А так не каждый компилятор справится, да и не для каждого языка есть компилятор.
Обычно в тех языках, в которых компиляторы не справляются с оптимизацией подобного кода — и уж тем более в таких, где компилятора нет — базовый уровень производительности настолько ниже, что микрооптимизации вроде инлайнинга переменных никакого значения иметь не будут. А там, где считают каждый такт — т.е. C и C++ — это свернет в изначальное выражение любой компилятор, выпущенный в последние 15 лет.
Тем не менее, те кто так считает формально правы — потребление ресурсов увеличивает. А на довод «микрооптимизации вроде инлайнинга переменных никакого значения иметь не будут» возражают в стиле «копейка рубль бережет» и тоже сложно поспорить.
Потребление ресурсов в случае использования вменяемого оптимизирующего компилятора это не увеличивает ни на грамм (если только вы не о времени компиляции, но и там это пренебрежимо малая величина).

А с «копейка рубль бережет» спорить очень легко в том случае, если выбор языка изначально предполагает сорение «деньгами» просто в силу дизайна реализации (например, PHP или Python) — встречный аргумент там очень простой, предложить переписать все на плюсах, т.к. экономия сразу будет куда серьезней.
На плюсах будет дольше. Собственно аргументы за невыделения сложных выражений (или даже простых типа x!=j в примере выше по треду):
— меньше жрет ресурсов
— главное, писать быстрее, хоть тупо символы считать, хоть считать время затраченное на придумывание имен
Писать быстрее только в режиме write-only. Если потом этот код переписывать, или даже дебажить, то все эти попытки сэкономить десяток символов отольются во много зря потраченного времени.
Как раз превратить x!=j в is_field_free может быть полезно. А вот два остальных условия ничего к читабельности не прибавляют, в именах переменных там написано то же, что и в самих выражениях.
Не сказал бы, что то же самое.
Спорить очень легко. Нечитаемый код => ошибки => копейки/рубли/десятки(миллионов) рублей в пусконаладке, эксплуатации, сопровождении и развитии. А закон Мура пока никто не отменял.
чтобы не делать таких опечаток, нужно взять за правило менять переменную и константу местами 5 == a

Я считаю такую практику спорной. Читаемость ухуджается, а смысла мало. Если уж берёшь на себя труд совершать какие-то дополнительные манипуляции, то лучше «взять за правило» перепроверять за собой (и другими при review) каждое условие с оператором равенства.
Поэтому просто приучитесь всегда вне зависимости от языка программирования писать if(5==a) — константа СЛЕВА.
У меня у одного после прочтения статьи остаётся вопрос: «кто же такие эти мистические заземлённые указатели?»?) А то заинтриговали же…
Я думаю легко догадаться, что имеется в виду. Как я понимаю, имеются в виду объявление указателей, которые сразу обнулены (на всякий случай): float * f = NULL;
UFO just landed and posted this here
Мне кажется, это очень опасно. Вместо падения будет неочевидное неадекватное поведение.
UFO just landed and posted this here
В принципе, как я понимаю, «заземлять» можно не только указатели. Вот заземлённый int:
int A = 0;
:-)
Думаю, в случае указателей аналогия уместнее, так как указатели могут содержать в себе опасность :)
Нет. Заземлённые — это только там где «NULL». NULL созвучно с Зануление. А Зануление это почти Заземление (в электрике).
UFO just landed and posted this here
Если объявление с инициализацией сильно разнесены друг от друга и такие моменты в коде постоянно, то вероятность в следующий раз объявить переменную, но забыть её проинициализировать, сильно повышается.
UFO just landed and posted this here
Лучше инициализировать непосредственно перед использованием, чем рассчитывать, что а) переменная была проинициализирована когда-то раньше и б) её значение не изменилось.
UFO just landed and posted this here
А где невозможно — инициализировать непосредственно перед первым использованием.
прокатывает константами с только, что жалко
Может, всё-таки стоит читать предупреждения компилятора? Никогда не использовал Yoda conditions, т.к. не вижу смысла городить уродливый костыль для решения проблемы, которая обнаруживается ещё до запуска приложения штатным инструментом разработчика. Читается неестественно — «если пять равно a...», работает только с константами. Напоминает танец для вызова дождя, а не серьёзное решение.

Вопрос вначале скорее к Singerofthefall.
1 ) Этому приему более 10 лет. Вы уверены что все компиляторы подо все платформы лет этак 10-15 назад выдавали варнинги?

2) Помимо C/C++ есть еще куча языков с аналогичными граблями. Yoda conditions работает везде.

3) Это всего навсего привычка которая реально помогает жить. Хуже точно не будет.

4) То что это «уродливо» всего лишь ваше субъективное мнение, на качество кода и его стабильность негативно не влияет.

Поймите правильно старого программиста. Если вас спросить цвета радуги 99% вы на автомате вспомните «каждый охотник...» Точно так-же я когда пишу код не задумываясь ставлю константу слева…
Хуже точно не будет.

Главный для меня аргумент.
Помимо C/C++ есть еще куча языков с аналогичными граблями. Yoda conditions работает везде.
Для Java, при сравнении строк, это практически «стандартная хитрость»: вместо
if( aa != null &&  aa.equals("qwerty")) {...} 
писать
if( "qwerty".equals(aa)) {...}

Не знал, что это так называется…
Грабли не аналогичные, но название тоже подходит, да
Чего только люди не придумают, чтобы не добавлять в язык перегрузку операторов…
Ну, так сейчас — не 10-15 лет назад. Уже можно пользоваться современными компиляторами, я гарантирую это. Про качество кода можно даже не говорить после того, как для вас это стало субъективным мнением.
Если вас спросить цвета радуги 99% вы на автомате вспомните «каждый охотник...»

Нет, я сразу вспоминаю на автомате «красный оранжевый жёлтый зелёный голубой синий фиолетовый». И сразу пишу "==" в условиях, если только не сделал сознательное решение сделать/оставить в нём присваивание (что, кстати говоря, считаю плохим стилем). Если вижу "=" в условии в чужом коде, воспринмаю как красную тряпку, уделяю особое внимание. Это эффективнее.
А почему вы решили, что я использую Yoda conditions — только потому что я про них вспомнил? Я вообще работаю со включенным treat warnings as errors (ну, в моем случае это QMAKE_CXXFLAGS += -Werror, но суть одна).
Такое ощущение, что в конторе даже с языком знакомы понаслышке, а о стандарте вообще не знают. :-)
Боюсь, Вы не так далеки от истины. Забыл написать ещё про одно полезных дело, который сделал этот человек. Уговорил руководство закупить для отдела разных книг по Си++.
Теперь ему еще останется уговорить эти книги прочитать…
И дома тоже?

Как же они живут без однокласников и вконтактов (опционально фейсбуков, твиттеров, линкединов и т.п.)!!! ))))
UFO just landed and posted this here
печально. cppcheck мы вкидываем на билд-машину вместе с плагином для jenkins'а. на выходе имеем актуальную информацию после каждого коммита. -Wall объявлен обязательным флагом и за игнор ворнингов бьем по рукам
>-Wall объявлен обязательным флагом и за игнор ворнингов бьем по рукам

Только -Wall -Wextra -Werror, только хардкор! %)
$ gcc -Wall -Wextra -Werror -std=c99   -pedantic
$ gcc -Wall -Wextra -Werror -std=gnu99 -pedantic
$ gcc -Wall -Wextra -Werror -std=c89   -pedantic
$ gcc -Wall -Wextra -Werror -std=gnu89 -pedantic

UFO just landed and posted this here
Столько пунктов…
А между тем, все можно существенно упростить, если всегда в опции компилятора добавлять -Wall -Werror
УМВР.
// кстати, конструкции вида if((a = b)){...} сам часто использую. Это удобнее, чем писать a = b; if(a){...}
Если аналогичную вещь сделать в Visual C++, то перестает компилироватьca любой проект, включающий в себя заголовки Microsoft SDK, которые нужны для использования Windows API.
Надо понимать, что /Wall в VC++ включает в себя т.н. «informational warnings», которые не предполагают наличия проблемы. Например, там выдаются варнинги о том, что в структуру добавлен padding. Настоящий аналог gcc -Wall в VC++ — это /W4. С ним все стандартные заголовочные файлы, в т.ч. WinSDK, компилируются молча.
MSDN говорит следующее:
Level 4 displays all level 3 warnings and informational warnings.
т.е. уровень 4 объединяет в себя «informational warnings». Выключены по умолчанию предупреждения самых разных уровней, например, C4906 имеет уровень 1, выключено по умолчанию и очень даже предполагает наличие неопределенного поведения.
Сам по себе каст строкового литерала к char* неопределенного поведения не предполагает. Оно возникнет только в том случае, если вы попытаетесь потом через этот неконстантный указатель литерал поменять.

В целом, да, я был несколько некорректен. Но суть та же — /Wall включает в себя большое количество варнингов, которые таковыми по сути не являются, и на практике собирать с ним смысла не имеет — базовым должен являться /W4. А если там чего-то не хватает, то это уже надо включать выборочно.
Боюсь, это лишь теория. Поднимите руку те, у кого на хотя бы среднем проекте -Wall? Средний — это от мегабайта исходников.
В том проекте, который сейчас использую (OpenFOAM): исходников ~ 60 МБ, флаги
-Wall -Wextra -Wno-unused-parameter -Wold-style-cast -Wnon-virtual-dtor -O3
При компиляции вылезает ещё несколько предупреждений на неиспользуемые переменные, и вроде всё.
Я не автор, я только пишу дополнения для своих целей. Так что уважение направляется авторам. Но там в коде другие особенности: например, широкое использование #include для кусков кода, своя самописная система сборки…
Строго и правильно всё, кроме -O3. Я бы побоялся в продакшн включать экспериментальные оптимизации gcc…
Респект! У меня тоже непереносимость варнингов, я еще и -Werror включаю, чтобы не пропустить ненароком. Однажды в релизном билде забыл его убрать, и было весело, когда ворнинг вылез из Qt-шного хедера, и проект перестал собираться на некоторых платформах :)
В своих проектах стараюсь всегда собирать с флагами:

-Werror -Wall -Wextra -pedantic -Weffc++ -Wconversion -Wsign-conversion -Wold-style-cast -Wunreachable-code -Woverloaded-virtual -Wctor-dtor-privacy -Wnon-virtual-dtor -Wenum-compare
Если речь про gcc то -Wunreachable-code удалили вроде пару лет назад и по-моему он тупо игнориться сейчас.

-Weffc++ полезно иногда включать, но в больших проектах ни у кого не хватает духу его оставить — задалбывают параноидальные ворнинги про необходимую инициализацию всего в конструкторе. Там сейчас собственно есть предложение разделить Weffc++ на несколько отдельных частей, надеюсь к 5-му gcc разделят :).

Ещё кстати -Wshadow полезен.

Есть ещё много флажков но они не одинаково полезны для всех случаев.
"-Wall -Wextra" и порядка 8Мб своих исходников на С++. К сожалению, из-за использования некоторых сторонних библиотек и древних компиляторов (включая gcc 4.1.2), которые выдают некоторые предупреждения, которые реально ложные срабатывания флаг -Werror не используется. Однако, все предупреждения тщательно анализируются и либо игнорируются с соответствующей записью куда следует, либо исправляются, а от древних gcc я очень надеюсь избавиться в ближайшее время ибо у следующего нужного компилятора gcc 4.3 с ложными срабатываниями все куда лучше (лично не встречал).
Visual Studio подойдет? Там не везде /W4, но в очень многих плюсовых модулях таки да.
Да даже на больших: достаточно вводить его постепенно, по модулям.

Скажем Chromium — там делоко не один мегабайт исходников, но большая часть модулей компилируется именно в таком режиме.

Собственно единственная отговорка была до GCC 4.6, когда не было "#pragma GCC diagnostic push"/"#pragma GCC diagnostic pop" (которые необходимы для постепенного введения -Wall -Werror в проекте где в header'ах много… добра).
Если в проекте с самого начала используется этот флаг — то не проблема. А вот потом вводить — проблема.
Чтобы убедиться в том, что в непрофильных компаниях в отделе программирования болото, достаточно взглянуть на то, что производители различной и порой даже хорошей техники поставляют в виде прилагающегося софта. Из того, с чем приходилось сталкиваться: Никон, Кенон, Моторола, Нокия, НР… Так что увы :(
Кстати, да. И это вообще очень стыдно, так как эти приложения — не мат. моделирование, в котором действительно важнее всего результат. Они — пользовательские. И жуткий глючный интерфейс в сочетании с общей нелогичностью и убогостью совсем не вяжется с отличным дизайном телефона или фотоаппарата.
Никон, Кенон, Моторола, Нокия, НР
SONY!!!!1
Но всё равно, тенденция заболачивания четко прослеживается. Я не знаю, отчего так происходит, но это так.


Имею кое-что сказать по этой теме исходя из личного опыта. Будучи профессиональным программистом, по образованию я — потомственный физик. Так уж вышло, что в тот момент, когда я выбирал ВУЗ, голос крови оказался сильнее, чем вера в светлое будущее IT. И я поступил в достаточно престижную по местным меркам физическую высшую школу, которая, по сути, является «детским садиком» при крупном НИИ в родном городе Нижнем Новгороде. Люди, знающие тему, узнают и НИИ, и название школы.

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

1. Физики рассматривают компьютер как большой многофункциональный калькулятор, позволяющий построить график зависимости Эта от Тэта при Гамма стремящемся в бесконечность. Причем, очевидным образом, для них цель — график, а вовсе не та программа, которая его рисует.
2. Как следствие из этого факта, программист — это не профессия. Программист — это просто тот человек, который умеет пользоваться Большим Калькулятором, чтобы построить означенный график. Каким способом график будет построен, не имеет значения. Совсем. Как-как вы сказали? Статический анализ? Контроль версий? Окститесь, родные! C++ — язык для программистов. Физики пишут на Фортране!
3. Как следствие из предыдущего пункта, человек, стремящийся посвятить свою жизнь написанию программ физ. моделирования, даже универсальных, даже очень и очень крутых — не более, чем приложение к калькулятору. Он и не человек вовсе, а так… И это, кстати, распространялось не только на меня (куда уж мне, убогому), а даже и на лучшего численника-расчётчика в НИИ, который преподавал у нас численные методы и который, когда я пришел к нему делать курсовую, сказал мне почти открытым текстом: «Вас будут презирать, приготовьтесь терпеть.»

Терпеть мне не захотелось и я после окончания ушел из моделирования в области, где программистов не считают людьми второго сорта. Надеюсь, этот пример объясняет, почему инициативы типа ввода статического анализа даже на сравнительно крупных (до 20-30 человек) проектах по мат. моделированию — гиблое дело. Там просто может не найтись человека, который знает, что это такое. А если такой человек и найдётся, его, скорее всего затопчут, потому что нафиг не нужны эти новомодные программерские прибамбасы. Сто лет без них жили — и дальше проживём.

И тем, кто не заскучал, второй пример. Мой отец, находясь в пенсионном возрасте, тем не менее работает в очень крупном оборонно-инженерном предприятии, здесь же, в Нижнем (самом крупном в городе и одном из крупнейших в стране — те, кто в теме опять же угадают ;) ). Он всю жизнь программировал на Фортране. Начинал еще с перфокарт. Я не виню его за то, что не учит C++. Ему это уже 10 лет назад было поздно — он еще неплохо держится. Но на предприятии, где 2/3 сотрудников что-то как-то программируют, приняты следующие меры безопасности:

1. Никакого интернета. Совсем. Нужна литература — иди в местную библиотеку. Stack Overflow? А что это? Даже если ты хочешь отправить письмо электронной почтой, ты должен написать заявление начальнику, где ты объяснишь, кому это письмо и для чего. Интернет «под расписку» есть только у избранных. Слава богу хоть внутренняя сеть есть.

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

3. (не относится к делу, просто иллюстрация) Нельзя даже пронести телефон с камерой (а где вы теперь видели другие)?

В результате даже молодняк пишет на Фортране, причем реально грамотных в программировании — единицы. Знаю, потому что подтягивал по программированию одного парня лет 25, который был мне отцом зарекомендован как многообещающий.

Мой вердикт: там 80-е годы. Даже при том, что там неплохо платят, я не пойду туда ни за какие каврижки.

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

Просто люди имеют свойство быть очень консервативными в областях, не являющихся их основным «коньком».
Как-как вы сказали? Статический анализ? Контроль версий? Окститесь, родные! C++ — язык для программистов. Физики пишут на Фортране!
Особенно печально, что при таком восприятии контроль версий каким-то непостижимым образом оказывается связан с C++, который «для программистов». Вот в Википедии у каждой статьи есть история — по сути, тот же контроль версий. Видимо, Википедия тоже «для программистов».
Для этих людей (особенно для старшего поколения «за 40», которое руководит) принцип работы Википедии — еще большая магия, чем для большинства веб-разработчиков устройство двигателя подлодки или ядерного реактора. И это не грустно и не радостно. Это — просто разделение обязанностей.

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

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

Разумеется, большинство из них, являясь очень интеллигентными людьми, даже не отдают себе отчёта в факте своего презрения. Сознательно они будут вам говорить, что программирование — очень важная и сложная наука.
Статический анализ? Контроль версий? Окститесь, родные! C++ — язык для программистов. Физики пишут на Фортране!
В результате даже молодняк пишет на Фортране
Никакого ООП в проекте под миллион строк кода, никакого статического анализа.

Почему-то мне кажется, что вы во власти каких-то стереотипов находитесь, слово FORTRAN для вас как красная тряпка. А ведь поддержка ООП появилась в FORTRAN больше 20 лет назад (стандарт FORTRAN 90) и с тех пор не раз улучшалась. Инструменты контроля версий были даже в «русифицированных» клонах Unix на «русифицированных» клонах (ЕС, СМ и т. п.) «серьезных» компьютеров типа PDP-11 (и в начале 90-х нас заставляли ими пользоваться на лабах по FORTRAN 77 на СМ-1420), и современные никто не запрещает использовать. Инструменты статического анализа для FORTRAN тоже существуют, хотя бы предупреждения компилятора.

Описанные вами проблемы не в языке, а в мышлении. Люди осваивают минимально необходимый набор знаний и больше ничего изучать и использовать для «управления большим калькулятором» не хотят.
Аллергия, да :) Не совсем беспочвенная, на мой взгляд (знаю эту конкретную ситуацию изнутри, привет, bigfatbrowncat! ;) )

Что касается болота и мышления… как говорится, что посеешь — то и пожрёшь пожнёшь, в основном там работают «старые кадры» с уже существующими наработками, а молодые и перспективные редко туда идут (не только в «крупном оборонном предприятии», но и в других НИИ, например, под эгидой Нижегородского Университета), по крайней мере на полную ставку. Соответственно и времени на обучение людей правильному написанию не остаётся, надо за минимально потраченное время добавить то-то и то-то в расчеты, а не перепахивать весь проект.
А не надо перепахивать весь проект, если есть желание ввести современную культуру разработки. Например, научить базовым командам Git, Mercurial или SVN можно за 15 минут. ООП тоже можно внедрять постепенно, как и TDD. Язык тут явно не причем. Вон в НАСА используют FORTRAN весьма активно с использованием TDD оценивая базовое введение в 1-2 дня.
Я знаю про ООП-расширения Фортрана. Приделаны они, на мой взгляд, весьма и весьма косо. Что понятно, так как когда этот язык создавался, о том, что такое ООП, никто даже не задумывался (поправьте, если я неправ).

Разумеется, дело в мышлении. Никто и не спорит. Но чтобы «постепенно перейти на ООП», надо знать, что такое рефакторинг. А эта наука, на мой взгляд, сложнее, чем понимание основ ООП. Большинство людей физики (как и я когда-то) видя, что их программа в процессе «эволюции» превратилась в летающего макаронного монстра, просто берут, выкидывают ее и пишут заново.

Да, я субъективен. Мне C++ намного намного ближе. Там хотя бы грамматика почти контекстно независимая.
Хорошо, уточню. Пишут на фортране стандарта F77, как и подобает любому продвинутому разработчику 80-х годов.
В Си/Си++ переменная по умолчанию не инициализируется нулём.


В Си++ локальная переменная по умолчанию не инициализируется нулём
Я очень стараюсь убирать все ворнинги компилятора, но довольно часто ничего не могу поделать с двумя:
statement is unreachible и pointless comparison between unsigned value and zero. И вот почему.

Я в коде (embedded) часто использую самопальный assert, который сводится к следующему
do { if(! (statement) ) { while(1); } } while(0)
так я сразу в отладчике вижу, на какой строчке остановилось выполнение. Но если этот ассерт вставлен, например, в одной из веток switch'a — компилятор ругается.

Второй ворнинг в основном вылезает из шаблонов, когда при проверке одно из шаблонных значений оказывается нулем.
А из-за чудного компилятора, который выдает ворнинг на коды в .h-файлах при КАЖДОМ ВКЛЮЧЕНИИ этого .h-файла, вывод иногда просто весь в ворнингах.
Это меня очень огорчает, но что делать я не очень представляю. Не давить же эти ворнинги?
Вроде любой компилятор выдает ворнинги на код из хедера при каждом включении хедера. Другое дело, что если хедер системный или 3rd-party, который не поменяешь, то можно перед его инклудом поткнуть прагму, которая ворнинг давит, а после — прагму, которая возвращает настройку нотификации о ворнингах в режим «как было».
Ах, если бы все компиляторы поддерживали эти прагмы :)
Но может быть есть какой-то другой способ код писать?
А какие компиляторы их не поддерживают?

Просто интересно. GCC научился с версии 4.6, остальные распространённые компиляторы (MSVC, Clang) вроде всегда умели…
Так речь идёт же о встраиваемых системах. А там компиляторы могут очень необычными, от производителя процессора.
На самом деле, я был не прав на счет конкретно своего (keil arm compiler), просто мне было лень хорошенько погуглить.
Я вчера потратил пару часов и смонстрячил более-менее переносимое решение. По-крайней мере, сторонние хедеры я могу заключать в прагмы.

Но вот что делать со сторонними сишниками — пока не знаю.
Предупреждения, порождаемые сторонними заголовочными файлами, нужно глушить с помощью pragma warning (см., например, эту стутью). При этом для остального кода предупреждения остаются включенными. А описанный пример с while(1), насколько я понял, употребляется только для отладки. В таком случае предупреждение, наоборот, полезно, так как помогает не забыть убрать отладочный код.
Мда. За окном 2013-й год, беспилотные космические вездеходы давно уже бороздят просторы не только Большого театра, но и марсианскую поверхность. А статья, рассказывающая, как не путать сравнение и присваивание и чем чревато сравнение С-строк по указателям, выходит в топ Хабра.

Простите мне мой скепсис, но я склоняюсь к тому чтобы согласиться со Станиславским. Ибо после всех постов о мегадостижениях вашего программного продукта у меня в голове не укладывается, как кто-то, уходя от вас, стал бы устраиваться на работу в такое место. Не поверю, что люди могут дойти до такой степени отчаяния и при этом хотеть жить на этом свете. Либо вы своим работникам совсем не платите, и ради денег они готовы на самые извращённые формы рабства =).
Возможно, просто мы имеем дело с перфекционистом, который пошёл в глухой угол в надежде сделать мир лучше
В условии оператора 'if' происходит не проверка значения, а присваивание:
if (numb_numbc[i] = -1) { }

Кстати, предупреждает ли о возможности подобной ошибки анализаторы, если она встречается не в if, а в циклах? Что-то вроде
nLines = 0;
file->open();
while (str = file->readLine()) {
  nLines++;
}

Для себя так и не решил, является ли подобный код допустимым или следует его разворачивать во что-то вроде
nLines = 0;
file->open();
str = file->readLine();
while (str) {
  nLines++;
  str = file->readLine();
}

или
nLines = 0;
file->open();
for(str = file->readLine(); str; str = file->readLine()) {
  nLines++;
);

Смущает двойное повторение в коде file->readLine() при попытке избавиться от присваивания в проверке условия цикла, особенно в варианте с for, который вроде бы больше для этого подходит. Кажется, что ухудшает читаемость. Кто как думает?
Кстати, предупреждает ли о возможности подобной ошибки анализаторы, если она встречается не в if, а в циклах?

Да. Например, PVS-Studio предупреждает в некоторых случаях. Но тут надо соблюдать компромисс между нахождением ошибок и количеством ложных срабатываний. Слишком это частый приём.
Я последнее время пишу так:
nLines=0;
for(;;){
  str=file->readLine();
  if(!str) break;
  nLines++;
}

Кстати, да, лучше чем мои выглядит, хотя если переписать под обычные правила, то уже не так:
nLines=0;
for(;;){
  str=file->readLine();
  if(!str) { 
    break;
  }
  nLines++;
}

Потому что эти «обычные» правила — отстой.

nLines = 0;

while (true)
{
    str = file->readLine();

    if (str != NULL)
        ++nLines;
    else
        break;
}
Отстой или нет, но может просто коммит не пройти.
А поясните пожалуйста 21 пункт, почему если мы присваиваем переменной a новый адрес не будет никакого эффекта на значение которое хранится по данному адресу
Имелось в виду другое. Программисты путают. Они думают, что раз вот так *a = 10; можно поменять значение данных по указателю, то можно изменить и само значение указателя вне функции. Думают так они не всегда, но видимо бывает, что забываются. :)
По поводу пункта 15 можно найти такую красоту:

\Microsoft SDKs\Windows\v7.0A\Include\WinSock.h

char FAR * PASCAL FAR inet_ntoa (__in struct in_addr in);

The string returned by inet_ntoa resides in memory that is allocated by Windows Sockets. The application should not make any assumptions about the way in which the memory is allocated. The data is guaranteed to be valid until the next Windows Sockets function call within the same thread, but no longer. Therefore, the data should be copied before another Windows Sockets call is made.
Ах, WinAPI, WinAPI… Сколько счастливых ночей было проведено за выискиванием причин «Access violation at address 123455FF read at address 00000000»…
UFO just landed and posted this here
Каким боком пример 4 иллюстрирует проблему одновременного использования знакового и беззнакового типа? BufPos unsigned int, size_t скорее всего unsigned long, имеется ошибка в логике, при чем здесь знаковость?
Ошибка в голове. Люди не осознают, что смешивая int и unsigned, они получают unsigned со всеми вытекающими последствиями. Я вот тоже нередко встречал людей, которые думают что 1u — 2 < 0
Статья про notepad проскакивала в thedailywtf.
> Я не знаю, отчего так происходит, но это так. Причём, чем больше компания, тем сильнее проявляется этот эффект.

Вы глубоко заблуждаетесь. Могу вам с уверенностью сказать, что есть большие компании в которых готовы двигаться вперед,
но для этого требуется проводить тренинги по новейшим технологиям и кроме того иметь отдел R&D. А вот теперь на пальцах
пересчитай компании в которых есть R&D и как уже было сказано в статье команды, которые прибиты к какой-то отрасли просто
реально загнивают, так как сами по себе сидят на жопе ровно в своем сформированном годами штате и ничего им для счастья
не нужно (а вот на сколько хорошо это или плохо не нам судить, так как если их устраивает ZIP архив, то не надо лезть со своими
вениками мужики и без вас разберутся, а то и напишут какой-нить Zit или Zubversion)
Но ведь отдел R&D в какой-нибудь физической лаборатории должен заниматься, скорее, средствами фиксации результатов экспериментов и алгоритмами обработки этих результатов, а не системами контроля версий? То же и при АЭС — там им надо, к примеру, разрабатывать и настраивать какие-нибудь системы контроля своего оборудования и электростанции в целом. Хотя, с большей вероятностью, этот отдел будет где-нибудь при министерстве, а на станции они будут ездить в командировки.
Пункт N20 точно правильный? Просто то, что там написано противоречит логике ленивых вычислений в моём понимании. Больше похоже, что имелось в виду группировка выражений (мол "(A || (B && C))" вместо "((A || B) && C)").

Код для проверки
#include <iostream>

class C
{
public:
    C(char name, bool val)
        : name(name)
        , val(val)
    {
    }

    operator bool() const
    {
        std::cout << name << std::endl;
        return val;
    }

private:
    const char name;
    const bool val;
};

int
main(void)
{
    C a('a', false), b('b', true), c('c', true);
    if (a || b && c)
    {
    }
    return 0;
}


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

Ну и меня сильно удивил сам факт того, что никто из читателей не указал на неточность.
Ну глупость там написана, глупость. :) Бывает. Поправил.
Спасибо. Теперь я снова смогу спать спокойно :-)
Да-да. ПО от Никона. Софт по синхронизации данных для почившей уже Нокия, драйверы и ГУИ к принтерам-сканерам… А еще я однажды увидел экран диагностического софта одного из европейских автогигантов. Который стоит много-много денег. Темно-синий на черном, розовый на желтом, вырезанные в паинте логотипы… Хочу это развидеть, но никак. И можно продолжать бесконечно!
> Пункт 14 — Использование неинициализированных переменных
тут на многих компиляторах очень интересно сделано — в дебаг сборке все инициализируется. в прод — нет.
как по мне лучше бы в дебаге все инициализировалось мусором.
Sign up to leave a comment.