В чем смысл говорить "#define FOO FOO" в C?

Я натолкнулся на код C, где автор использует следующую идиому повсюду:

typedef __int32 FOO_INT32;
#define FOO_INT32 FOO_INT32

В чем смысл этого? Разве не должно быть typedef? Это способ обхода некоторых компиляторов C?

Ответы

Ответ 1

С помощью команды #define вы сможете проверить, было ли выполнено typedef в другом месте в коде, используя:

#ifdef FOO_INT32
FOO_INT32 myfoo;
#else
int myfoo;
#endif

Ответ 2

Это практика, которая иногда выполняется в заголовках. #define позволяет проводить проверку времени существования typedef во время компиляции. Это позволяет использовать код:

#ifdef FOO_INT32
FOO_INT32 myfoo;
#else
int myfoo;
#endif

или как true guard #define, аналогично защитному файлу заголовка.

#ifndef FOO_INT32
typedef int FOO_INT32
#define FOO_INT32 FOO_INT32
#endif

Это не обязательно хорошая практика, но она имеет свои применения, особенно когда у вас есть некоторые заголовки, которые используют типы, определенные другими библиотеками, но вы хотите предоставить свои собственные замены для случаев, когда вы вообще не используете эти библиотеки.

Ответ 3

Этот шаблон также полезен для обнаружения функций регистров в микропроцессорах, как в этом вопросе. Например, могут быть два одинаковых файла заголовка, один из которых определяет один таймер, и один, который определяет 2:

cheapprocessor.h:

#define TMR1 TMR1
extern volatile int TMR1;

expensiveprocessor.h:

#define TMR1 TMR1
extern volatile int TMR1;
#define TMR2 TMR2
extern volatile int TMR2;

Что означает в вашем основном коде, когда вы включаете общий processor.h, который делегирует соответствующий заголовок для цели, вы можете обнаружить функции:

#include <processor.h>

#ifdef TMR2
    x = TMR2;
#else
    x = 0;  // no timer, probably because we're on the cheaper model
#endif

Ответ 4

Другая причина состоит в том, что для стандартизации могут потребоваться определения макросов.

Фрагмент из glibc netinet/in.h:

/* Standard well-defined IP protocols.  */
enum
  {
    IPPROTO_IP = 0,    /* Dummy protocol for TCP.  */
#define IPPROTO_IP      IPPROTO_IP
    IPPROTO_ICMP = 1,      /* Internet Control Message Protocol.  */
#define IPPROTO_ICMP        IPPROTO_ICMP
    IPPROTO_IGMP = 2,      /* Internet Group Management Protocol. */
#define IPPROTO_IGMP        IPPROTO_IGMP

Здесь перечисляемые символы также экспортируются как макросы, как требуется соответствующая спецификация POSIX, цитируя:

Заголовок должен определять следующие макросы для использования в качестве значения аргумента уровня getsockopt() и setsockopt():

IPPROTO_IP

Internet protocol.

IPPROTO_IPV6

Internet Protocol Version 6.

...