Я пишу код C для взаимодействия с частью оборудования. Это аппаратное обеспечение имеет встроенные функции API, которые определены в файле заголовка, заключенном в блок extern "C". По какой-то причине я не могу заставить программу компилироваться, когда я выбираю "компилировать как код С" в листах свойств. Даже незнакомец, я могу заставить его не давать ошибок, когда я "компилирую как C++", не меняю никакого кода, а затем меняю его на "компилировать как C". Что происходит? Единственными двумя файлами, которые у меня есть, являются main.c, header_file.h и define_file.h (который является #include
d в header_file.h).
Я написал очень простую программу, чтобы проиллюстрировать, что происходит:
#include "header_file.h"
int main(){
return 0;
}
Чтобы дать более подробную информацию, ошибка, которую я получаю, поступает из файла заголовка, который выглядит примерно так:
#ifdef __cplusplus
extern "C" {
#endif
#include defines_file.h
FUNC_API(int) Function(Type1 var1, Enum2 var2, Type3 var3, void* ptr=0);
#ifdef __cplusplus
}
#endif
Файл define_file.h выглядит так:
enum Enum2{
//enumerator list
};
Ошибки:
1>c:\header_file\include\header_file.h(78): error C2146: syntax error : missing ')' before identifier 'var2'
1>c:\header_file\include\header_file.h(78): error C2081: 'Enum2' : name in formal parameter list illegal
1>c:\header_file\include\header_file.h(78): error C2061: syntax error : identifier 'var2'
1>c:\header_file\include\header_file.h(78): error C2059: syntax error : ';'
1>c:\header_file\include\header_file.h(78): error C2059: syntax error : ','
1>c:\header_file\include\header_file.h(78): error C2059: syntax error : ')'
Кажется, он думает, что Enum2
является переменным именем Type1
. Как будто мне не хватает определения Enum2
, но я не - он определен в define_file.h. Одна вещь, которую я заметил, это то, что Enum2
не определен внутри блока "extern C". Это проблема? Я не хочу менять файлы заголовков, потому что я их не писал. (Я все еще не уверен на 100%, как работает "extern C").
В C вам нужно определить перечисление как тип или фактически префикс его с enum
слова, когда вы используете его, как имя типа.
Поэтому либо вам нужно изменить определение
//replace this:
enum Enum2{A,B,C,D};
//with this
typedef enum{A,B,C,D} Enum2;
или вы можете сохранить определение одинаковым и изменить подпись функции на
FUNC_API(int) Function(Type1 var1, enum Enum2 var2, Type3 var3, void* ptr);
Дело в том, что C и C++ - это два разных языка, и если заголовок не был написан с одним из двух, то вы можете просто не использовать его, не изменяя его.
edit: как упоминалось в @Clifford, то же самое касается типов struct
.
struct Type1 //this is passed as "struct Type1 pName"
{
int a,b,c;
};
typedef struct //this is passed as "Type2 pName"
{
int a,b,c;
}Type2;
//this is passed as either "struct type3 pName" or "type3_t pName"
typedef struct type3
{
int a,b,c;
}type3_t;
Type1
должен быть псевдонимом typedef, а не классом или прямой структурой.
Объявленный интерфейс extern "C"
должен быть действительно C; поэтому интерфейс:
Вы можете использовать структуры POD, пока они сами объявляются extern "C" в компиляции C++. В C, в отличие от C++ struct, теги enum и union не имеют собственных имен типов, поэтому они должны быть явно квалифицированы или заданы псевдоним typedef.
Обратите внимание, что следующее:
#if defined __cplusplus
extern "C"
{
#endif
// Declarations must be valid C syntax
int function() ;
#if defined __cplusplus
}
#endif
Решает:
extern "C"
{
// Declarations must be valid C syntax
int function() ;
}
в C++, и просто:
// Declarations must be valid C syntax
int function() ;
в C
Важным моментом является то, что при компиляции кода C ничто C++ не может быть включено.
extern "C"
- это синтаксис C++ для переключения всех имен символов, которые необходимы для поддержки перегрузки, членства в классе и необязательных параметров и т.д., И который недействителен C. Он заставляет имя символа в компиляции C++ быть таким же, как в компиляции C.
extern "C"
не является допустимым C, это конструкция C ++. Если вы компилируете код как C, то вам нуженextern
(или вообще нет спецификатора хранилища, так как функции по умолчанию являютсяextern
).