Suggerisco di iniziare con lo GCC Macros documentation che fornisce un po 'di informazioni interessanti sull'implementazione GCC del preprocessore C.
Clay Bridges nella sua risposta fornisce un paio di esempi di utilizzo del preprocessore C. Quello sulla lingua dell'Ordine è interessante con una serie di esempi. L'autore dell'Ordine fa emergere un problema in cui si è imbattuto, le implementazioni del preprocessore C potrebbero non implementare completamente standard più recenti.
In generale l'utilizzo del preprocessore C per sviluppare una sorta di linguaggio bastardo come quello che ha fatto Steve Bourne durante la scrittura di Bourne Shell per Unix è un'attività che considererei motivi idonei per la consegna, seguita da più sessioni di water boarding.
La cosa principale da ricordare sul preprocessore C è che sta manipolando i token di testo. Quindi il preprocessore C consentirà un po 'di armeggiare con la sintassi. Ad esempio la seguente macro, che compila con Visual Studio 2005 senza errori, mostra la manipolazione del testo non intuitiva possibile.
#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),+=,});
}
Tuttavia si ha bisogno di comprendere e risolvere alcuni dei limiti del preprocessore C quando spingendo i confini. Vedere lo GCC topic Macro Pitfalls per alcuni dei problemi da considerare.
E il Preprocessore C può essere utilizzato come un preprocessore generale di macro e testo che ha come target alcuni strumenti diversi dal compilatore C. Ad esempio, il precedente imake utility for build automation utilizzava il preprocessore C per fornire una funzione macro estesa.
Dove ho visto il Preprocessore C utilizzato in modo più efficace era nella semplificazione di codice e dichiarazioni complesse.
Un caso che ho visto è stato l'utilizzo del preprocessore C per fornire un linguaggio macchina di stato che è stato utilizzato per creare strutture dati e dati per descrivere una macchina a stati. Le strutture dati risultanti sono state quindi utilizzate come argomento per una funzione della macchina a stati. Ciò consentiva di scrivere più procedure di macchina a stati diversi nella lingua definita da C Preprocessore con l'elaborazione della macchina a stati eseguita da una singola funzione.
Microsoft, nel proprio Microsoft Foundation Classes (MFC), ha utilizzato il preprocessore C per nascondere alcuni dettagli di messaggistica di MFC. Una volta che ci si abitua a qualcosa di simile a quanto segue è ragionevolmente facile da leggere. Dal momento che l'IDE di Visual Studio disponeva di strumenti per generare e modificare il codice utilizzando i macro, era piuttosto semplice per il programmatore.
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()
soprattutto quando si vede ciò che le macro aspetto usato come:
#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)) },
Date un'occhiata alla seguente domanda sulla scrittura di codice orientato agli oggetti in C http://stackoverflow.com/questions/351733/ can-you-write-object-oriented-code-in-c .... perché alcune delle implementazioni di C oop fanno un uso pesante del IIRC del preprocessore. –
C con le classi era un compilatore che indirizzava il codice C, che è una [abitudine comune] (http://programmers.stackexchange.com/a/257873/40065). La menzione del preprocessore C è confusa. –