Dmitry Develop
176 subscribers
77 photos
35 videos
88 files
205 links
Этот канал в основном будет интересен новичкам в программировании и людям немного поопытнее.
Здесь я буду делиться своими новостями и достижениями в программировании.

Разработка, программирование; c++, gcc, g++, gnu, mingw; winapi, windows; vscode.
Download Telegram
Dmitry Develop
image_2025-02-24_06-37-24.png
Впервые за много лет я снова увидел VHS кассеты.
Сегодня её вручную ручкой крутил).

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

ссылка на канал | ссылка на группу
👍4
Зашёл сегодня в настройки роутера и случайно обратил внимание в разделе WAN на значение IP адрес, оно было вида 172.24.86.40.
Потом проверил IP, например, на сайте myip.com.
Там отображался отличный от WAN IP вида 83.224.86.40.

Стало интересно, а почему так.

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

Решил узнать, к какой классификации и диапазону IP относятся те двое.
Первый это class B private (172.16.0.0-172.31.255.255), а второй это class A public (1.0.0.0-127.0.0.0).
То есть эти IP адреса имеют разную классификацию и попадают в разные диапазоны публичности.

У роутера для подключённых устройств есть своя локальная сеть, а из-за недостатка адресов ipv4 у провайдера (ISP) используется NAT (сетевая трансляция адресов), которая транслирует запросы от множества локальных адресов на один публичный в интернет и обратно транслирует ответ.

То есть между моим роутером и интернетом как минимум стоит ещё оборудование провайдера с настроенным NAT.
Ещё можно сделать вывод, что мой IP является серым, то есть на него нельзя напрямую делать запросы из интернета.

ссылка на канал | ссылка на группу
What is the Strict Aliasing Rule and Why do we care?
(OR Type Punning, Undefined Behavior and Alignment, Oh My!)
https://gist.github.com/shafik/848ae25ee209f698763cffee272a58f8

Смотрел ещё недавно по этой теме трансляцию Ильи Мещерина и доклад на C++ Russia от Романа Русяева, поэтому чуть-чуть контекст, причины, цели и последствия понял.

Просто мозг взрывается от strict aliasing rule.
Очень, очень много правил, которые легко нарушить.
Единственные совместимые со всеми другими типами являются только char, unsigned char, or std::byte.
Про signed char, int8_t и uint8_t в стандарте ни слова.

Не могу понять, почему нельзя перекрывать объект через signed char?
Да и знаковость char implementation defined, если не ошибаюсь, или просто не указана.
По идее, если для этого типа нет исключения, то будет undefined behavior.

Мне очень хотелось бы работать с байтами именно через типы-псевдонимы из stdint.h (cstdint), в которых, оказывается, нет псевдонима байта.
Хотя через минуту я вспомнил и понял, что: байт != 8 бит, поэтому на эту роль uint8_t не подойдёт.
Да и в статье упоминается, что эти псевдонимы могут, но не обязаны быть реализованы через char.

Ещё интересно, а можно ли как-то обойтись без placement new, std::launder, std::memcpy, чтобы не нарушить strict aliasing и реализовать, например, сериализацию и десериализацию?

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

Where can I find what std::launder really does?
A byte type: std::byte vs std::uint8_t vs unsigned char vs char vs std::bitset<8>

ссылка на канал | ссылка на группу
Мне нужно автоматизировать запуск некоторых программ с некоторыми аргументами в некоторой последовательности, с некоторой дополнительной логикой, с пользовательским вводом (выбором) в консольном интерфейсе.

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

Скрипт будет лежать на флешке и потенциально запускаться на разных версиях операционной системы и её разрядности, в основном на windows.

У меня уже есть реализация на batch, но мне ужасно сильно не нравится его синтаксис, а так же привязанность к windows.
Примерно то же самое могу сказать про powershell и bash.

Что скажете насчёт написать скрипт на python?
Синтаксис этого языка мне нравится, и я уже когда-то на нём писал свою простую реализацию системы сборки, опыт приятный и положительный.

Но меня волнует требование носить с собой его portable интерпретатор.
Какие потенциальные могут проблемы быть с его запуском или работой скриптов?
Сможет ли portable сборка python запуститься в win PE во время установки windows?

ссылка на канал | ссылка на группу
Dmitry Develop
python32InWinPE.png
Продолжение предыдущей публикации.

Решил переписывать batch скрипт на python.
Язык мне этот нравится, некоторый опыт на нём я уже имею, интерпретатор весит мало, а сверхвысокая производительность не нужна.

Изначально я скачал только 32 битный python с расчётом на то, что такая разрядность будет универсальнее, так как сможет запускаться как на 32, так и на 64 битном оборудовании / установщике.
Но при запуске я получил ошибку, который в первый раз увидел:
"Не удалось запустить приложение, поскольку его параллельная конфигурация неправильна".
("The application has failed to start because its side-by-side configuration is incorrect")

