- Defining literal constants:
The C Preprocessor Way
#define VALUE 5
The D Way
const int VALUE = 5;
- Creating a list of values or flags:
The C Preprocessor Way
int flags:
#define FLAG_X 0x1
#define FLAG_Y 0x2
#define FLAG_Z 0x4
...
flags |= FLAGS_X;
The D Way
enum FLAGS { X = 0x1, Y = 0x2, Z = 0x4 };
FLAGS flags;
...
flags |= FLAGS.X;
- Distinguishing between ascii chars and wchar chars:
The C Preprocessor Way
#if UNICODE
#define dchar wchar_t
#define TEXT(s) L##s
#else
#define dchar char
#define TEXT(s) s
#endif
...
dchar h[] = TEXT("hello");
The D Way
import dchar; // contains appropriate typedef for dchar
...
dchar[] h = "hello";
D's optimizer will inline the function, and will do the conversion of the
string constant at compile time.
- Supporting legacy compilers:
The C Preprocessor Way
#if PROTOTYPES
#define P(p) p
#else
#define P(p) ()
#endif
int func P((int x, int y));
The D Way
By making the D compiler open source, it will largely
avoid the problem of syntactical backwards compatibility.
- Type aliasing:
The C Preprocessor Way
#define INT int
The D Way
alias int INT;
- Using one header file for both declaration and definition:
The C Preprocessor Way
#define EXTERN extern
#include "declations.h"
#undef EXTERN
#define EXTERN
#include "declations.h"
In declarations.h:
EXTERN int foo;
The D Way
The declaration and the definition are the same, so there is no need
to muck with the storage class to generate both a declaration and a definition
from the same source.
- Lightweight inline functions:
The C Preprocessor Way
#define X(i) ((i) = (i) / 3)
The D Way
int X(inout int i) { return i = i / 3; }
The compiler optimizer will inline it; no efficiency is lost.
- Assert function file and line number information:
The C Preprocessor Way
#define assert(e) ((e) || _assert(__LINE__, __FILE__))
The D Way
assert() is a built-in expression primitive. Giving the compiler
such knowledge of assert() also enables the optimizer to know about things
like the _assert() function never returns.
- Setting function calling conventions:
The C Preprocessor Way
#ifndef _CRTAPI1
#define _CRTAPI1 __cdecl
#endif
#ifndef _CRTAPI2
#define _CRTAPI2 __cdecl
#endif
int _CRTAPI2 func();
The D Way
Calling conventions can be specified in blocks, so there's no
need to change it for every function:
extern (Windows)
{
int onefunc();
int anotherfunc();
}
- Hiding __near or __far pointer wierdness:
The C Preprocessor Way
#define LPSTR char FAR *
The D Way
D doesn't support 16 bit code, mixed pointer sizes, and different
kinds of pointers, and so the problem is just
irrelevant.
- Simple generic programming:
The C Preprocessor Way
Selecting which function to use based on text substitution:
#ifdef UNICODE
int getValueW(wchar_t *p);
#define getValue getValueW
#else
int getValueA(char *p);
#define getValue getValueA
#endif
The D Way
D enables declarations of symbols that are aliases of
other symbols:
version (UNICODE)
{
int getValueW(wchar[] p);
alias getValueW getValue;
}
else
{
int getValueA(char[] p);
alias getValueA getValue;
}