Почему __cplusplus определяется внутри внешнего "C" - PullRequest
3 голосов
/ 10 июля 2019

В пределах extern "C" { } макрос __cplusplus все еще определен.Когда я хочу включить версию C mpi.h в заголовок моей библиотеки, которая динамически загружается, это не будет работать, поскольку mpi.h все еще находит __cplusplus и все равно будет загружаться так, как это было открыто C ++.

#undef __cplusplus работает с gcc.Но я не хочу на это полагаться.

Итак, как написать программу на C ++, которая - использует версию mpi на C ++ и - связана с библиотекой C, которая использует версию mpi на C (где#include <mpi.h> появляется уже в заголовке?

Пример кода:

library.h:

#ifdef __cplusplus
extern "C" {
#endif

#include <mpi.h>

void library_do(MPI_Comm comm);

#ifdef __cplusplus
}
#endif

program.cpp:

#include <library.h>

#include <mpi.h>

int main() {
  MPI::Init();
  // do some mpi C++ calls...  
  library_do(MPI::COMM_WORLD);
  MPI::Finalize();
}

В случае, если кто-то захочет воспроизвести пример здесь, library.c:

#include <stdio.h>
#include "library.h"

void library_do(MPI_Comm comm)
{
    int rank;
    MPI_Comm_rank(comm, &rank);
    printf("MPI Rank: %d", rank);
}

И скомпилировать все, что я пытаюсь с помощью

mpicc -shared library.c -o lib.so
mpicxx program.cpp -l lib.so

Ответы [ 6 ]

6 голосов
/ 10 июля 2019

__cplusplus всегда будет определяться компилятором, если компилятор является компилятором C ++. extern "C" {} дает только связь C, поэтому код внутри прекрасно работает с компилятором C.

3 голосов
/ 10 июля 2019

Точка использования

#ifdef __cplusplus
extern "C" {
#endif

...

#ifdef __cplusplus
}
#endif

предотвращает искажение имени, которое делает C ++. Мы в основном говорим, что не используйте искажение имени, как при традиционном вызове функции C ++, вместо этого оставьте его без декорации. Эта ссылка может быть полезной Имя искажения

Используется для совместимости заголовков C с C ++. Флаг __cplusplus автоматически определяется в компиляторе C ++.

3 голосов
/ 10 июля 2019

Потому что это разные вещи.extern "C" {} сообщает компилятору, как экспортировать символы ( см. Здесь ), тогда как __cplusplus сообщает, что вы можете использовать код C ++, чтобы ваша библиотека могла использовать различные пути кода между #ifdef s.

2 голосов
/ 10 июля 2019

Компилятор выводит следующее:

In file included from /usr/include/c++/4.8.2/bits/stl_algobase.h:61:0,
                 from /usr/include/c++/4.8.2/bits/stl_tree.h:61,
                 from /usr/include/c++/4.8.2/map:60,
                 from /usr/include/openmpi-x86_64/openmpi/ompi/mpi/cxx/mpicxx.h:38,
                 from /usr/include/openmpi-x86_64/mpi.h:2674,
                 from x1.cpp:6:
/usr/include/c++/4.8.2/bits/cpp_type_traits.h:72:3: error: template with C linkage
   template<typename _Iterator, typename _Container>
   ^
/usr/include/c++/4.8.2/bits/cpp_type_traits.h:85:3: error: template with C linkage
   template<bool>
   ^
...

Заголовок mpi.h обнаруживает, что он компилируется как C ++ и, следовательно, включает в себя специфические функции C ++. Однако шаблоны (среди прочего) не работают с связью C (т.е. если заголовок находится внутри блока extern "C").

Переместить включить выше extern "C":

#include <mpi.h>

#ifdef __cplusplus
extern "C" {
#endif

void library_do(MPI_Comm comm);

#ifdef __cplusplus
}
#endif
2 голосов
/ 10 июля 2019

Конечно, это определено. Это все еще компилятор C ++, который компилировал код внутри блока extern "C". Он не прекращает обрабатывать код как C ++, только гарантирует использование соглашения о вызовах / именах C.

Если заголовок не может быть скомпилирован компилятором C ++, единственным выходом является создание оболочки C , которая предоставляет API, совместимый с C ++.

1 голос
/ 10 июля 2019

Если вы #include <mpi.h> из программы на C ++, просто не ставьте extern "C".По крайней мере, OpenMPI и Intel MPI делают это для вас в самом заголовке - если определено __cplusplus.

Возможно, у вас возникли проблемы, потому что некоторые реализации MPI все еще определяют интерфейс C ++ в mpi.h, который был удален изстандарт.Это очевидно ломается под extern "C".Например, с OpenMP вы можете пропустить это, установив OMPI_SKIP_MPICXX.Тогда двойной extern "C" работает, но я все равно не рекомендую его.

Обновление: если вы не можете изменить заголовок библиотеки, просто #include <mpi.h> до #include <lib.h>.

Тем не менее, вы не должны использовать привязки C ++ для MPI.Они были удалены из стандарта более 6 лет назад, после 3 лет ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...