Подтвердить что ты не робот

Интерфейс с объектами С++ через внешние функции "C"

Может ли функция extern "C" принимать или возвращать типы данных, специфичные для С++, такие как ссылки, указатели-к-членам или не-POD-классы (по значению)? Я не могу найти ничего в стандарте С++, который запрещает это. Логично, я бы ожидал, что стандарт скажет что-то об этом, так как C ABI не обязательно подходит для передачи таких типов.

Причина, по которой я хочу использовать C-ссылку, не имеет ничего общего с компиляторами C. Функция вызывается только из кода С++. Я просто хочу экспортировать unmangled имена функций из моих динамических библиотек.

Пример глупого кода:

class Foo {
  public:
    virtual void doit() = 0;
};

class Bar : public Foo {
  public:
    void doit() { std::cout << "Bar" << std::endl; }
};

extern "C" Foo& getFoo() { static Bar bar; return bar; }

extern "C" Bar getBar() { return Bar(); }

Это компиляция с GCC на Linux и работает так, как ожидалось. Должен ли он, стандартно?

Вопрос - это продолжение обсуждения в комментариях к этому вопросу.

Обновление Я тестировал это с компилятором Comeau, он не жаловался.

4b9b3361

Ответ 1

В соответствии с разделом 7.5.9 Спецификации привязки (С++ 11 draft) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf

"Связывание с С++ с объектами, определенными на других языках, и объектами, определенными на С++ с других языков, определяется реализацией и зависит от языка. Только там, где стратегии размещения объектов двух языковых реализаций достаточно схожи, такая связь может быть достигнута."

Ответ 2

5.2.2 Вызов функции [expr.call]

Существует два типа вызова функции: вызов обычной функции и вызов функции member62 (9.3). Вызов функции - это постфиксное выражение, за которым следуют скобки, содержащие, возможно, пустой список выражений, разделенных запятыми, которые составляют аргументы функции. Для обычного вызова функции выражение postfix должно быть либо lvalue, которое относится к функции (в этом случае стандартное преобразование функции-to-pointer (4.3) подавляется в постфиксном выражении) или оно должно иметь указатель на тип функции, Вызов функции через выражение, тип функции которого имеет языковое связывание, отличное от языкового связывания типа функции определения вызываемых функций, undefined (7.5).

Итак, если тип вашей функции в точке вызова (т.е. тип вызываемой функции) отличается от типа функции в точке определения, результат равен undefined.

7.5 Характеристики связи (пункт 1) [dcl.link]

Все типы функций, имена функций с внешней связью и имена переменных с внешней связью имеют языковые связи.

Отсюда видно, что языковая связь является частью типа функции. Таким образом, как сайт вызова, так и реализация вызова должны иметь точно такую ​​же языковую привязку.

7.5 Характеристики связи (пункт 9) [dcl.link]

Связывание из С++ с объектами, определенными на других языках, и объектами, определенными в С++ с других языков, определяется реализацией и зависит от языка. Только там, где стратегии размещения объектов двух языковых реализаций достаточно схожи, такая связь может быть достигнута.

Так как C не поддерживает типы С++, никакие объекты С++ не могут быть переданы через интерфейс значимым образом. Функция не может иметь C-языковую связь и передавать объекты С++. Таким образом, мы нарушаем правила типа, определенные выше.

Но: Мы не только должны рассмотреть макет объекта, но и как объект передан/возвращен. Значения, переданные в стек или по регистру, все они определены ABI, и поскольку у C/С++ есть другой API, нет никакой гарантии, как объект передается от одного к другому или что ожидания очистки функции одинаковы.

Ответ 3

У меня нет окончательного ответа на это, но экстраполировать из Wikipedia, я бы сказал, что это не гарантируется Работа. Статья (у меня нет копии стандарта) говорит, что extern "C" специфицирует как mangling, так и ABI. C ABI, по-видимому, не специфицируют не-C-типы, поэтому вы отключены в неспецифическом поведении. (В статье также приводятся случаи, когда CI и С++ ABI отличаются друг от друга, хотя, похоже, это не проблема.)

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

Ответ 4

Я просто хочу экспортировать неповрежденные имена функций из моей динамической библиотеки.

Считаете ли вы, что используете .def файл, который позволит вам экспортировать украшенные имена-функции разными именами? Таким образом, вы можете наслаждаться преимуществами перегрузки и в то же время предоставлять своим функциям "дружественные" имена по своему усмотрению.

EXPORTS
[email protected]@@[email protected]
[email protected]@@[email protected]