Особенности extern "C"
От: Shmj Ниоткуда  
Дата: 26.04.23 14:25
Оценка: -3
Когда нужно либу на C++ сделать доступной для нормальных (с человеческим лицом) языков программирования — приходится переходить на extern "C". А значит многих фишек C++ уже не будет.

К примеру, не будет ссылок — а только указатели.

Не будет исключений.

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

К примеру, некая функция возвращает указатель void*. А внутри там объект класса из C++. Если его получит прога и вызовет calloc.free для этого указателя — вызовется ли деструктор? Нужно ли каждое поле отдельно делать calloc.free ?
Re: Особенности extern "C"
От: Pzz Россия https://github.com/alexpevzner
Дата: 26.04.23 14:32
Оценка: +8
Здравствуйте, Shmj, Вы писали:

S>К примеру, некая функция возвращает указатель void*. А внутри там объект класса из C++. Если его получит прога и вызовет calloc.free для этого указателя — вызовется ли деструктор? Нужно ли каждое поле отдельно делать calloc.free ?


Нет, нужно отдельно проэкспортировать функцию, которая умеет иничтожать такие объекты, и пусть она сама зовет delete() на C++-ной стороне.

Не надо освобождать C++-ные объекты с помощью free(). Деструктор никто не позовет и вообще никто не обещал, что это в принципе будет работать.
Re: Особенности extern "C"
От: Нomunculus Россия  
Дата: 26.04.23 14:51
Оценка: +3
Здравствуйте, Shmj, Вы писали:

В либе такое надо оборачивать в HANDLE, никаких void*

И иметь в API две функции:

HANDLE create(…)
bool destroy(HANDLE)
Re: Особенности extern "C"
От: night beast СССР  
Дата: 26.04.23 14:54
Оценка:
Здравствуйте, Shmj, Вы писали:

S>К примеру, некая функция возвращает указатель void*. А внутри там объект класса из C++. Если его получит прога и вызовет calloc.free для этого указателя — вызовется ли деструктор? Нужно ли каждое поле отдельно делать calloc.free ?


посмотри как сделано C api в openCV
Re: Особенности extern "C"
От: rg45 СССР  
Дата: 26.04.23 15:43
Оценка: +8 -1
Здравствуйте, Shmj, Вы писали:

S>Когда нужно либу на C++ сделать доступной для нормальных (с человеческим лицом) языков программирования — приходится переходить на extern "C". А значит многих фишек C++ уже не будет.

S>К примеру, не будет ссылок — а только указатели.
S>Не будет исключений.

А ламочка Ильича может работать на дровах.

S>Но то пол беды еще, больше интересует вопрос очистки памяти.


Ты в следующий раз начинай сразу с вопроса. Потому что тоннами бреда, который ты генеришь, ты успеваешь отбить всякое желание отвечать тебе.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: Особенности extern "C"
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 26.04.23 16:23
Оценка: -2
Здравствуйте, rg45, Вы писали:

R>Ты в следующий раз начинай сразу с вопроса. Потому что тоннами бреда, который ты генеришь, ты успеваешь отбить всякое желание отвечать тебе.


Да и вопрос лучше не задавать
Маньяк Робокряк колесит по городу
Re: Особенности extern "C"
От: rg45 СССР  
Дата: 26.04.23 16:38
Оценка: +3
Здравствуйте, Shmj, Вы писали:

S>Когда нужно либу на C++ сделать доступной для нормальных (с человеческим лицом) языков программирования — приходится переходить на extern "C". А значит многих фишек C++ уже не будет.

S>К примеру, не будет ссылок — а только указатели.
S>Не будет исключений.

Если библиотека имеет plain C интерфейс, это вовсе не означает, что она должна быть полностью написана на чистом С. Внутри ты можешь спокойно использовать все перечисленное и гораздо больше.

S>К примеру, некая функция возвращает указатель void*. А внутри там объект класса из C++. Если его получит прога и вызовет calloc.free для этого указателя — вызовется ли деструктор? Нужно ли каждое поле отдельно делать calloc.free ?


Тебе не обязательно возвращать наружу указатели в чистом виде (хотя и такая возможность тоже есть, конечно же). Наружу ты можешь возвращать какие-то безликие дескрипторы, об устройстве и формате которых знаешь только ты. Например, это может быть указатель, закриптованный каким-то нехитрым способом. Или, например, это может быть целочисленный тип 32 или 64 в котором зашифрован индекс типа и индекс объекта. Или еще что-то. Главное то, что все манипуляции с предоставленным тобой ресурсом, включая его освобождение, пользователь должен выполнять через предоставленные тобой же функции, и не пытаться применть к ним какие-нибудь free или delete.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 26.04.2023 16:48 rg45 . Предыдущая версия .
Re: Особенности extern "C"
От: BSOD  
Дата: 26.04.23 16:55
Оценка: +1
Здравствуйте, Shmj, Вы писали:

S>Когда нужно либу на C++ сделать доступной для нормальных (с человеческим лицом) языков программирования — приходится переходить на extern "C". А значит многих фишек C++ уже не будет.


extern "C" означает что имя функции в библиотеке будет сформировано по правилам C. Обычно это добавление префикса "_" к имени. По молчанию, по правилам C++ экспортируемый символ формируется по правилам т.к. "мэнглинга" из сигнатуры функции.
Sine vilitate, sine malitiosa mente
Re: Особенности extern "C"
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 27.04.23 18:02
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Когда нужно либу на C++ сделать доступной для нормальных (с человеческим лицом) языков программирования — приходится переходить на extern "C". А значит многих фишек C++ уже не будет.

