Ошибка G ++: 1000 <anonymous>’имеет неполный тип - PullRequest
6 голосов
/ 16 марта 2012

Я вынужден использовать стороннюю библиотеку доступа к ключу, которая предоставляет включаемый файл 'sense4.h' с кодом следующим образом:

#if !defined _WINDOWS_

#define WINAPI
#define CONST const

typedef unsigned char   UCHAR;
typedef unsigned short  USHORT;
typedef unsigned int    UINT;
typedef unsigned long   ULONG;

typedef char            CHAR;
typedef char            TCHAR;

typedef void            VOID;

...

#endif /* !defined _WINDOWS */

...

unsigned long WINAPI S4Startup(
        VOID
);


unsigned long WINAPI S4Cleanup(
        VOID
);

...

Проблема в том, что g ++ 4.6.1 жалуется на строкикод, в котором используется typedefed VOID:

sense4.h:375:9: error: ‘<anonymous>’ has incomplete type
sense4.h:376:1: error: invalid use of ‘VOID {aka void}’
sense4.h:383:9: error: ‘<anonymous>’ has incomplete type
sense4.h:384:1: error: invalid use of ‘VOID {aka void}’

Есть ли что-нибудь, что я могу сделать, не меняя включаемый файл 'sense.h' для компиляции моего проекта с g ++?

Обновление 1

Я обнаружил, что раздел 18 C ++ Standard Core Language закрытых выпусков, редакция 30 гласит:

Если предложение параметра-объявления пусто, функцияне принимает аргументовСписок параметров (void) эквивалентен пустому списку параметров.

Можно ли использовать typedef to void вместо типа void в списке параметров?

Обоснование: IS уже ясенчто это не разрешено.

1 Ответ

7 голосов
/ 16 марта 2012

Краткое резюме: Код не является допустимым C ++, хотя есть некоторая неясность относительно того, должен ли он быть.Использование void вместо VOID или использование пустых скобок позволит избежать ошибки.

Я думаю, что это ошибка в g ++.

Я думал,это была ошибка в g ++.Теперь я убежден, что это не так, хотя я утверждаю, что было бы лучше сделать это предупреждение, а не фатальную ошибку.

Обычно в C ++ функция без параметров объявляется с пустыми скобками:

int foo();

В качестве уступки совместимости с C, C ++ также допускает создание прототипа в стиле C, используя void, чтобы указать, что функция не имеет параметров (поскольку пустые скобки означают что-то еще в C):

int bar(void);

g ++ интерпретируется так, что void в этом синтаксисе здесь не относится к неполному type void;скорее он обрабатывает его как специальный синтаксис с отдельным использованием ключевого слова.

Я думаю, вам нужно изменить файл заголовка, чтобы g ++ его принял.

gcc принимает егокак действительный C, но это не полезно, если вам нужно #include из исходного файла C ++ - если только вы не напишите обертку C и не вызовете ее из своего кода C ++, что может быть приемлемым обходным путем.

(Между прочим, я ненавижу typedefs как этот. Какова цель typedef void VOID;? Автор думал, что void был слишком запутанным? Я подозреваю, что это для совместимости с очень старыми компиляторами C, которые не поддерживалиvoid, но необходимость в этом давно миновала.)

Вот соответствующее описание из последней версии стандарта ISO C ++ 2011 (8.3.5 [dcl.fct]):

Параметр-объявление-предложение определяет аргументы, которые могут быть указаны, и их обработку при вызове функции.[...] Если параметр-объявление-предложение пуст, функция не принимает аргументов.Список параметров (void) эквивалентен пустому списку параметров.За исключением этого особого случая, void не должен быть типом параметра (хотя типы, производные от void, такие как void*, могут).

Это означает, что ключевое слово voidв int bar(void); относится к типу void. Поскольку имя typedef является синонимом для именованного типа, int bar(VOID); должно быть в равной степени допустимым. Было бы наиболее целесообразно, чтобы имя typedef, например VOID, было принято вместо void,но формулировка стандарта фактически относится к ключевому слову void, а не к типу.

Вся цель разрешения (void) - совместимость с Си.Просто чтобы добавить к путанице, стандарт ISO C 1990 года требует ключевое слово void;стандарты C 1999 и 2011 годов изменили формулировку, позволив вместо этого использовать typedef.Ответ на Отчет о дефектах C ++ # 577 подтверждает, что в текущей формулировке требуется ключевое слово void, и предлагает изменение, которое разрешит typedef, но это изменение пока отсутствует ни в одном стандарте ISO C ++.Вероятно, он появится в первом Техническом исправлении для C ++ 2011, когда бы он ни был опубликован.

Спасибо another.anon.coward за поиск существующего gcc отчета об ошибках .Я добавил слишком подробный комментарий о том, что код действителен, и сообщение об ошибке не должно создаваться, и более поздний комментарий, в котором говорится, что код недействителен, но предупреждение будет более уместным, чем фатальная ошибка.

Тем временем я предлагаю связаться с поставщиком этого sense4.h заголовочного файла.Если они намеревались сделать это #include d только из кода на C, то с этим нет никаких реальных проблем (кроме плохого стиля IMHO);в противном случае они могут рассмотреть возможность использования #ifdef __cplusplus, объявив функции с (void) в C и с () в C ++.И вы можете пойти дальше и сделать это самостоятельно.Независимо от того, должен ли g ++ принять код или нет, с некоторыми изменениями это будет допустимый C, допустимый C ++, приемлемый как для gcc, так и для g ++, и лучший стиль.

Если вы прочитали это далеко и вы еще не спите, я впечатлен.

...