Jump to content

Talk:C preprocessor/Archive 1

Page contents not supported in other languages.
From Wikipedia, the free encyclopedia
Archive 1

Pre Proccesor Abuse

I felt that the information about the abuse of pre-processor is correct. For reference check Obfuscated code and in particular check this page (on official obfuscated c code contest page) for creative pre-processor abuse.--Hq3473 21:17, 15 Apr 2005 (UTC)

I have no problem with a section on preprocessor abuse. The problem is that everything you wrote after "For example" is incorrect. Akihabara 10:26, 16 Apr 2005 (UTC)
All right, i agree it will probably not compile in ANSI, i will rewrite this soon with a correct example --Hq3473 16:44, 16 Apr 2005 (UTC)
You might consider example like redefining int to long. Akihabara 23:04, 17 Apr 2005 (UTC)
Also, note that that file is not valid C. This page shows the makefile; the compiler compiles the file after two preprocessing stages, for three in all. Valid C code only does preprocessing once. Akihabara 09:56, 15 Jun 2005 (UTC)

X-Macros

The article says, "One little-known use pattern of the C preprocessor is known by the name X-Macros." "Little-known" seems to be fairly accurate; I couldn't find any more information on the subject, anywhere. For example, a google search for "preprocessor X-Macros" finds less than 400 pages; I saw none which referred to what this article describes. Maybe this section should be removed?

Actually, rather than see it removed, I'd like to see it described in more detail; being only a moderately competent programmer myself, I couldn't tell on a cursory reading what the example code was supposed to do. I also couldn't tell if it was being presented as a useful and creative technique, or as an abuse of the preprocessor.

If the section is kept in, then a link should probably be included to at least one external website that mentions the technique. --Surelyyoujest 06:35, 25 January 2006 (UTC)

X-macros have been around for decades and are insanely useful. See http://www.drdobbs.com/cpp/184401387

X-Macros information

The reason I wrote the X macro section is exactly because I could find so little information about it elsewhere. Whether or not this is an "abuse" is obviously a subjective opinion. The same can be said on whether it is creative. However, whether or not it is useful is not debatable, as it proved useful in many projects - and obviously allows far more applications for the DRY principle.

You said you couldn't understand what the example code was supposed to do. It simply applies the macro COMMAND multiple times, each time expanding it to something else. The same COMMAND list in the .x.h file is expanded to a command enum, to a command description list, and to a command handler list. The 3 lists are kept in sync by the x-macro, and you don't have to edit multiple files and locations to add or remove a command.

X-Macros original research?

Forgive the formatting--I'm not up enough on wiki yet. I actually came to wiki trying to search for a use of a similar, but cleaner pattern. The difference is you simply define an apply macro to contain the associations rather than including some other file you make, like such: \

  COMMAND(ADD, "Addition command")\
  COMMAND(SUB, "Subtraction command")\
  COMMAND(XOR, "Exclusive-or command")

Changes to: \

  #define APPLY_COMMAND \
  COMMAND(ADD, "Addition command") \
  COMMAND(SUB, "Subtraction command") \
  COMMAND(XOR, "Exclusive-or command")

