Untitled

НикнеймzHz (а также zHz00, zHz01 и так далее)
О чём пишубыт, аниме, программирование, компьютерная техника
(полный список тегов -- что теги обозначают)
Интересненькоесписок моих статей с разбивкой по темам
Где меня ещё читать Telegram
Как со мной связатьсяTelegram, e-mail, Jabber: [email protected],
Discord: zHz#1243
Как дать мне денегBitcoin

Что тут можно и нельзя (читать правила полностью):
1. Комментировать можно всем.
2. Читать всё можно всем.
3. Раскрывать чьи-либо личные данные нельзя.
4. Нарушать правила @дневников и законы РФ нельзя.
5. Если в записи есть ссылки "<<" или ">>" -- то эти ссылки ведут на связанные записи в цепочке.
6. Если навести мышку на зелёный текст, будет сюрприз.
URL
Записи с темой: Программирование (79)
пятница, 28 марта 2025
03:48 Всегда добавляйте default
В Си/Си++ оператор switch позволяет выполнить одно из N действий. Какое действие вызывается -- зависит от входного параметра. Я не буду показывать синтаксис, показываю только принцип:

Например, если тип измерения равен 1, то делать А.
Есть равен 2, то делать Б.
Если равен 3, то делать Ц.

Ну и есть волшебная опция default, которая срабатывает тогда, когда не срабатывают предыдущие.

Бывает, что по смыслу у вас особенным образом обрабатываются несколько значений, а для всех остальных подходит "общее". Тогда каждый дурак поставит default и напишет в нём то, что надо. Но что, если типов измерения всего три?

Велик соблазн поставить только три кейса и на этом закончить блок. Так делать не надо. Я много раз сталкивался с тем, что рано или поздно добавляется новый тип измерения, и надо перебрать все свитчи, чтобы они правильно срабатывали. Легко что-нибудь упустить. Кроме того, если значение параметра окажется ошибочным, программа пропустит свитч "молча", а последствия придётся долго анализировать, чтобы выяснить, где косяк.

Чтобы ошибка вылезала сразу, я стал принудительно добавлять во все свитчи секцию default. И в случаях, описанных выше, попадание в эту секцию как раз означает ошибочное значение параметра!

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

Такая система позволяет не только узнать, что где-то неправильно работает свитч. В сообщении сразу указывается, ГДЕ это происходит. Я не могу сосчитать, сколько раз меня спасала такая система.

@темы: Программирование, Лайфхак

URL
пятница, 14 марта 2025
05:45 Шок! Сумма меняется от перемены мест слагаемых!
Да, причину вчерашнего бага я отыскал, но в двух словах это не об'яснить. Тут надо статью писать. Может быть, как-нибудь в другой раз.

Вместо этого расскажу то, что рассказали мне о суммировании чисел. Как известно, точность в компьютере ограничена. Если мы складывает числа примерно одного порядка, то всё ок. Если же числа отличаются на десять порядков, то маленькие числа начинают теряться на фоне больших. То есть:

1e10+1 будет примерно равно 1e10.

Если использовать более точный тип (64 бита вместо 32, или даже ещё больше), то будет доступен больший разброс диапазонов, но ограничения всё равно будут.

Если мы суммируем большой массив, и числа в нём самые разнообразные, то существует риск потерять точность при суммировании из-за явления, которое я указал выше. Если маленьких чисел мало, то пёс с ним. А если у нас большинство чисел маленьких, но есть несколько больших? Потеря точности будет уже более значительной.

И вот какой тут есть совет. Массив надо отсортировать по возрастанию. Тогда в том случае, если маленьких чисел много, они при суммировании станут больше, и уже будут заметнее при сложении с большим числом. Если же суммировать в обратном порядке, то все значения после больших будут просто потеряны.

@темы: Программирование, Лайфхак

URL
пятница, 10 января 2025
05:29 Kittens Game Buildings Calculator
Я уже не раз писал про curses, но зачем вообще мне понадобилась эта библиотека? Для нетерпеливых сразу ссылка: github.com/zHz00/KGBC