Прочитал информацию по этой ошибке и подумал, что дело в отсутствующих зависимостях.

В документации на python написано, что "The embedded distribution does not include the Microsoft C Runtime and it is the responsibility of the application installer to provide this", поэтому я подумал, что легко не будет.

Поэтому начал искать способ разрешить эти зависимости.
Скачал vc redist и искал способы как-то распаковать все нужные мне DLL библиотеки без их установки.
Открыть как архив в 7zip ничего полезного не дало.
Вспомнил про msiexec, но установочный файл формата exe.
В документации на vc redist нашёл аргумент командной строки layout, который "The /layout option copies the complete contents of the Redistributable in the current directory", но почему-то после запуска ничего не появилось ни в текущей рабочей папке, ни в папке temp.

Позже на форуме microsoft я нашёл тему с похожей проблемой.
В итоге при помощи google и какой-то древнего форума нашёл программу UniExtract2, которая умеет распаковывать различные форматы архивов и установщиков microsoft, и это помогло достать все нужные DLL.

Но прежде чем их подкидывать в папку python, я решил попробовать скачать ещё 64 битную версию и попробовать ещё раз.
И о чудо, в этот раз интерпретатор python смог запуститься в среде winPE и потом даже корректно выполнить скрипт!

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

Но почему-то на 64 битном оборудовании и на такой же разрядности установщике 32 битная программа не запустилась.
Возможно, дело просто в отсутствии или по умолчанию выключенной подсистеме WoW64 в winPE.
В итоге распакованный vc redist не пригодился, но на всякий случай я его сохраню, да и опыт оказался очень интересным и полезным.

ссылка на канал | ссылка на группу
👎2👍1
Сегодня хотел скомпилировать программу на C++ с минимальным размером исполняемого файла и без зависимостей от стандартной библиотеки, только winAPI, так как её суть всего лишь быть небольшой обёрткой для запуска другой программы.

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

Не помню, было ли такое же поведение на более старых версиях gcc + mingw, но при сборке на gcc 14.2.0 и mingw 12.0.0 оно есть, и мне кажется, это баг или недоработка.
Хотя, возможно, так было и раньше, но я мог собирать код без -ffreestanding, поэтому проблема себя не проявляла.
А если компилятор из-за оптимизаций или по другим причинам генерировал вызов любой функции из стандартной библиотеки или crt, то я просто получал ошибку компоновки.
Например, побайтовое копирование циклом for компилятор спокойно может оптимизировать в вызов функции memcpy.

Минимальный воспроизводимый пример состоит лишь из включения заголовочного файла windows.h и ключа компилятора -ffreestanding.
// g++ -ffreestanding -o winapi.exe winapi.cpp

#include <windows.h>

int main()
{
MessageBoxA(nullptr, "Hello world", "message", 0);

return 0;
};


При такой комбинации компилятор выдаёт такой текст ошибки.

Посмотрел в текст заголовочных файлов, на которые указал компилятор, и понял, что из-за ключа -ffreestanding макрос __STDC_HOSTED__ устанавливается в значение 0, поэтому hosted код исключается из сборки.
Беглым поиском я нашёл ещё несколько мест с такими же проверками, но почему-то их не оказалось в x86intrin.h, immintrin.h и xmmintrin.h (возможно, есть ещё такие), которые вне зависимости от значения __STDC_HOSTED__ используют функционал hosted окружения, который отсутствует в freestanding окружении.

Я не знаю для чего нужны эти заголовочные файлы и какое будет наиболее правильное решение, поэтому я сделал максимально простое и тупое решение.
Так как в этих заголовочных файлах вместо директивы препроцессора #pragma once используются header guards через #ifndef #def, я просто перед включением windows.h определил два нужных макроса, чтобы препроцессор не включал эти проблемные заголовочные файлы:
// g++ -ffreestanding -o winapi.exe winapi.cpp

#define _X86INTRIN_H_INCLUDED
#define _EMMINTRIN_H_INCLUDED
#include <windows.h>

int main()
{
MessageBoxA(nullptr, "Hello world", "message", 0);

return 0;
};


Получается, первый способ это не использовать ключ -ffreestanding и получать ошибки на этапе компоновки, а второй это использовать ключ -ffreestanding и получать ошибки на этапе компиляции, но решать некоторые из них придётся костылями или редактированием заголовочных файлов стандартной библиотеки компилятора.
Вне зависимости от использованного способа, конкретно с этим MRE (Minimal Reproducible Example), размер исполняемого файла получается одинаковым.

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

ссылка на канал | ссылка на группу
👍1👎1🤓1
Dmitry Develop
ссылка на канал | ссылка на группу
Сегодня целый день разбирался в исходном коде python.

