Walter Bright es el "dictador benevolente de toda la vida" del lenguaje de programación D y fundador de Digital Mars . Tiene décadas de experiencia en el desarrollo de compiladores e intérpretes para varios lenguajes, incluido Zortech C ++, el primer compilador nativo de C ++. También es el creador de Empire , la principal inspiración de Sid Meier's Civilization.
Better C es una forma de trasladar los proyectos C existentes a D de manera coherente. Este artículo le muestra un proceso paso a paso para convertir un proyecto no trivial de C a D y le muestra los problemas comunes que surgen.
Aunque la interfaz del compilador de D dmd ya se ha convertido a D, es un proyecto tan grande que es difícil cubrirlo en su totalidad. Necesitaba un proyecto más pequeño y modesto que pudiera entenderse completamente, pero que no fuera un ejemplo especulativo.
Me vino a la mente un antiguo programa make que escribí para el compilador Datalight C a principios de la década de 1980. Esta es una implementación real del clásico programa make que ha estado en uso constante desde principios de la década de 1980. Se escribió en C incluso antes de que se estandarizara, se transfirió de un sistema a otro y solo cabe en 1961 líneas de código, incluidos los comentarios. Todavía se usa regularmente en la actualidad.
Aquí está la documentación y el código fuente . El tamaño del ejecutable make.exe es 49.692 bytes y se modificó por última vez el 19 de agosto de 2012.
Nuestro plan maligno:
- Minimice las diferencias entre las versiones C y D. Por tanto, si el comportamiento de los programas difiere, será más fácil encontrar la fuente de la diferencia.
- C. № 1.
- . , . № 1.
- C , .
- , № 4.
, , , ..
!
C D. — 52 252 ( — 49 692 ). , , - NEWOBJ ( C- ) DMC 2012 .
#include
D: , #include <stdio.h>
import core.stdc.stdio;
. , Digital Mars C, D ( ). , 29- 64-. (. import
).
#if _WIN32
version (Windows)
. (. ).
extern(C):
C. (. ).
debug1, debug2 debug3 debug prinf
. , #ifdef DEBUG
debug
. (. debug
).
/* Delete these old C macro definitions...
#ifdef DEBUG
-#define debug1(a) printf(a)
-#define debug2(a,b) printf(a,b)
-#define debug3(a,b,c) printf(a,b,c)
-#else
-#define debug1(a)
-#define debug2(a,b)
-#define debug3(a,b,c)
-#endif
*/
// And replace their usage with the debug statement
// debug2("Returning x%lx\n",datetime);
debug printf("Returning x%lx\n",datetime);
TRUE, FALSE NULL true
, false
null
.
ESC . (. ).
// #define ESC '!'
enum ESC = '!';
NEWOBJ .
// #define NEWOBJ(type) ((type *) mem_calloc(sizeof(type)))
type* NEWOBJ(type)() { return cast(type*) mem_calloc(type.sizeof); }
D (thread-local storage, TLS). make
— , __gshared
. (. __gshared
).
// int CMDLINELEN;
__gshared int CMDLINELEN
D , typedef
. alias
. (. alias
). , struct
.
/*
typedef struct FILENODE
{ char *name,genext[EXTMAX+1];
char dblcln;
char expanding;
time_t time;
filelist *dep;
struct RULE *frule;
struct FILENODE *next;
} filenode;
*/
struct FILENODE
{
char *name;
char[EXTMAX1] genext;
char dblcln;
char expanding;
time_t time;
filelist *dep;
RULE *frule;
FILENODE *next;
}
alias filenode = FILENODE;
D macro
— , MACRO
.
// char *name,*text;
// In D, the * is part of the type and
// applies to each symbol in the declaration.
char* name, text;
static
D . C D, , . __gshared
, . (. static
).
/*
static ignore_errors = FALSE;
static execute = TRUE;
static gag = FALSE;
static touchem = FALSE;
static debug = FALSE;
static list_lines = FALSE;
static usebuiltin = TRUE;
static print = FALSE;
...
*/
__gshared
{
bool ignore_errors = false;
bool execute = true;
bool gag = false;
bool touchem = false;
bool xdebug = false;
bool list_lines = false;
bool usebuiltin = true;
bool print = false;
...
}
, , , D .
// int cdecl main(int argc,char *argv[])
int main(int argc,char** argv)
mem_init()
, .
void cmderr(const char* format, const char* arg) {...}
// cmderr("can't expand response file\n");
cmderr("can't expand response file\n", null);
- (->
) C (.
), D .
/*
#if TERMCODE
...
#endif
*/
version (TERMCODE)
{
...
}
// doswitch(p)
// char *p;
void doswitch(char* p)
D debug
. xdebug
.
C \n\
. D .
/+ +/
. (. , ).
// utime(name,timep);
utime(name,timep.ptr);
const
C D, D . (. const
immutable
).
// linelist **readmakefile(char *makefile,linelist **rl)
linelist **readmakefile(const char *makefile,linelist **rl)
void*
char*
D .
// buf = mem_realloc(buf,bufmax);
buf = cast(char*)mem_realloc(buf,bufmax);
inout
, «» . const
, , . (. inout
-).
// char *skipspace(p) {...}
inout(char) *skipspace(inout(char)* p) {...}
arraysize
.length
. (. ).
// useCOMMAND |= inarray(p,builtin,arraysize(builtin));
useCOMMAND |= inarray(p,builtin.ptr,builtin.length)
(immutable
), , . (. ).
// static char envname[] = "@_CMDLINE";
char[10] envname = "@_CMDLINE";
.sizeof
sizeof()
C. (. .sizeof
).
// q = (char *) mem_calloc(sizeof(envname) + len);
q = cast(char *) mem_calloc(envname.sizeof + len)
Windows .
char *
void*
.
! , . , , — , .
make , make-:
\dmd2.079\windows\bin\dmd make.d dman.d -O -release -betterC -I. -I\dmd2.079\src\druntime\import\ shell32.lib
C D, . .
, , :
-
#include
import
; - D- ;
-
->
; - :
- ,
- ,
- ,
- ,
- ;
- ;
- ;
- ;
- ;
- ;
- C D.
:
- ,
- ,
- ,
- ,
- .
, Better C, , :
- !
- acceso seguro a la memoria (incluida la comprobación de desbordamiento del búfer ),
- metaprogramación,
- RAII ,
- Unicode
- funciones anidadas ,
- métodos ,
- sobrecarga del operador ,
- generador de documentación ,
- programación funcional ,
- ejecución de función en tiempo de compilación (CTFE) ,
- y mucho mas .
A la acción
Si sabes inglés, dirígete al Foro D y cuéntanos cómo está progresando tu proyecto Better C.