Я играю в Kittens Game, там у меня цивилизация котят, у них разные фабрики-заводы-газеты-параходы, и всё это надо строить. При этом следующая постройка стоит на 15% больше предыдущей. А иногда не на 15%. Есть ещё один нюанс: некоторые ресурсы, из которых собирают постройки, имеют "ёмкость". Допустим, уран имеет ёмкость 10000. Если следующий ускоритель стоит 11000, то хоть ты тресни, ты его не построишь, потому что не сможешь накопить 11000 урана. Сначала надо поднять ёмкость урана на 1000, для чего надо построить новый реактор. Он не требует урана, но он требует титана. И стоит на 15% больше предыдущего реактора. Есть ли у меня достаточная ёмкость титана, чтобы построить следующий реактор? Вопрос.

(читать дальше)

@темы: Игры, Статьи, Программирование, Программы

URL
среда, 08 января 2025
07:41 Ещё два прикола при работе с терминалом
Вообще, это надо в пост про curses, и я туда добавлю, но сейчас там никто не прочитает.

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

Но когда я решил провести углублённое тестирование, то обнаружил ещё две вещи.

1. Tab невозможно отличить от Ctrl+i. Потому что они оба возвращают один код. (это поведение присутствует и в винде, как выяснилось)
2. Ctrl+M невозможно получить. Потому что когда нажимаешь Ctrl+M, в программе получаешь Ctrl+J. То же самое происходит и при нажатии Enter (поэтому различить Ctrl+J и Enter невозможно тоже).

В некоторых терминалах поведение отличается. Там нажатие энтера генерирует Ctrl+M. Тогда не получится сгенерировать Ctrl+J, поскольку его нажатие будет генерировать Ctrl+M. Такое поведение связано с различием управляющих кодов CR/LF. И если в настройках терминала стоит одно, то во всех трёх случаях будет генерироваться Ctrl+J, а если другое -- Ctrl+M.

Есть очень окольные способы настроить такое под себя. Но если я пишу программу для терминала, которая должна более-менее работать в любом линуксе, то надо отказаться от Ctrl+J, Ctrl+M, Ctrl+i, Tab, а ещё, желательно, от Ctrl+H, который легко путается с Backspace. Но вот именно настройка управляющего кода бэкспейса в эмуляторах терминалов всегда расположена на видном месте.

@темы: Программирование, Борьба с техникой

URL
понедельник, 23 декабря 2024
04:53 Во входном канале никель, в выходном -- пуговица
(никель -- монета в 5 центов)

Выводил текстовый файл при помощи Си++. Использовал класс ofstream. Неожиданно обнаружил, что файл прерывается досрочно. При этом цикл, который туда пишет, дорабатывает до конца. А в какой момент прерывается вывод?

В общем, у меня был импровизированный ассоциативный массив. Так не делайте, используйте готовый, он в Си++ есть (std::map). Но я сделал свой, с б/дж и ш. Ключ у меня был... целое число. А значение -- текстовая строка (char*, так тоже не делайте, потому что есть std::string). Для поиска по ассоциативному массиву была сделана специальная функция, возвращающая char*.

Проблема была в тех случаях, когда ключ был в массиве не найден. Моя функция возвращала NULL, а точнее, (char*)NULL. Нулевой указатель. Который с удовольствием выводился в файл.

Файловый поток такого издевательства терпеть не мог. Он выставлял сразу биты fail и bad (но не возбуждал исключение!). Я, естественно, не проверял статус выходного потока после каждого вывода. Да и не проверял вообще. А так уж поток устроен, что если ошибку не устранить, весь остальной вывод будет молча с'едаться, что и происходило.

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

@темы: Программирование, Фейлы, Говнокод, Борьба с техникой

URL
вторник, 17 декабря 2024
01:51 Длинные условия
Сколько раз такое было, пишем оператор условия, а там:

if(flag1==True&&flag2==False&&function_call(a,b,c,d)>0)

и что-нибудь ещё.

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

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

2. Но я хотел написать про минорное упрощение. Нужно записывать условия в столбик. Я давно так делаю. Но недавно я обнаружил, что записывать в столбик можно по-разному. Можно написать:

if(flag1==True&&
flag2==False&&
function_call(a,b,c,d)>0)

А можно написать:

if(flag1==True
&&flag2==False
&&function_call(a,b,c,d)>0)

Я всегда использовал первый вариант, но убедился, что он неудобен. Логическая операция находится в конце строки, её надо постоянно искать глазами. А концы у каждой строки находятся в разном месте. Если расположить оператор в начале, то, во-первых, будет понятнее, что происходит, а во-вторых, можно для удобства дублировать оператор и в конце предыдущей строке, но уже в комментарии, типа //&& .

