Подтвердить что ты не робот

Последствия typedef void FOO vs. #define FOO void в сигнатурах функций

Пройдя через некоторый исходный код, который сильно смешивает C и С++, я натолкнулся на следующее (слегка измененное для защиты работы компании, значение остается тем же):

/*
 * Typedefs of void are synonymous with the void keyword in C,
 * but not in C++. In order to support the use of MY_VOID
 * in place of the void keyword to specify that a function takes no
 * arguments, it must be a macro rather than a typedef.
 */
#define MY_VOID void

В чем разница между typedef void MY_VOID и #define MY_VOID void в этом конкретном контексте?


Я не считаю, что это дубликат этого вопроса, потому что он конкретно спрашивает о последствиях в отношении сигнатур функций, а не о гораздо более общем "разница".

4b9b3361

Ответ 1

Простая тестовая программа в С++ демонстрирует разницу:

typedef void VOID;

void f(VOID) {}

int main()
{
    f();
}

В компиляции (как С++) она дает следующие ошибки:

prog.cpp:5:8: error: '<anonymous>' has incomplete type
 void f(VOID) {}
        ^
prog.cpp:5:12: error: invalid use of 'VOID {aka void}'
 void f(VOID) {}
            ^
prog.cpp: In function 'int main()':
prog.cpp:9:7: error: too few arguments to function 'void f(<type error>)'
     f();
       ^
prog.cpp:5:6: note: declared here
 void f(VOID) {}
      ^

который объясняет, что означает комментарий в коде. В частности, кажется, что typedef VOID пытается быть типом, отличным от VOID, когда он используется как тип параметра.

Ответ 2

Комментарий объясняет разницу. Учитывая псевдоним для void:

typedef void MY_VOID;

Если вы попытаетесь использовать это вместо void, чтобы указать, что функция не принимает никаких параметров:

int f(MY_VOID);

C разрешит это, но С++ не будет.

Итак, если вы действительно хотите сделать жизнь трудной для себя, написав код, который (а) действителен на обоих языках, и (b) использует псевдоним для этого конкретного использования void, этот псевдоним должен быть макрос.

Ответ 3

Комментарий относится к коду, подобному этому:

typedef void my_void_t;
my_void_t foo(my_void_t); // Illegal.

С #define это законно.

Ответ 4

Отрывок из языковых стандартов может сделать все лучше!

C99, 6.7.5.3/10:

Частный случай неименованного параметра типа void как единственного элемента в списке указывает, что функция не имеет параметров.

С++, 8.3.5/2:

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

Разница очевидна. C имеет void в качестве неназванного параметра типа void, а С++ имеет идентификатор void. Первый может быть typedef -ed, последний не может.

Может быть интересно подумать о причинах этого. На самом деле, в С++ допустимо следующее, но незаконно в C:

void fn(int){
}

Поскольку С++ имеет концепцию неназванных (анонимных) параметров в определениях функций, а C не... Почти.

На самом деле один неопределенный параметр может присутствовать в определении функции C: один из типов void.

Что определенно не имеет никакого смысла, поскольку для этого типа не может быть именованного параметра.

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

Но я предполагаю, что вместо того, чтобы пытаться сказать что-то такое сумасшедшее, коммисия С++ просто решила полностью удалить материал "unnamed-void-type-parameter" и перейти со "списком специальных параметров". Я говорю о хорошем избавлении.

И стандарт C? Вероятно, он сохраняет свои странные 6.7.5.3/10 для соображений обратной совместимости...

Ответ 5

Вы можете использовать оба варианта: они делают одно и то же, поэтому единственная разница в том, что с помощью #define вы объявите новый тип макросом.