2010-05-29 26 views
8

Escuché que C no es tan seguro y creo que podría usarlo como una ventaja para mi proyecto actual.C: ¿Punteros a cualquier tipo?

Estoy diseñando un intérprete con el objetivo de que la VM sea extremadamente rápida, mucho más rápida que Ruby y Python, por ejemplo.

Ahora sé que la optimización prematura "es la raíz de todo mal", pero esto es más bien un problema conceptual.

  • Tengo que utilizar algún tipo de estructura para representar todos los valores en mi idioma (desde el número más cuerda a la lista y el mapa)

sería posible la siguiente?

struct Value { 
ValueType type; 
void* value; 
} 
  • I almacenaría los valores reales en otro lugar, por ejemplo: una matriz separada para las cadenas y números enteros, el valor * entonces apuntaría a algún miembro en esta tabla.

  • Siempre sabría el tipo de valor a través de la variable de tipo, por lo que no habría ningún problema con los errores de tipo.

Ahora:

Es esto posible en términos de sintaxis y escribir?

+0

Supongo que planea escribir su propio administrador de memoria también? –

Respuesta

7

Sí, puede usar un void* para señalar cualquier cosa, y luego convertirla al tipo apropiado cuando sea necesario (así es como malloc y tal pueden funcionar).

void* es básicamente "puntero a un bloque arbitrario de memoria".

0

Existen diversos grados de seguridad de tipo, pero como C es un lenguaje fuertemente tipado, en realidad se encuentra en el extremo más seguro del espectro. Eso no te impedirá hacer lo que propones. El ejemplo que da es sintácticamente válido y podría usarse para implementar el sistema que describe. Tenga en cuenta, sin embargo, que si continúa e intenta reinventar la rueda creando su propia máquina virtual, es muy poco probable que supere el rendimiento de los idiomas existentes, como Ruby y Java.

+0

Java está precompilado bytecode, tiene que ser más rápido que el intérprete en tiempo de ejecución por definición. De todos modos, "dragme" no habla de Java, así que no entiendo por qué lo mencionas? –

+0

Java también tiene un JIT, que es más rápido que bytecode precompilado por definición :) –

+0

(Aparte de los aspectos de JIT, que concedo), el bytecode de Java se ejecuta en una máquina virtual. Las máquinas virtuales no son "por definición" más rápidas que los intérpretes en tiempo de ejecución. De hecho, las VM son intérpretes en tiempo de ejecución. – warrenm

7

Si conoce la gama de tipos que desea apoyar, esto podría fácilmente hacerse con un union para evitar proyecta por todo el lugar:

struct Value 
{ 
    ValueType type; 
    union 
    { 
     int*  iptr; 
     char*  sptr; 
     float*  fptr; 
     struct map* mptr; 

     /* ... */ 

     void* vptr; /* catch all, extensions */ 

    } ptrs; 
}; 
+0

De acuerdo, esto no es necesariamente más corto que escribir un elenco, especialmente si la conversión es temprana. – Amber

+0

Por supuesto que no es necesario, solo le permite escribir macros de conveniencia. –

+0

Y alguien que mira el código puede ver los diferentes tipos de valores en lugar de simplemente anular *. Usar uniones en un AST/intérprete es un patrón muy común. –

2

Claro que lo es. Solo necesitará un interruptor grande en type para distinguir el tipo de un valor particular. El mejor tipo a utilizar para su campo type probablemente será una enumeración con una constante para cada uno de los tipos de la lengua, así:

typedef enum type { 
    Integer, 
    String, 
    /* and so on... */ 
} ValueType; 

También se recuerda que desechar el puntero void* a un tipo particular antes usándolo

0

Está bien escribir ese código, pero tal vez tenga que diseñar su "idioma" (ok, intérprete :)) antes que otras cosas.

Por cierto, sugiero que lea el object oriented programming in c book. Cuando haya entendido los conceptos principales, puede consultar la implementación de Python Objects, para que pueda pensar cómo los métodos interactúan con los objetos y cómo se almacenan, y así sucesivamente.

¡Adiós!

0

Consulte CCAN's type safe callbacks para obtener macros que lo ayuden a evitar malos moldes. Sé que no está escribiendo una devolución de llamada, pero una gran cantidad de devoluciones de llamada de tener este aspecto:

void my_callback(void *context) 

Y varios tipos sea desechado a (void *) y pasé a context. Casting dentro de esa función se vuelve complicado, especialmente si la devolución de llamada inicia un hilo que toma un solo argumento (void *).

De todos modos, puede encontrar algunos bits útiles si sigue el enlace.