Но насчёт дублирования я пока не уверен, т.к. никогда так не делал.

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

bool b1=(flag1==True);
bool b2=(flag2==False);
bool b3=(function_call(a,b,c,d)>0);//скобки необязательны, но пусть будут на всякий случай
if(b1&&b2&&b3)

Какие есть особенности у этого метода?
Во-первых, если удастся дать условиям краткие понятные имена, а не b1, b2, b3, то это действительно упростит читаемость. Если имена будут условными, то упрощение тоже будет условным.
Во-вторых, упрощается отладка, поскольку вы получаете непосредственный доступ к частям логического выражения, а обычно такого доступа нет, т.к. условие выполняется в отладчике как одна строка.

@темы: Программирование, Говнокод

URL
вторник, 03 декабря 2024
01:44 Второй проход
Если при добавлении функционала в программу приходится вносить массовые правки, то у программы плохая архитектура. И тем не менее, массовые правки вносить иногда приходится.

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

Потому что при массовых правках легко пропустить что-нибудь по невнимательности. А поиск этих пропусков будет гораздо быстрее, если сделать его сразу.

Одна из проблем, которая может возникнуть -- это поиск всех исправленных мест. Тут есть три варианта:
1. Все места для правок могут быть уже помечены ещё до начала (например, вы исправляете поведение программы при определённом значении какой-либо опции, и сравнение с этим значением есть во всех исправленных местах).
2. Можно вручную помечать все места, куда вносятся правки, но делать это надо было заранее
3. Система контроля версий.

@темы: Программирование, Лайфхак, Говнокод

URL
пятница, 08 ноября 2024
03:57 Парные случаи в действии
Продолжение истории про копирование строки.

Начальник делал свою задачу, доделал, рассказывает: всё работает, кроме одного окна. При этом оно безобидное. Но стоит его открыть -- программа падает.

Я прошу показать его, и он открывает... то самое окно, при открытии которого происходили события предыдущего поста.

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

Как выяснилось, он тоже установил тот редкий флаг, но совсем по другой причине. И так удачно совпало, что мы оба наткнулись на эту многолетнюю проблему одновременно. Но я решил её на день раньше...

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

@темы: Программирование, Борьба с техникой

URL
среда, 06 ноября 2024
05:30 Это не Питон
(но в Питоне тоже можно обосраться похожим образом)

В коде нашёл спящую ошибку. Есть строка типа...

char *str=new char[len];

В эту строку раз за разом копируется разный текст через strcpy

strcpy_s(str,len,src);//src каждый раз разный

Потом эта строка отправляется куда-то на обработку, а после обработки в неё копируется следующая строка. Это происходит не в цикле, а методом китайского кода, т.е. строка за строкой.

Оставим в стороне вопрос о том, почему сразу не отправлять src. Тому есть причина.

Несколько копирований проходит успешно, но во время очередного я получаю access violation. Откуда он там может быть? Я тихо копирую в свою область раз за разом. Может быть, не хватает места?

Но путём отладки я обнаруживаю, что ошибка происходит при копировании в ПЕРВЫЙ байт. А когда это возможно?

Когда пытаешься копировать в const-область или типа того. Но у меня же не константная область? Точнее, не была константная ещё три строчки назад. Хммм...

Поднимаю глаза на предыдущие строки. А там примерно следующее:

if(very_rare_option)
{
str="Very rare string";
}

Много лет редкий флаг не выставлялся, поэтому строчка не выполнялась. Но я выставил этот флаг. В результате произошло присваивание. Но в Си++ строки таким образом не присваиваются. Тип правого выражения это const char *, а тип левого -- char *. Я присвоил константный указатель на строку и успешно с ним поработал. Но при попытке записи я стал записывать не по старому адресу, на который была выделена память, а по адресу &"Very rare string", который теперь содержался в str. А там запрещённая для записи область...

Естественно, пришлось переписать:

strcpy_s(str,len,"Very rare string");

И проблема исчезла.

@темы: Программирование, Фейлы, Говнокод

URL
четверг, 31 октября 2024
02:12 Библиотека curses. Краткий обзор
Если линукс-приложение имеет симпатичный интерфейс с кнопочками в текстовом режиме, то обычно считают, что это сделано при помощи curses. Но, как оказывается, пользоваться ей не так-то просто.

