«Гопник-2»: переход на нормальный Си++11
Как я писал прежде, когда я адаптировал
Тут у нас в Татарстане выдались длинные выходные, — в праздник
Вызов _fileno у меня использовался для получения номера дескриптора входного потока, так что тут всё решилось просто, — для этого есть специальная константа STDIN_FILENO. А вот с strdup пришлось повозиться.
Сначала я, разумеется, сделал свою реализацию — там
Первым делом пошёл на поклон к «ЧатГПТ», спросил совета. Советы не заработали, но дали направление мысли.
Первая мысль была забахать макрос, который заменял бы собой strdup в проблемном компиляторе, а остальные не трогал. Тут надо сказать, что под «Виндой» далеко не во всех наборах утилит компиляторы не содержат функцию strdup, например в msys2 она есть.
Мне хотелось
Пришлось пошарить по исходникам. Оказалось, есть ряд макросов, которые присутствуют в msys2, но отсутствуют в msys. Из них я выбрал __MINGW64_VERSION_MAJOR:
#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
#define strdup(s) (__extension__({ const char* __s = (s); size_t __l = strlen(__s) + 1; char* __d = (char*)malloc(__l);\
__d ? (char*)memcpy(__d, __s, __l) : nullptr; }))
#endifТут используется расширение, которое позволяет писать многострочные макросы. Хотя этот вариант мне и нравится, но опять используется не нормальный Си++, а расширение компилятора.
Вторая мысль, на которую меня навела нейросеть — использовать слабые символы языка Си++. Это совершенно новая для меня штука, поэтому нужно небольшое пояснение. Прежде всего для меня же, чтобы я в будущем не забыл что это вообще такое.
Если упрощать, то символы — это экспортируемые именованные сущности. Те, что
Слабые символы используются для библиотек, чтобы пользователь мог заменить некоторые сущности, если они его не устраивают.
Если перевернуть ситуацию, и считать мой код библиотекой, а тот код, где должна быть определена strdup основным, то всё должно получиться.
«ЧатГПТ», к сожалению, помочь не смог, — сначала подсовывал нерабочий код, а потом зациклился в своих советах. Поэтому пришлось разбираться самостоятельно.
Всё оказалось не так уж и сложно. Сначала в заголовочном файле определяем прототип функции:
#ifdef __MINGW32__
char *strdup(const char *s1);
#endifЯ его спрятал под условие, чтобы мой редактор перестал ругаться на избыточное определение, но всё работает и без этого.
Потом в самом коде создаём слабый символ для strdup:
#ifdef __MINGW32__
#pragma weak my_strdup
char *strdup(const char *src) {
size_t len = strlen(src) + 1;
char *s = (char *) malloc(len);
return s == nullptr ? nullptr : (char *) memcpy(s, src, len);
}
#endifСлабый символ я определяю через директиву #pragma weak, у которой надо указать имя слабого символа, причём оно должно отличаться от имени функции. Я пока не до конца понял зачем это нужно делать, но без этого не работает.
Кстати, #pragma weak тоже расширение, но оно легко заменяется на атрибут weak, надо только будет изучить его синтаксис, я не успел этого сделать.
На имя my_strdup у меня ругается редактор — говорит, что слабый символ нигде не определён, поэтому я опять же засунул всё это в условную компиляцию.
В выходные, как всегда, есть куча дел, кроме хобби, поэтому до конца я разобраться не успел и буду рад, если
Дополнено: в итоге все ситуации я побороть не смог и откатился на самое простое решение со своей собственной реализацией strdup.