...and: \

  enum command_indices {\
  #define COMMAND(name, description)              COMMAND_##name ,\
  #include "commands.def"\
  #undef COMMAND

...to: \

  enum command_indices {\
  #define COMMAND(name, description)              COMMAND_##name ,\
  APPLY_COMMAND\
  #undef  COMMAND

... I could find no information either (and am still searching), though I found code samples which used something similar.

The point being, if nobody uses this, I think this is original research, and furthermore isn't developed enough (it's possible people use something better than what I use). Consider removal? (It'd be better to use C/C++ resources to develop/discuss these ideas, as opposed to wiki). —The preceding unsigned comment was added by 199.46.198.237 (talk) 00:05, 12 April 2007 (UTC).

FWIW, and at risk of sounding like a 'me too' poster, I use the APPLY_COMMAND technique all the time. Beyondo 23:06, 27 October 2007 (UTC)

I have marked it as "original research". As I said in my comments, it is a useful pattern, and should be better known. But Wikipedia is not the conduit for doing that. --Larry Hastings 01:21, 13 November 2007 (UTC)

I found an explanation of the trick at X-Macros -- User:nroets —Preceding unsigned comment added by 41.242.187.18 (talk) 12:59, 23 November 2007 (UTC)
I recognize the technique from examining some C-code, although the section is not well written. But now, in order to get rid of that malplaced {{Original research|section|date=November 2007}} (Original Research in a non-science philosophy related to maths!) screaming, you should add a reference to that link. I'll do it for you. However, the section needs cleanup, so I'll add the appropriate template. Said: Rursus 15:46, 23 November 2007 (UTC)

Random Note

"semicolon ... is omitted so that the macro looks 'natural' when written. It could be included in the macro definition, but then there would be lines in the code without semicolons at the end which would throw off the casual reader."

Au contraire, I think anything that weird ought to look weird, specifically in order to clue in the casual reader that the owls are not what they seem; to do otherwise creates a maintenance beartrap. If it looks like a function call, somebody may assume it's more or less equivalent to a function call expression, and make a change based on that assumption.

FWIW, many years ago I used to use the technique referred to as 'X-Macros' a lot, especially for command tables; one inclusion builds a string table, another builds a table of structs, maybe another builds a table of help messages, and having it all in one place makes it easier to maintain. The stringifying features are handy for this. However, in the last 5-10 years we have things like python which are a far better way of generating tables like that from a common file.

Examples of other uses

Krauss, do you have any more authoritiative links besides these blog and personal pages? If not, please consider moving this to "web template". These all appear to be very unusual uses for C preprocsessor, and they are all more related to web application development. Also, please note the spelling of the word "syntax" is a bit different than a non-native English speaker might expect.

   On web applications, it may be used as a template engine:
   * C-precompiler generating HTML;
   * C-precompiler  generating CSS;
   * C-precompiler generating Javascript.
   * CheetahTemplate use, as a subset language, the C-precompiler sintax. 

Dreftymac 17:31, 9 October 2006 (UTC)

Multi-line macros?

The article currently claims: "Properly used, multi-line macros can greatly reduce the size and complexity of the source of a C program, enhancing its readability and maintainability." This seems debatable, at best. Can anyone give an example? Pfaffben 21:37, 7 March 2007 (UTC)pfaffben

Uses of X-Macros

I've used this construct a lot, mostly in code that processes CSV data to or from a database. The #include file is generated via a Perl program from some data description. Defining FIELD in various ways impliments the variable declarations in the class header, and in the class code itself the pickup methods, the laydown methods, the copy methods and the debug methods. I frequently do the do { ... } while(0) thing too, as the pickup may be non-trivial and need debugging code with column number, field name and variable name. You bet this greatly reduces the size and complexity of a C progam, expecially if you have a few hundred columns to deal with.

One unmentioned feature of do { ... } while(0) is that you can use break; as an early exit from the block. Also, a debugging macro can be re-defined to nothing without any unintended consequences.Got2code 19:21, 15 June 2007 (UTC)

in gcc 4.1.2, at least, do and while(0) are not actually necessary; macros may be bracketed without them. 128.128.98.46 (talk) 19:41, 2 May 2008 (UTC)

X-Macros (Not named as Such) used on a large scale

See the C Template Library on sf.net.

http://squat.sourceforge.net/ http://sourceforge.net/projects/squat/

This presses the technique to the logical (or illogical) conclusion. It generates initialization, destruction, deep-copy, serialization, XML, etc. for a particular piece of data nested to arbitrary complexity. In other words, it does things that C++ templates can not do.

It also manufactures STL-like containers from templates in straight C89, and will make C++ classes, too.

Very, very fast for the raw binary serialization, and the XML code is very simple (though somewhat inflexible, designed only to get data into and out of the structures/classes as they were defined; undefined values will be ignored).

It also contains an AMF-like 'Record' format (and probably will contain an AMF (Actionscript) format in the near future), and a few other odds & ends, such as a lightweight 2D library and GUI manufactured from Photoshop layers.

The C Preprocessor is also used in situations beyond its original purpose

There are many articles on the web for applying the preprocessor to other programming languages, even to generate HTML. For instance...

I don't think there really is a way to 'abuse' the C preprocessor. It's just too handy. Most of the people who cry 'foul' and 'abuse' seem to think it should NEVER be used. That's the worst crime imaginable. Ignoring, even deprecating valuable language features just because YOU PERSONALLY can't figure out how to use them safely and effectively.

Here's one such (ab)use. Coding in ActionsSript, CPP makes hard constants, enumerations and 'inline' functions possible. I personally use it to maintain an 800 line function that makes 16,000 lines of AS source code. It's cheaper (computationally) to expand certain things inline than to call and return on the fairly thick stack frame that AS uses (along with all the initialization and destruction of data on the stack). It also allows very simple things like 'XYZ' coordinates to be generated as a macro class instead of a native one, which speeds things up dramatically. http://flex2cpp.sourceforge.net/


Hi, I just wanted to you to inform, that some people, including me, are using GNU C preprocessor for preprocessing JavaScript. It is usefull as one can use #include, to include independent small files into one bigger one to be served (this reducing number of requests, latency, and improving compression of bigger file). It also allows conditional compilation (for example for different browser, or when some functionality is not needed - also to decress size of script, or turn on/off debuging, tracing, etc,) via #define, #undef #ifdef, #ifndef, #if. Also __FILE__ and __LINE__ is usefull, when debuging bigger applications with multiple source files merged into one. It is generally no problem of using cpp, as JavaScript is similar to C, so there is essentially no conflicts. Witek — Preceding unsigned comment added by 91.213.255.7 (talk) 20:02, 10 July 2011 (UTC)

how would one call a wikipedia page on "#if"?

The # char is not possible in a mediawiki. what would be a good circumscription ?

I want to fix these:

Sorry if that's too OT but I dont know another place to ask ...

Why not:
  • "if (C preprocessor directive)"
  • "else (C preprocessor directive)"
  • "endif (C preprocessor directive)"
and so on... (this does not prohibit linking these articles from disambiguation pages for the "if", "else" and "endif" keywords, notably because there may be indenting spaces between the initial hash symbol and the preprocessor directive name). verdy_p (talk) 12:38, 28 November 2009 (UTC)

use of C99 macro (...) variable arguments is missing

C99 allows variable arguments to macros. This needs to be documented.. it's not even mentioned in the article. —Preceding unsigned comment added by 222.150.16.135 (talk) 02:33, 24 November 2007 (UTC)

See C preprocessor#Variadic macros. EdC (talk) 17:53, 24 November 2007 (UTC)

Code Generation

Here's a subset of another thing you can do that's similar to X-Macros... but different.

It lets you manufacture data that can be used across platforms, and generate tons of boiler-plate code, such as init, destruct and serialization. This is something I've used for lightweight applications with great success. The result can't be 'stepped' in a debugger, but as long as the constructs aren't complicated, you'll never need to. How often do you want to 'step' into memcpy, for instance?

On the down-side, Microsoft's compiler tends to choke to death on its internal buffers expanding macros that get big, as these tend to, though GCC doesn't have a problem with it. If you go much beyond the 'simple', the xmacros version works much better.

On the plus side, and all that including of include files to include include files work doesn't have to happen. One include file can define 'everything' and get expanded into your code.


/*
 * Establish template patterns
 */

#define DEF_DECL( item )		decl_##item
#define decl_BEGIN( classname )				typedef struct classname {
#define decl_SCALAR( type, label, value )		type label;
#define decl_COMPOUND( type, label )			type label;
#define decl_END( classname )				} classname;\
											extern void classname##_init( classname* self );\
											extern void classname##_destroy( classname* self );\


#define DEF_INIT( item )		init_##item
#define init_BEGIN( classname )				void classname##_init( classname* self ) {
#define init_SCALAR( type, label, value )		self->label = (value);
#define init_COMPOUND( type, label )			type##_init( &self->label );
#define init_END( classname )				}
 
#define DEF_DESTROY( item )		destroy_##item
#define destroy_BEGIN( classname )			void classname##_destroy( classname* self ) {
#define destroy_SCALAR( type, label, value )   
#define destroy_COMPOUND( type, label )			type##_destroy( &self->label );
#define destroy_END( classname )            }


/* And serialization, XML I/O, database, dispatch, encoding, etc functions based on this pattern! */

#define CLASS_DECLARE( class_decl )		class_decl( DEF_DECL )
#define CLASS_IMPLEMENT( class_decl )	\
class_decl( DEF_INIT ) \
class_decl( DEF_DESTROY ) \

#define XYZ_DECL( def ) \
def( BEGIN( XYZ ) )\
   def( SCALAR( float, X, 0.0f ) )\
   def( SCALAR( float, Y, 0.0f ) )\
   def( SCALAR( float, Z, 0.0f ) )\
def( END( XYZ ) )

#define MYSTRUCT_DECL( def ) \
def( BEGIN( MyStruct ) )\
   def( SCALAR( int, id, ++globalID ) )\
   def( COMPOUND( XYZ, location ) )\
def( END( MyStruct ) )

CLASS_DECLARE( XYZ_DECL );
CLASS_DECLARE( MYSTRUCT_DECL );


int globalID = 0;

CLASS_IMPLEMENT( XYZ_DECL );
CLASS_IMPLEMENT( MYSTRUCT_DECL );


int main( void )
{
	MyStruct mys;
	MyStruct_init( &mys );
	return 0;
}

When you break this up into X-Macros and include a template, the code can be more elaborate, such as init/destruct/copy functions, etc, because you can step the results directly in a decent GUI debugger, which is nice.

You can view what these make by invoking 'cpp' (cl /E) and then 'indent' on the output.

#! /bin/bash
cpp -P -I. -D__GNUC__ $* >blah.c
indent -l512 -bl -sob -cli0 -bli0 -i4 --tab-size4 blah.c
rm blah.c~
cl /E /I. %1 %2 %3 %4 %5>blah.c
sed s/\#line.*$//<blah.c>blah.c~
indent -l512 -bl -sob -cli0 -bli0 -i4 --tab-size4 blah.c~
move /y blah.c~ blah.c

Macros as templates

Here's a small-ish example of a strong naming convention and the preprocessor to manufacture a C template.

This makes a fixed pool of objects that can be allocated 'instantly' and a lookup table for them at the same time.

Yes, of course the same code can be written in C++, and slightly more concisely at that. So, why would I do this to myself?

(RANT) This code will build and run using any ANSI C89 compiler (C++ is not implemented (or implemented well) in all platforms, especially 'minor' embedded ones where a single vendor provides the development tools), and won't suffer the code-rot that C++ templates tend to experience as implementations of the C++ compiler 'standards' evolve. Unlike C++ template rules, it's hard to get the C preprocessor implementation 'wrong'. It's been around a long, long time, and is composed of simple rules that have very extensive unit tests to prove them.

This is something I learned over the last 20 years of C/C++ language generations since I abandoned assembly language(s) for C. The oldest C code still compiles and runs. C++ even a year old always needs to be 'fixed' when built with the newest compiler, because the modern 'standard' wouldn't compile 'back then', and the code the way it had to be written 'back then' needs things fixed to be compiled with the latest C++ compiler, and just occasionally, the old code builds, but inserts nasty, subtle new bugs.

This is not to say C is rot-proof. Anything with a ton of OS dependencies will generally quit building over time in either form of C. Something like the following example will never fail to build, whereas a similar C++ pool template of STL std::allocator failed to build between two minor versions of $&*@!!! Visual Studio, and it was a cross-platform library that built under the GNU tools of the time. This cross-platform inconsistency in C++ is utterly maddening. Anyway, I can't post that example because it was 'work for hire', and that code's not mine to share, and I don't even have it.

In general, structname_function(instance) is no less cumbersome than instance.function() or classname::function() with the implicit (this*), and the macros are always easier to write than templates, and the output can be viewed by filtering them through a C preprocessor and GNU indent, and you can even integrate that into your build (as needed) and make code that can be stepped line-by-line in the debugger as a result. In any 'modern' C++ compiler, the results of the template expansions are opaque, unless you're a real C++ language lawyer. I mean, sure there's still the old-style C++ compilers that made C code, but do you have one? Will it compile a random sampling of MODERN C++ source with templates? (Probably no, and DEFINITELY no.) (/RANT)

Naturally, C preprocessor templates can be applied to C++ and make marvelous template<> free code that doesn't rot, as long as you avoid anything beyond the most lightweight use of native C++ templates in your own code... but even then you're asking for grief.

#ifndef CTL_POOL_H
#define CTL_POOL_H
/**
 * \file	ctl/pool.h
 * \author	David Mace
 * \brief	Memory allocation from fixed pool
 * Doubles as an array indexed lookup table for items in the pool
**/

/**
 * \brief Declare a fixed pool of type
 * \param type  Template: Type of compound data this allocates
 * \param count Template: Count of available blocks of data
 * \param label What to name the type we've manufactured
**/
#define ctl_fp_decl(type,count, label )\
typedef type ppConcat(label,_type);\
struct ppConcat(label,_freenode)\
{\
	struct ppConcat(label,_freenode)* free;\
};\
typedef struct label\
{\
	struct ppConcat(label,_freenode)* free;\
	type	data[count];\
} label;

/**
 * \brief Initialize a fixed pool of type
 * \param label Template: Type of allocator
 * \param instance	Pointer to fixed pool
**/
#define ctl_fp_init(label, instance )\
{\
	size_t fpicurr = countof((instance)->data);\
	(instance)->free = NULL;\
	while( fpicurr-- )\
	{\
		struct ppConcat(label,_freenode)* fpipCurr = (struct ppConcat(label,_freenode)*) ((instance)->data + fpicurr);\
		fpipCurr->free = (instance)->free;\
		(instance)->free = fpipCurr;\
	}\
}

/**
 * \brief Validate a pointer from a fixed pool; 
 * \param label Template: Type of allocator
 * \param instance	Pointer to fixed pool
 * \param ptr	A void pointer that came from ctl_fp_alloc
 * \return true if this pointer could be from this pool
**/
#define ctl_fp_valid(label, instance, ptr )		memberof((instance)->data,(ppConcat(label,_type)*)(ptr))

/**
 * \brief Return the index of a pointer allocated from a pool
 * Useful for certain constructs where we need unique identifiers for objects
 * Returns the item whether it's free or not, so mark it 'used' in your data somehow wrap this
 * \param label Template: Type of allocator
 * \param instance	Pointer to fixed pool
 * \param ptr A pointer that came from ctl_fp_alloc
 * \return 0 based index from start of pool; and bogus index for bogus pointer
**/
#define ctl_fp_index(label, instance, ptr )		indexof((instance)->data,(ppConcat(label,_type)*)(ptr))

/**
 * \brief Return the pointer to an object in the pool from an index
 * Useful for certain constructs where we need unique identifiers for objects
 * Returns the item whether it's free or not, so mark it 'used' in your data somehow and wrap this
 * \param label Template: Type of allocator
 * \param instance	Pointer to fixed pool
 * \param index An index into the pool
 * \return 0 based index from start of pool; and bogus index for bogus pointer
**/
#define ctl_fp_lut(label, instance, index )		( ((unsigned)(index) < sizeof(instance->data)) ? instance->data + (index) : NULL )

/**
 * \brief Allocate a pointer of type from fixed pool
 * \param label Template: Type of allocator
 * \param instance	Pointer to fixed pool
 * \param result A void pointer to receive the anonymous data
**/
#define ctl_fp_alloc(label, instance, result )\
{\
	(result) = (ppConcat(label,_type)*)(instance)->free;\
	/* Assert: memory link damage? */\
	assert( NULL == (result) || ctl_fp_valid(label, instance, (result) ) );\
	if( (instance)->free )\
		(instance)->free = (instance)->free->free;\
}

/**
 * \brief Allocate a pointer of type from fixed pool, clear it
 * \param label Template: Type of allocator
 * \param instance	Pointer to fixed pool
 * \param result A void pointer to receive the anonymous data
**/
#define ctl_fp_calloc(label, instance, result )\
{\
	ctl_fp_alloc(label, instance, result );\
	memset((result),0,sizeof(ppConcat(label,_type)));\
}

/**
 * \brief Free a pointer of type back to fixed pool
 * \param label Template: Type of allocator
 * \param instance	Pointer to fixed pool
 * \param ptr A void pointer of 'type' that came from ctl_fp_alloc, it will be set to NULL as a side-effect
**/
#define ctl_fp_free(label, instance, ptr )\
{\
	if( (ptr) )\
	{\
		struct ppConcat(label,_freenode)* fpipfree = (struct ppConcat(label,_freenode)*)(ptr);\
		/* Assert: Memory pointer must belong to this pool */\
		assert( ctl_fp_valid(label, instance, ptr ) );\
		fpipfree->free = (instance)->free;\
		(instance)->free = fpipfree;\
		(ptr) = NULL;\
	}\
}
#endif /* CTL_POOL_H */

And here's how to use that thing... note that something repetitive like "SocketPool, &SockPool" can be wrapped in a macro as well, somewhat reducing the verbosity of the code (a useful trick for declaring repetitive C++ template parameters as well). Generally you want to wrap these things in a function, rather than use the naked allocator everywhere, because even small template code can tend to bloat up the application a bit. A problem many C++ implementations share.

Most of the other examples of templates I had handy were, uh, HUGE. They included code to pre-compile functions for variations of character type. Needless to say, this sort of code needs a fat set of unit tests written for it before it can be trusted to run in a larger application, but so do C++ templates.

struct Socket
{
// Whatever contents...
};

ctl_fp_decl( Socket, MAX_SOCKETS, SocketPool );
static SocketPool SockPool; // or "static SocketPool *SockPool;" if you want to allocate it yourself

/* Initialize sockets */
bool SocketsInit(void)
{
    ...
    ctl_fp_init( SocketPool, &SockPool );

}

/* Make and initialize socket */
Socket* Socket_Create(void)
{
	Socket* sock;
	ctl_fp_calloc(SocketPool, &SockPool, sock );
...
	return sock;       
}

/* Free up dead socket */
void Socket_Free( Socket* sock )
{
...
	ctl_fp_free(SocketPool, &SockPool, sock );
}


Calculated Includes

There is no explanation of this in this page, and what are some real world examples of how to use it - instead of the simple:

#define MACRO "someheader.h"
#include MACRO

Is it possible to combine X-Macro capabilities with calculated includes? How would you do it? —Preceding unsigned comment added by 12.5.54.215 (talk) 22:44, 13 July 2008 (UTC)

Yes... and NO. It works with some preprocessors, and not others. While the C compiler will take "two" "strings" next to each other to make "twostrings", the preprocessor doesn't necessarily do the same thing.

  1. define PATH "../some/other/dir/"
  2. include PATH "someheader.h"

Will work on some, and generate an error on others. —Preceding unsigned comment added by 174.145.30.111 (talk) 17:34, 8 October 2008 (UTC)

Maybe the X-Macros section should be transwikied here:

Wikibooks Entry. Thoughts? - Richfife (talk) 16:25, 15 July 2008 (UTC)

C, C++ and "const".

I've made a few corrections to the section which discusses the use of "const" in place of macro definitions.

Specifically, "const" is present in C89, so the statement that "newer versions of C provide the const directive" doesn't seem appropriate.

In addition, I've removed the erroneous statement that a "const" variable can never change. A "const" variable can never change by code that directly references it, but there is nothing to stop code from casting it to a non-const value (though in practice the code may fail). This is often used to work around problems with APIs that aren't const-correct. In reality, "const" means "read only in this context". I've not added that statement to this page as it doesn't seem the right place. Indeed, this is discussed on the const-correctness page.

Jacob (talk) 09:05, 5 November 2008 (UTC)

Really old versions of C (K&R) are not ANSI-compliant and will not define "__STDC__", just like they don't support prototypes and "const". This is quite useful to still support const:
#if defined(__STDC__) || defined(__cplusplus)
# define CONST const
#else /* K&R assumed */
# define CONST /*empty*/
#endif
This predefined macro is one of the first that one will use when porting to old systems (and it is tested in almost all GNU projects, including to build the first-boot Linux kernel, with a very basic compiler that cannot still support the full GLIBC; but anyway, today we are using crosscompilation on another more advanded platform to create the bootstrap and then continue to build on the target system).
There is also a GCC option to build a C source in K&R style from an ANSI-style C source... This is probably even easier than defining complex macros to support the obsoleted K&R syntax from the 1980's... There are however some very small platforms (with little memory, such as embedded systems) that will never be able to upport a full ANSI compiler, and for which only the K&R basic compiler can run, and where you still need to be able to compile small programs, and the K&R syntax is fun to work with... and debug ! verdy_p (talk) 12:49, 28 November 2009 (UTC)

Redirects from # macros

I noticed that there is no Wikipedia article for #define. I don't think it necessarily deserves an article on its own, but it would seem useful to have it redirect to this article. I'm not sure of the status of other preproc directives. Thoughts? Dhollm (talk) 14:23, 12 January 2009 (UTC)

That may have more to do with the limitation of the wikimedia software than anything else. "#define" is not a legal article name, so it would have to be either "define" or "pound_define", neither one of which is very useful. - Richfife (talk) 16:29, 12 January 2009 (UTC)
Given that the initial hash sign is separated from the directive name (which may be separated by indentation spaces), the only directive name should be used as the significant keyword, and suffixed by a disambiguation precision, such as "if (C preprocessor directive)", linked from the "if" disambiguation page (that will also link to "if (C language keyword)", "if (Java language keyword)", ... as needed). verdy_p (talk) 20:01, 28 November 2009 (UTC)