Если вы хотите сделать симпатичное переносимое приложение в текстовом режиме, то, возможно, curses не лучший выбор. Да, у вас будет работать и на винде, и на линуксе, и на аналогичных системах. Но какой ценой?

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

Может показаться, что это немало, но у каждого пункта есть "но". Вот примерный список проблем библиотеки:

-- Вывести текст в правый нижний угол экрана непросто (и я не уверен, что вообще возможно)
-- Во всех функциях первый аргумент -- ИГРЕК, а второй -- икс
-- Гарантированно поддерживается только 8 цветов. На многих терминалах поддерживается большее число, но рассчитывать на это нельзя. Далее, каждый терминал видит эти 8 цветов по-своему. Поэтому если вы сделали симпатичное сочетание, то при запуске другой терминальной программы вы рискуете получить нечто вырвиглазное.
-- Атрибуты типа жирный, мигание поддерживаются, но гарантий что они будут отображаться -- нет.
-- Рамочка у псевдо-окон доступна по-умолчанию только одна, одинарная. Для рисования любой другой надо вручную передать 8 символов, которые будут служить границами. Эта рамочка после рисования сразу забывается, поэтому если вы будете выводить сплошной текст, он будет затирать рамку при переносе строки.
-- Поля ввода поддерживаются, но другие контролы типа кнопок, чекбоксов -- нет. Делайте сами.
-- Скролл мышкой гарантированно работает только в одну сторону, через BUTTON4. Скролл в другую сторону генерирует сигнал, который у меня совпал на видне, на линуксе в ssh через putty и в xfce в эмуляторе терминала. Но у этого кода нету именованной константы. Я его подобрал. Это 0x200000. Как вы понимаете, нету гарантий, что это есть на всех реализациях.
-- Проблемы с передачей сочетаний с Alt и с кнопкой Esc. В винде всё работает идеально (что забавно), а в линуксе после эскейпа идёт пауза 1-2 секунды. Видимо, ждёт ввода эскейп-последовательности. Это, кажется, можно победить. Но получить через терминал готовые сочетания типа "M_a" ("ALT_A") невозможно. Вы сначала получите код 27, потом надо ещё раз вызвать getch(). Возможно, при не-удалённой работе линукса на собственном железе этих проблем не будет, пока не проверил.
-- При работе через ssh надо следить, чтобы тип эмулятора терминала с обоих сторон совпадал. Иначе у вас будут неправильно работать клавиши F1...F12. И не только.
-- При работе в графических эмуляторах терминала происходит перехват части нажатий в пользу менюшек. Это можно отключить, но это геморрой.
-- А заставить в линуксе правильно обрабатывать Home, End пока вообще не вышло. Приходит по 3-4 нажатия. Буду разбираться.
-- Самое неприятное, что разницу в работе вы обнаруживаете только в процессе работы. Я работал с библиотекой через питон. И вот вы запускаете один и тот же исходник на одной и той же системе с одной и той же версией пакета curses -- и получаете разный результат в разных терминалах (и ещё отдельный результат через ssh).
-- Команда изменения размера терминала работает через раз. В винде она отрабатывает правильно (что забавно). В линуксе изменяется виртуальный размер терминала, но реальный -- не всегда. При этом терминальная программа сама решает, какие строчки выводить. Например, она понимает, что такое статусная строка, и будет выводить последнюю строку экрана в приоритете. Но часть другого может не понять. И как мне работать? Пользователь может запустить терминал в размере 10 на 10 символов. Иногда это приводит к падениям программы, если пытаться вывести в границах виртуального экрана, но за границами реального. Хотя вроде вызываешь изменение размера, потом проверяешь -- всё ок. Выводишь символ в разрешённую позицию -- и программа падает. *пингвин кланяется* Это происходит не всегда, в глубинной причине не разобрался.

Выводы:
-- Если ваша основная задача это вывод текста в определённой позиции экрана, то всё хорошо
-- Надеяться на стабильное оформление нельзя
-- Надо рассчитывать на минимум доступных цветов, цветовых пар и прочего. При этом ваш терминал может на самом дел всё поддерживать (например, при игре в NetHack через Putty+SSH я вижу больше цветов, у меня работают все сочетания и автоизменение размера экрана, но библиотека говорит, что больше не может)
-- Удивительно, но неплохо работает мышка, хотя это вообще не основная задача терминала

