Sugiero que empiece con GCC Macros documentation que proporciona bastante información interesante sobre la implementación de GCC del preprocesador C.
Clay Bridges en su respuesta proporciona un par de ejemplos del uso del Preprocesador C. El del lenguaje de la Orden es interesante con varios ejemplos. El autor de Order menciona un problema con el que se encontró, las implementaciones de C Preprocessor pueden no implementar completamente estándares más recientes.
En general, usar el preprocesador C para desarrollar un tipo de lenguaje bastardo, como lo que hizo Steve Bourne al escribir el Bourne Shell para Unix es una actividad que consideraría un motivo idóneo para la reproducción seguida de múltiples sesiones de inmersión en el agua.
Lo más importante que debe recordar sobre el preprocesador C es que está manipulando tokens de texto. Entonces, el preprocesador C permitirá bastante retoques con la sintaxis. Por ejemplo, la siguiente macro, que compila con Visual Studio 2005 sin errores, muestra la manipulación de texto no intuitiva posible.
#define TESTOP(a,x,y,op,z) a (x) op (y); z
void f(void)
{
int i = 0, j = 5;
TESTOP(,i,j,+=,);
TESTOP(,i,(j + 2),+=,);
TESTOP({,i,(j + 2),+=,});
}
Sin embargo sí es necesario para entender y solucionar algunas de las limitaciones del preprocesador C al empujar los límites. Vea el GCC topic Macro Pitfalls para algunos de los problemas a considerar.
Y puede utilizar el preprocesador C como un preprocesador general de macro y texto que se dirige a alguna herramienta que no sea el compilador de C. Por ejemplo, el imake utility for build automation anterior usaba el preprocesador C para proporcionar una amplia facilidad macro.
Donde he visto que el preprocesador C más utilizado fue en la simplificación de código complejo y declaraciones.
Un caso que he visto fue el uso del preprocesador C para proporcionar un lenguaje de máquina de estados que se utilizó para crear las estructuras de datos y los datos para describir una máquina de estados. Las estructuras de datos resultantes se usaron luego como argumento para una función de máquina de estado. Esto permitió que se escriban múltiples procedimientos de máquina de estados diferentes en el lenguaje definido del preprocesador C con el procesamiento de la máquina de estado realizado por una sola función.
Microsoft, en sus Microsoft Foundation Classes (MFC), usó el preprocesador C para ocultar bastantes de los detalles de mensajería de MFC. Una vez que te acostumbras, algo como lo siguiente es razonablemente fácil de leer. Como el IDE de Visual Studio tenía herramientas para generar y modificar el código con las macros, el programador se mostró bastante directo.
BEGIN_MESSAGE_MAP(CFrameworkWndDoc, CWindowDocument)
//{{AFX_MSG_MAP(CFrameworkWndDoc)
ON_WM_CHAR()
ON_WM_TIMER()
ON_MESSAGE(WU_EVS_DFLT_LOAD, OnDefaultWinLoad)
ON_MESSAGE(WU_EVS_POPUP_WINDOW, OnPopupWindowByName)
ON_MESSAGE(WU_EVS_POPDOWN_WINDOW, OnPopdownWindowByName)
ON_MESSAGE(WM_APP_CONNENGINE_MSG_RCVD, OnConnEngineMsgRcvd)
ON_MESSAGE(WM_APP_XMLMSG_MSG_RCVD, OnXmlMsgRcvd)
ON_MESSAGE(WM_APP_BIOMETRIC_MSG_RCVD, OnBiometricMsgRcvd)
ON_MESSAGE(WM_APP_SHUTDOWN_MSG, OnShutdownMsgRcvd)
ON_MESSAGE(WM_POWERBROADCAST, OnPowerMsgRcvd)
ON_MESSAGE(WM_APP_SHOW_HIDE_GROUP, OnShowHideGroupMsgRcvd)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
sobre todo cuando ves lo que las macros aspecto usado como:
#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
PTM_WARNING_DISABLE \
const AFX_MSGMAP* theClass::GetMessageMap() const \
{ return GetThisMessageMap(); } \
const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() \
{ \
typedef theClass ThisClass; \
typedef baseClass TheBaseClass; \
static const AFX_MSGMAP_ENTRY _messageEntries[] = \
{
#define END_MESSAGE_MAP() \
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
}; \
static const AFX_MSGMAP messageMap = \
{ &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; \
return &messageMap; \
} \
PTM_WARNING_RESTORE
// for Windows messages
#define ON_MESSAGE(message, memberFxn) \
{ message, 0, 0, 0, AfxSig_lwl, \
(AFX_PMSG)(AFX_PMSGW) \
(static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) > \
(memberFxn)) },
#define ON_WM_TIMER() \
{ WM_TIMER, 0, 0, 0, AfxSig_vw, \
(AFX_PMSG)(AFX_PMSGW) \
(static_cast< void (AFX_MSG_CALL CWnd::*)(UINT_PTR) > (&ThisClass :: OnTimer)) },
Echa un vistazo a la siguiente pregunta acerca de cómo escribir código orientado a objetos en C http://stackoverflow.com/questions/351733/ can-you-write-object-oriented-code-in-c .... porque algunas de las implementaciones de C oop hacen un uso intensivo del preprocesador IIRC. –
C con clases era un compilador que apuntaba al código C, que es un [hábito común] (http://programmers.stackexchange.com/a/257873/40065). Mencionar el preprocesador C es confuso. –