Нормальных это питон? Ммм... Нормальность которую мы заслужили.
S>К примеру, не будет ссылок — а только указатели.
Не проблема.
S>Не будет исключений.
Не больно-то и хотелось.
S>Но то пол беды еще, больше интересует вопрос очистки памяти.
Да, это проблема. Если у тебя винда, то рекомендую использовать COM.
S>К примеру, некая функция возвращает указатель void*. А внутри там объект класса из C++. Если его получит прога и вызовет calloc.free для этого указателя — вызовется ли деструктор? Нужно ли каждое поле отдельно делать calloc.free ?
Проблема ещё глубже, разные приложухи могут использовать разный crt что может, ок, скорее всего приведёт приключениям при отладке. Конечно, можно запускаться с одним, но про это всегда надо помнить.
Sic luceat lux!
Re: Особенности extern "C"
От: Кодт Россия  
Дата: 02.05.23 21:50
Оценка: +2
Здравствуйте, Shmj, Вы писали:

S>Когда нужно либу на C++ сделать доступной для нормальных (с человеческим лицом) языков программирования — приходится переходить на extern "C". А значит многих фишек C++ уже не будет.


Нет, не значит. extern "C" — это всего лишь указание компилятору/библиотекарю/линкеру, чтобы экспортируемым объектам давали простые имена.
Фишки, которые мы здесь потеряли — это одноимённые сущности (прежде всего, перегрузки функций).

S>К примеру, не будет ссылок — а только указатели.


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

S>Не будет исключений.


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

S>Но то пол беды еще, больше интересует вопрос очистки памяти.


Это четверть и даже осьмушка беды.
В любой библиотеке есть правило: кто память выделил, тот её и освобождает.
И любой адаптер (хоть плюсовый к "нормально-человеческой" — к той же питоньей, хоть "нормально-человеческий" к плюсовой) должен автоматизировать вызовы функций освобождения.
Даже плюсовый к плюсовой такое может делать: shared_ptr с пользовательским делителем deleter'ом.
class Foo {
private:
  ~Foo();
public:
  static std::shared_ptr<Foo> Create(.....);
};


S>К примеру, некая функция возвращает указатель void*. А внутри там объект класса из C++. Если его получит прога и вызовет calloc.free для этого указателя — вызовется ли деструктор? Нужно ли каждое поле отдельно делать calloc.free ?


А к примеру, если тот же фокус проделает плюсовый код с плюсовым объектом?
Мало ли способов выстрелить в ногу.

Разработчики библиотек с сишным интерфейсом стараются принять меры против шаловливых ручек. Отдают не голые void* "реинтерпретируй меня как хочешь", а всякие там HANDLE.
Для которых валидный способ грохнуть — это вызвать DeleteTheObject(HANDLE), а как это внутри устроено — дело библиотечное.
А если "нормальный с человеческим лицом" язык умеет в RAII, то он вызовет делитель хэндла в своей умной человеческой обёртке.
Перекуём баги на фичи!
Re[2]: Особенности extern "C"
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 03.05.23 05:14
Оценка:
Здравствуйте, Кодт, Вы писали:

S>>Когда нужно либу на C++ сделать доступной для нормальных (с человеческим лицом) языков программирования — приходится переходить на extern "C". А значит многих фишек C++ уже не будет.


К>Нет, не значит. extern "C" — это всего лишь указание компилятору/библиотекарю/линкеру, чтобы экспортируемым объектам давали простые имена.

К>Фишки, которые мы здесь потеряли — это одноимённые сущности (прежде всего, перегрузки функций).

Мы тут не только потеряли, но и приобрели. Приобрели веселье, которое начнётся, если в разных местах одноимённые extern "C" сущности будут разных типов
Маньяк Робокряк колесит по городу
Re[3]: Особенности extern "C"
От: rg45 СССР  
Дата: 03.05.23 06:44
Оценка:
Здравствуйте, Marty, Вы писали:

M>Мы тут не только потеряли, но и приобрели. Приобрели веселье, которое начнётся, если в разных местах одноимённые extern "C" сущности будут разных типов


Для предотвращения таких проблем в C-шниых либах обычно используются всякие суффиксы/префиксы, которые добавляются ко всем публичным именам.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: Особенности extern "C"
От: _NN_ www.nemerleweb.com
Дата: 04.05.23 06:24
Оценка:
Здравствуйте, Нomunculus, Вы писали:

Н>Здравствуйте, Shmj, Вы писали:


Н>В либе такое надо оборачивать в HANDLE, никаких void*


Главное не брать HANDLE из Windows

Для решения этой проблемы есть STRICT + DECLARE_HANDLE, но это всё равно не решает HANDLE.

#ifdef STRICT
typedef void *HANDLE;
#if 0 && (_MSC_VER > 1000)
#define DECLARE_HANDLE(name) struct name##__; typedef struct name##__ *name
#else
#define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name
#endif
#else

typedef PVOID HANDLE;

#define DECLARE_HANDLE(name) typedef HANDLE name
#endif


P.S.
Был в своё время забавный баг:
void f(HANDLE h) {}

HANDLE myHandle;
f(&myHadnle) {} // Бабах !
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: Особенности extern "C"
От: Нomunculus Россия  
Дата: 04.05.23 06:26
Оценка: +1
Здравствуйте, _NN_, Вы писали:

Ну я имел ввиду суть. Да, обычно для каждой либы префикс какой-то дают. Типа MR_HNDL
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.