Мне уже Minoru подсказывал альтернативные библиотеки по работе с экраном (STFL, он пишет, что мёртвый). Тем не менее, если вы знаетете библиотеку, которая позволяет:
1) Работать в питоне и с виндой и с линуксом
2) Делать не только поля ввода, но и менюшки, и кнопки и прочее (привет Turbo Vision)
3) Делать стабильное оформление

То сообщите мне.

@темы: Статьи, Программирование, Борьба с техникой

URL
среда, 16 октября 2024
06:09 Дело было не в бобине
Дайри внезапно усилил защиту CloudFlare, возможно специально для меня. Я уже писал, что проверяет эта защита. А у меня долгое время работало просто по куки _identity_. Но перестало.

Я стал делать по своей же инструкции (в конце концов, для себя я её и писал), но не достиг успеха.

Через некоторое время я обнаружил, что User-agent, который я задавал в настроечном файле, не применяется. А почему он не применяется?

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

***

Когда читаешь англоязычные сайты, где различные люди описывают, как они решали программные, аппаратные и другие подобные проблемы, можно периодически видеть выражение "no luck". "I tried XXXX and YYYY, but no luck".

Понятно, что это что-то вроде фразеологизма. И тем не менее, мне как-то не по себе от таких фраз. Luck -- это удача. В то время как большинство программных и аппаратных проблем имеют конкретную причину, которая срабатывает независимо от удачи. И если в результате XXXX и YYYY ничего не вышло, то это не no luck, это no success, no solution или что-нибудь такое.

@темы: Программирование, Восприятие, Борьба с техникой

URL
воскресенье, 13 октября 2024
06:06 Делать хорошо надо сразу
Пет-проектов у меня немного. Тем не менее, кое-что есть. И вот какой эффект я у себя заметил.

Как известно, одно из ключевых средств при разработке ПО -- это система контроля версий. Обычно -- гит. Новый проект лучше сразу начинать в репозитории. Тем не менее, я этого не делаю. Какое-то время файлы проекта болтаются без надзора. А почему?

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

Полагаю, что это порочная практика. Говнокод надо не писать вообще, тогда и коммитить можно будет сразу. А работать без системы контроля версий опасно, хотя конечно в зарождающемся проекте об'ём кода такой маленький, что всё легко не только сломать, но и починить.

Но... непонятно, где тогда экспериментировать с новыми средствами. Делать отдельный репозиторий для экспериментов и никому не показывать?

@темы: Программирование

URL
воскресенье, 06 октября 2024
07:09 Я еще послушник и могу ругаться сколько захочу
Попробовал библиотеку curses. Широко известно, что если текстовая программа выглядит симпатично, то она была сделана на curses.

Так вот. Я, возможно, не до конца разобрался, но пока я не нашёл в библиотеке встроенных средств для создания кнопок, полей ввода и т.п. То есть, библиотека уступает аналогичному TurboVision (кто помнит такой? я на нём не писал, но результаты его работы видел предостаточно).

Но ладно. Я нашёл способ написать то, что мне надо. А поразил меня следующий момент.

В этой библиотеке повсеместно при задании координат сначала задаётся ИГРЕК, а потом икс!

@темы: Программирование, Говнокод, Борьба с техникой

URL
вторник, 24 сентября 2024
05:04 Смотримся в бездну, первая попытка
"Неправильно формируется пдф-отчёт об измерении" -- сообщает коллега.

Я этот отчёт не делаю, но мои данные там есть. Начинаю распутывать происхождение данных и в ужасе понимаю, что отчёт формируется при помощи значений, передаваемых по цепочке между тремя разными программами с двумя промежуточными файлами. И в этом процессе задействованы четыре разных человека.

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

А если бы... если бы я работал с базами данных в большом бизнесе? Я читаю e1_huev0, у него каждый день истории такого же плана, но в десять раз хуже. Э-эх.

@темы: Программирование, Борьба с техникой

URL
четверг, 05 сентября 2024
06:13 Невнятные сообщения об ошибках
Примеров таких ошибок я приводил множество, но недавно до меня дошло, что это системная проблема, и даже появилось подозрение, с чем это связано.

