extern C не может быть использован на уровне класса? - PullRequest
9 голосов
/ 22 июня 2009

Просто хочу подтвердить, что в среде Windows, проекте VSTS 2008 + C ++, мы можем применять только extern C к уровню функций, не имея возможности применять к уровню класса (так что все функции-члены из класса используют искажение имени языка C) ? Я пробовал несколько способов, но всегда ошибка компиляции.

спасибо заранее, George

Ответы [ 5 ]

12 голосов
/ 23 декабря 2009

Вы можете как-то применить extern "C" к функции-члену с помощью очень запутанного (но совершенно законного) хака:

extern "C" typedef int bar_t(int x);

struct foo {
     bar_t bar; // yes, this declares a nonstatic member function!
};

int foo::bar(int x) { return x; } // definition

Это возможно в соответствии с ISO C ++ 03 9.3 [class.mfct] / 9:

функция-член может быть объявлена ​​(но не определена), используя typedef для типа функции. Результирующая функция-член имеет точно такой же тип, как если бы она была явно указана в деклараторе функции, см. 8.3.5.

Однако на самом деле это ничего вам не дает, из-за ISO C ++ 03 7.5 [dcl.link] / 4:

Связывание языка C игнорируется для имен членов класса и функции-члена тип функций-членов класса.

5 голосов
/ 22 июня 2009

extern "c" использует связь в стиле c; то есть необработанное имя функции - это то, что раскрывается из библиотеки. Поскольку это просто необработанное имя функции, ни одна из функций, предназначенных только для C ++, не будет работать с ним, включая методы или внешние члены данных в пространствах имен, классах, структурах или объединениях.

Уточнение : Структуры и объединения находятся в C, но не имеют функций-членов, поэтому их функции-члены в C ++ нельзя экспортировать в стиле c (и определения struct и union не нужно экспортировать, так как это уже в шапке)

4 голосов
/ 22 июня 2009

Глядя на комментарий, который вы поместили к предыдущему ответу («[M] y вопрос только в том, можем ли мы применить extern C на уровне класса, чтобы все функции в классе автоматически имели искажение имени в стиле C?», Ответis 'extern "C" не совсем так работает.'

Синтаксически, extern "C" может применяться к одному выражению блока с разделенными фигурными скобками:

extern "C" int my_foo(int i)
{
    ...
}

extern "C" {
    int my_bar(int i)
    {
        ...
    }

    int my_baz(int i)
    {
        ...
    }
}

ЭтоОбычно используется extern "C" с соответствующими #ifdef __cplusplus защитными элементами для целых заголовков C.

Семантически фактический эффект применения extern "C" будет применяться только к "нормальным" (то есть, неклассовым) функциям иуказатели на функции. Конечно, вы не можете применить его к шаблону C ++. Также вы не можете применить его к методам класса (потому что метод класса должен знать, к какому объекту он был вызван, а связь в стиле C не имеет никакого способа передачиэта информация в функции).

Это , возможно , можно применить extern "C" к функциям, которые существуют в пространстве имен, но информация о пространстве имен просто исчезнетпри использовании через C.


Обновление

Если у вас уже есть класс (мы будем использовать POD class для простоты), и вы хотите сделатьЕго можно использовать из C, вам нужно применить extern "C" к функции, вызываемой в C. К сожалению, это становится уродливым даже в простых случаях:

// in the header file
#ifdef __cplusplus
namespace X {
#endif
    struct A
    {
        int x;
#ifdef __cplusplus
        A() : x(5) { }
        int foo()
        {
             return x += 5;
        }
#endif
    };
#ifdef __cplusplus
    extern "C" {
#endif
        int A_foo(struct A a);
        struct A A_create();
#ifdef __cplusplus
    }
}
#endif


// in the .cc file
#include "try.h"

namespace X {
    extern "C" {
        int A_foo(A* a)
        {
            return a.foo();
        }

        A A_create()
        {
            return A();
        }
    }
}

// in the .c file
#include <stdio.h>
#include "try.h"

int main()
{
    struct A a = A_create();
    printf("%d", A_foo(a));
}

Используя gcc, вы скомпилируете это следующим образом:

  • файл C ++: g++ try.cc -c -o try.o
  • файл C: gcc try.c try.o

Есть несколько важных моментов:

  • Если ваш файл C ++ вызывает в STL за кулисами или вызывает new или delete (или new[] или delete[]), вам нужно будет связать конечную программу с библиотекой времени выполнения C ++ (командная строкаПереключатель для этого в gcc: -lstdc++.
  • Вы, вероятно, захотите передать идентичные флаги оптимизации при компиляции кода C и C ++ (оптимизация может повлиять на размер объектов и, если размерне соответствует, вы можете получить много неприятностей).То же самое для многопоточности.
  • Вы можете использовать все исключения в коде C ++, но , когда они пересекают код C, все ставки отключены .
  • Если вы хотите что-то большееСложно, вы, вероятно, захотите взглянуть на шаблон PIMPL.
  • Когда структура выходит из области видимости в коде C, деструктор C ++ вызывается , а не (некоторые компиляторы могут обещать это сделать,но это не стандартно).Если вам нужно выполнить очистку этих объектов, вам нужно вызвать внешнюю функцию "C", которая вызывает деструктор.

Чтобы явно вызвать деструктор:

extern "C" void A_destroy(struct A a)
{
    a.~A();
}
4 голосов
/ 22 июня 2009

Боюсь, что нет. Но если вы хотите передать объект C ++ функциям C, вы можете обратиться по этой ссылке: http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html#faq-32.8

2 голосов
/ 22 июня 2009

Ммм ... extern "C" форсирование С-стиля. Не может использоваться с классами AFAIK.

...