Было очень сложно, ничего не понятно, откуда начать, куда смотреть, голова уже болит от объёма информации и от разных форматов данных.
Сборка сделана очень странно: где-то bat скрипты, где-то sh, makefile, sln, vcxproj...
Нет бы всё сделать через cmake.

Точка входа, то есть главные файлы, названы нелогично и непонятно.
Где-то это main.c, где-то python.c, WinMain.c, ...

Странная последовательность вызовов функций после точки входа:
[wWinMain, wmain, main] -> [Py_Main, Py_BytesMain] -> pymain_main -> Py_RunMain -> pymain_run_python ...

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

Сейчас у меня уже есть порядок вызова функций, вывод своих отладочных сообщений, я смог изменить как мне надо PyConfig и скомпилировать python.exe и python38.dll.
Дальше надо будет разобраться со статической компоновкой библиотеки и не только.

ссылка на канал | ссылка на группу
1🔥1
Если возникает исключение, cpython вызывает функцию _Py_DumpPathConfig из python.dll и выводит "Python path configuration".

Значение program name там берётся из PyConfig *config = &tstate->interp->config; config->program_name.

Как из скрипта на python получить значение program_name или сразу PyConfig?
Есть sys.executable, но он даёт полный путь, а не название программы, которое было использовано при запуске.

Например, если запустить, "python", то config->program_name будет "python", а если "python.exe", то config->program_name будет "python.exe".

Вот пример запуска из cmd c выводом path configuration:
> python.exe

Python path configuration:
PYTHONHOME = (not set)
PYTHONPATH = (not set)
program name = 'python.exe'
isolated = 0
environment = 0
user site = 1
import site = 1
sys._base_executable = 'path_to_python\\python.exe'
sys.base_prefix = 'path_to_python'
sys.base_exec_prefix = 'path_to_python'
sys.executable = 'path_to_python\\python.exe'
sys.prefix = 'path_to_python'
sys.exec_prefix = 'path_to_python'
sys.path = [
'path_to_python\\python38.zip',
'path_to_python\\DLLs',
'path_to_python\\lib',
'path_to_python',
'path_to_python\\lib\\site-packages',
]

> python

Python path configuration:
PYTHONHOME = (not set)
PYTHONPATH = (not set)
program name = 'python'
isolated = 0
environment = 0
user site = 1
import site = 1
sys._base_executable = 'path_to_python\\python.exe'
sys.base_prefix = 'path_to_python'
sys.base_exec_prefix = 'path_to_python'
sys.executable = 'path_to_python\\python.exe'
sys.prefix = 'path_to_python'
sys.exec_prefix = 'path_to_python'
sys.path = [
'path_to_python\\python38.zip',
'path_to_python\\DLLs',
'path_to_python\\lib',
'path_to_python',
'path_to_python\\lib\\site-packages',
]

Python 3.8.20 (tags/3.8-dirty:39b2f82, Apr 9 2025, 03:36:20) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys; print(sys.executable); print(sys.argv)
path_to_python\python.exe
['']
>>>


Для вывода "Python path configuration" после запуска я экспортировал функцию _Py_DumpPathConfig и вызывал её перед Py_RunMain.

ссылка на канал | ссылка на группу
1
Запускаю из-под python дочерний процесс cmd.exe.
Хочу получать stdin и stderr в utf-8, так как не хочу определять или угадывать ANSI кодировку, поэтому в cmd.exe сначала выполняется chcp 65001, а потом всё остальное.

Но после чистого запуска появилась ошибка, типа не удаётся декодировать неправильный байт.
Начал разбираться и отлаживать, вручную запускать команду в терминале, и заметил, что chcp почему-то не влияет на терминал, запущенный через cmd [/c|/k] (№1).
Если запускать его внутри другого терминала, поведение такое же, но после второго запуска всё становится правильным и почему-то изменяется кодировка родительского процесса (из-за наследования потоков?) (№2).

Почему происходит №1 и №2, что можно почитать, чтобы разобраться что и почему, можно ли это как-то решить?

Если просить вывод не в utf-8 из-за проблем windows с нет, то как тогда получать unicode вывод?
Нельзя же попросить вывод в utf-16?)
(Оказалось, вроде как только для .NET такое доступно)

>chcp
Текущая кодовая страница: 866

>cmd.exe /c "chcp 65001 > nul & testError"
"testError" не является внутренней или внешней
командой, исполняемой программой или пакетным файлом.

>chcp
Active code page: 65001

>cmd.exe /c "chcp 65001 > nul & testError"
'testError' is not recognized as an internal or external command,
operable program or batch file.


Обернул запуск cmd в cmd и заработало так, как я ожидал.
Странно, конечно.

>chcp
Текущая кодовая страница: 866

>cmd.exe /c "chcp 65001 > nul & cmd /c "testError""
'testError' is not recognized as an internal or external command,
operable program or batch file.


ссылка на канал | ссылка на группу