Впервые я встретился с описанием такой ошибки в знаменитой книжке П. Нортона Programmer's Guide to the IBM PC. В русском переводе она имела пространное название "Персональный компьютер фирмы IBM и операционная система MS-DOS". В одной из таблиц с кодами ошибок была следующая запись:

(номер кода ошибки): "Неверный формат (а чего, не говорится)".

Книжку читал я в детстве, не имея на руках ещё никакого компьютера. Меня тогда это насмешило.

Сейчас-то мне не очень смешно!

Так вот, кода ошибки недостаточно для понимания происходящего. Часто нужно указание на имя файла, на какое-то конкретное число и т.п.

Механизм кода ошибок по своей сути не предназначен для передачи дополнительной информации. Чтобы такую информацию передать, надо создавать отдельную систему, причём способную хранить значения произвольного типа.

Казалось бы, у нас есть более современный механизм: исключения. Когда возбуждается исключение, можно сделать целый об'ект и засунуть в него всё что пожелаешь. А если об'ект наследован от какого-нибудь базового CException, то там наверняка есть какой-нибудь GetAsStr(), куда можно всё записать.

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

Что делать? Писать логи. В момент передачи кода ошибки/исключения программа точно знает, что пошло не так. Пусть выводит сообщение с контекстом ещё до того, как вернуть код ошибки/возбудить исключение. Пока ещё всё известно.

@темы: Программирование, Говнокод

URL
пятница, 12 июля 2024
06:17 Ошибка: операция успешно завершена
Многие видели такие сообщения на сайтах или в программах. Видел их и я. А иногда даже делал. Сейчас расскажу, как такое может произойти.

Конкретно у меня был случай такой. Когда возникает ошибка, у неё есть код. Если код равен нулю, то ошибки нет. Начиная с единицы идут реальные коды ошибок.

Далее, произошла ошибка или нет, определяется не её кодом, а возвращением true или false из определённой функции, в которой ошибка и произошла. Если функция сообщила, что ошибка есть, происходит запрос кода ошибки.

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

У меня всё было наоборот. Я сообщаю в соседнюю программу об ошибке, потом получаю код у ошибочной функции. Соседняя программа, узнав об ошибке, тоже запрашивает её код -- уже у меня.

В идеальном мире последовательность действий будет такая:
1. Узнаю об ошибке.
2. Сообщаю соседней программе об ошибке.
3. Получаю код ошибки у ошибочной функции.
4. Приходит запрос от соседней программы о коде ошибки.
5. Я отдаю код ошибки.

Опытные программисты уже видят, где тут косяк. Запрос от соседней программы пришёл раньше, чем я узнал о коде. То есть, последовательность оказалась такой:

1. Узнаю об ошибке.
2. Сообщаю соседней программе об ошибке.
3. Приходит запрос от соседней программы о коде ошибки.
4. Я отдаю код ошибки. (нулевой!)
5. Получаю код ошибки у ошибочной функции.

Это типичная рассинхронизация многопоточного/многопроцессного приложения. У меня косяк: я не должен был никому рассказывать об ошибке, пока не буду сам иметь её кода.

@темы: Программирование, Фейлы

URL
четверг, 11 июля 2024
05:20 Пиши, сокращай
Сокращать длину текста без потери смысла -- это хорошо (не всегда). Но делать это надо речевыми средствами, а не орфографическими.

Я про сокращения. Сокр. разл. слова можно в каких-то личных записках, служебных документах. Но в официальных документах, в вывесках, в интерфейсах программ могут быть только общепринятые сокращения типа № п/п. Сокращений следует избегать, потому что они неизбежно усложняют восприятие текста. Это в каком-то смысле неуважение к читателю.

Тем не менее, сокращения иногда бывают неизбежны. Интерфейсы программ почти всегда изначально проектируются под английский язык. Текст на английском почти всегда компактнее текста на русском. Кнопочка sell может быть очень, очень узкой.

Если вы переводчик, то вам не повезло. Или ваш текст будет сокращённым, или он не влезет. В любом случае, это будет кринж.

Но если вы разработчик, то о таком можно подумать -- раньше или позже.
1. Кнопочки надо делать ПОШИИИИРЕ.
2. Лучше перенос текста на две строчки или уменьшение шрифта, чем сокращение слов (кстати, перенос может быть доступен и переводчику).
3. Если сокращение неизбежно, пусть будут всплывающие подсказки с полным текстом. Потому что иногда сокращённая запись просто непонятна.

