Ответ 1
С помощью команды #define
вы сможете проверить, было ли выполнено typedef в другом месте в коде, используя:
#ifdef FOO_INT32
FOO_INT32 myfoo;
#else
int myfoo;
#endif
Я натолкнулся на код C, где автор использует следующую идиому повсюду:
typedef __int32 FOO_INT32;
#define FOO_INT32 FOO_INT32
В чем смысл этого? Разве не должно быть typedef? Это способ обхода некоторых компиляторов C?
С помощью команды #define
вы сможете проверить, было ли выполнено typedef в другом месте в коде, используя:
#ifdef FOO_INT32
FOO_INT32 myfoo;
#else
int myfoo;
#endif
Это практика, которая иногда выполняется в заголовках. #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
Это не обязательно хорошая практика, но она имеет свои применения, особенно когда у вас есть некоторые заголовки, которые используют типы, определенные другими библиотеками, но вы хотите предоставить свои собственные замены для случаев, когда вы вообще не используете эти библиотеки.
Этот шаблон также полезен для обнаружения функций регистров в микропроцессорах, как в этом вопросе. Например, могут быть два одинаковых файла заголовка, один из которых определяет один таймер, и один, который определяет 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
Другая причина состоит в том, что для стандартизации могут потребоваться определения макросов.
Фрагмент из 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.
...