Как использовать заголовки C в программе C ++? - PullRequest
5 голосов
/ 07 июля 2011

Я работаю над проектом в Visual Studio 2010, который должен создать файл win 32 dll. У меня есть примеры C-файлов и компиляции, которые хорошо работают. Я хотел бы включить некоторые функциональные возможности из написанной мной функции C ++, но я натолкнулся на стену.

Если я попытаюсь связать функции C ++ с программой C, он ничего не знает о строках и т. Д. И просто не работает вообще (конечно).

Так что мне осталось изменить пример на программу на C ++, тогда я могу безнаказанно использовать другие мои файлы. Когда я пытаюсь сделать это, я получаю ошибку ссылки, которую я не понимаю, и не знаю, как ее устранить.

В примерах используются предоставленные поставщиком заголовки, которые включают такие выражения, как

 typedef void ( __cdecl *BINDING_PROC_BEVNT)(WORD_T choice, INT_T * pStatus, 
            I_EVNT_T  * pIn, O_EVNT_T  * pOut);

В теле основного кода следующие примеры:

extern BINDING_PROC_BEVNT       b_evnt;

Который затем позволяет писать

b_evnt(choice, &status, &inpEvent, &outpEvent);

В файле C, предоставленном поставщиком, они снова называются:

BINDING_PROC_BEVNT      b_evnt; 
b_evnt = (BINDING_PROC_BEVNT)GetProcAddress(hCNCMod, "bevnt");

Я вижу ошибку компоновщика:

ошибка LNK2001: неразрешенный внешний символ "void (__cdecl * b_evnt) (беззнаковое короткое, короткое *, объединение I_EVNT_T *, объединение O_EVNT_T *)" (? B_evnt @@ 3P6AXGPAFPATI_EVNT_T @@ PATO_EV@A @) @

Если я переименую свой основной файл и перекомпилирую как программу на C, а мои функции на C ++ опущены, все прекрасно скомпилируется. Даже когда основной файл обрабатывается как файл C ++, Intellisense, похоже, распознает определения (при наведении курсора отображаются правильные определения).

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

Любое понимание было бы оценено, возможно, я просто слишком долго смотрел на это сегодня, чтобы понять что-то очевидное, или это может быть что-то, чего я совершенно не осознаю.

Спасибо за помощь!

Ответы [ 4 ]

10 голосов
/ 07 июля 2011

Если вы компилируете библиотеку, имеющую привязки к языку C, вы должны явно указать C ++, что заголовочные файлы для библиотеки ссылаются на C-объекты, а не на объекты C ++ или искажение имен C ++, помешает правильному связыванию.Часто вы можете сделать это следующим образом:

extern "C" {
#include "vendor.h"
}

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

6 голосов
/ 07 июля 2011

Чтобы включить заголовочный файл C из C ++, сделайте что-то вроде этого:

test.cpp

extern "C" {

#include "c_header_file.h"

}

Похоже, что вам нужно сделать, чтобы включитьФайл заголовка поставщика в вашем коде C ++.

Соответственно, чтобы файл заголовка автоматически работал и для C, и для C ++:

c_header_file.h

#ifdef __cplusplus
extern "C" {
#endif

void f(int);
// all declarations go here

#ifdef __cplusplus
}
#endif

Не для всех поставщиков-обеспечиваемые заголовочные файлы будут содержать вышеуказанное обнаружение __cplusplus, поэтому вам придется обернуть их вручную в extern "C", как в первом примере.

3 голосов
/ 07 июля 2011
error LNK2001: unresolved external symbol "void (__cdecl* b_evnt) 
(unsigned short,short *,union I_EVNT_T *,union O_EVNT_T *)" 
(?b_evnt@@3P6AXGPAFPATI_EVNT_T@@PATO_EVNT_T@@@ZA)

Это означает, что искаженная переменная C ++ b_evnt не может быть найдена. Это правда, потому что это должен был быть C-искаженный (просто префикс _). Чтобы это исправить, сообщите об этом компилятору в заголовке при компиляции для C ++:

#ifdef __cplusplus
extern "C" BINDING_PROC_BEVNT       b_evnt;
#else
extern BINDING_PROC_BEVNT       b_evnt;
#endif

Если это все, все готово. Если вам нужно больше символов, вы можете вместо этого использовать решение Грега, но имейте в виду, что это также не является решением проблемы.

0 голосов
/ 07 июля 2011

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

Заголовки должны быть заключены в блок extern "C" {}, чтобы компилятор C ++ знал, что в этих объявлениях используется связь C.

Вероятно, самый простой способ сделать это - использовать собственные заголовки-обертки, которые делают что-то вроде:

#ifndef FOO_WRAPPER_H
#define FOO_WRAPPER_H

#if __cplusplus
extern "C" {
#endif

#include "foo.h"

#if __cplusplus
}
#endif

#endif

И включите ваш заголовок оболочки вместо заголовка производителя - оболочка будет работать для всех компиляций C или C ++.

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

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