@темы: Программирование, Восприятие

URL
четверг, 20 июня 2024
05:44 Неожиданно начал учить новый язык программирования. И сразу закончил
Мне нужно было поковырять данные, которые лежали в файле формата rda. Это двоичный контейнер языка R.

Что такое язык эр? Это какой-то язык для статистической обработки. Я с ним никогда не работал. Но данные мне были нужны.

Окей, гуглю, ставлю интерпретатор, открываю файл. Начинаю что-то с этими данными делать. Поскольку я ничего не знаю, гугл забивается запросами типа "r language how to view column names". И, сука, на каждый такой тупой вопрос есть ответы на стек оверфлоу.

Ковырялся я с этим часа два. В языке эр всё не как у людей. Есть небольшие отличия от си++, от матлаба, от питона. От всего, что я знаю. Поэтому ни одну манипуляцию я не могу произвести без гугла. Например, как вам нравится такое? Для доступа к определённой колонке через имя надо использовать не точку, не квадратную и не круглую скобку. А знак доллара. Например, table$field1. Индексация работает своеобразно. table[,4] -- покажи четвёртую колонку. table [,-4] -- удали (!) четвёртую колонку.

Ну и я просто устал. А ещё столкнулся с непреодолимой проблемой. Я не мог сложить значения двух колонок таблицы потому что где-то в колонке затесалось не-число. Но как его найти? Интерпретатор не указывает номер строки, просто говорит, что у вас формат не тот. А стек оверфлоу? Даже стек оверфолу считает, что такой поиск -- непростая задача.

И тогда меня осенила одна идея. Данные-то я смотреть давно могу. Зачем мне вообще этот эр?

"r language how to export to csv"

CSV-файл я с удовольствием открыл экселем. А уж про эксель я знаю побольше, чем про эр!

@темы: Программирование, Борьба с техникой

URL
четверг, 13 июня 2024
04:51 ТЗ нечёткое, но виноват сам
Надо было сделать многократное измерение. Сколько максимум раз может пользователь захотеть его сделать? Неизвестно. Сотня точно. Может и больше.

Но как это тестировать? Это пользователь может мерить по своему желанию. Мне запустить замер на много часов или даже несколько дней -- сложнее.

10 итераций проверил. 50 итераций проверил. 100... не помню, проверил или нет.

Пользователь запустил 200. А потом пишет -- а почему у меня количество измерений отрицательным отображается?

Читаю логи. 126 измерений... 127 измерений... -128 измерений...

Это такая классика, что у меня олдскулы свело. Программа, отображающая ход измерений и программа, непосредственно проводящая измерения -- разные вещи. Они обмениваются пакетами. Формат пакетов задаю я сам.

И вот почему-то для общего числа итераций я использовал тип int32_t (4 байта), а для номера текущей итерации -- int8_t (1 байт). При этом в микроконтроллере номер итерации хранится 32-битный. Это он только наружу выходит в урезанном виде.

Конечно же, восьмибитное знаковое число будет "оборачиваться" в минус после 127...

@темы: Программирование, Фейлы, Говнокод, Борьба с техникой

URL
вторник, 11 июня 2024
03:23 Файловый указатель: какую я придумал аналогию
В Питоне я предпочитаю файл сразу считывать в память, а уже потом с ним работать. То же и при записи: сначала готовлю содержимое, потом его сразу пишу.

Но файл может быть большим, по нему надо ползать, что-то считывать и что-то записывать не по порядку. В Си для этого есть fseek. В Си++ есть seekp/seekg. В Питоне тоже есть seek.

В детстве я плохо понимал смысл файлового указателя. Вот же он:

FILE *f;

Но это не тот указатель.

Файловый указатель, управляемый функциями типа fseek, обозначает позицию для следующих записи/считывания. Как же это об'яснить студентам, с учётом того, что я сам этого долго не понимал?

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

Несколько сложнее понять, что при чтении и записи курсор автоматически сдвигается.

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

Но изначально я писал не просто про файловый указатель, а про функции типа fseek. И вот каково об'яснение их назначения:

Функции fseek занимаются ничем иным, как установкой положения курсора -- от начала, от конца файла, или относительно текущего положения. Вот и всё.

@темы: Программирование, Студенты

URL