2008-12-17 14 views
32

¿Hay alguna manera de aplicar el molde explícito para los typedefs del mismo tipo? Tengo que lidiar con utf8 y algunas veces me confundo con los índices para el recuento de caracteres y el recuento de bytes. Por lo tanto, sería bueno tener algunos typedefs:Imponer comprobación de tipo fuerte en C (rigurosidad de tipo para typedefs)

typedef unsigned int char_idx_t; 
typedef unsigned int byte_idx_t; 

Con el añadido de que necesita una conversión explícita entre ellos:

char_idx_t a = 0; 
byte_idx_t b; 

b = a; // compile warning 
b = (byte_idx_t) a; // ok 

Sé que tal característica no existe en C, pero tal vez usted conoce un truco o una extensión de compilación (gcc preferible) que hace eso.


EDITAR todavía no me gusta mucho la notación húngara en general. No pude usarlo para este problema debido a las convenciones de codificación del proyecto, pero lo usé ahora en otro caso similar, donde también los tipos son iguales y los significados son muy similares. Y debo admitirlo: ayuda. Nunca iría y declararía cada entero con una "i" inicial, pero como en el ejemplo de Joel para tipos superpuestos, puede salvar vidas.

+2

Hay otro artículo muy bueno (Aunque no estoy de acuerdo con prohibir goto :)) de [Joel] (http://www.joelonsoftware.com/) llamado [Hacer que el código incorrecto parezca incorrecto] (http://www.joelonsoftware.com/articles/Wrong.html). Creo que está muy relacionado con tu pregunta, incluso si no hay una conexión directa. – Ilya

+0

Lo más "interesante" e importante en ese artículo, en mi humilde opinión, es el tema sobre la historia de la notación húngara. Muy interesante ... – Noein

Respuesta

2

Si estaba escribiendo C++, podría crear dos clases idénticamente definidas con diferentes nombres que fueran envoltorios alrededor de un int sin firmar. No sé de un truco para hacer lo que quiera en C.

+2

C funciona de la misma manera con las estructuras. Microsoft usa esto para diferenciar los tipos de identificador en windows.h. –

18

Se podría hacer algo como:

typedef struct { 
    unsigned int c_idx; 
} char_idx; 

typedef struct { 
    unsigned int b_idx; 
} byte_idx; 

allí tendría que ver cuando se está utilizando cada uno:

char_idx a; 
byte_idx b; 

b.b_idx = a.c_idx; 

Ahora está más claro que son tipos diferentes pero aún compilarán.

18

Para los tipos "mango" (punteros opacos), Microsoft utiliza el truco de declarar estructuras y luego typedef'ing un puntero a la estructura:

#define DECLARE_HANDLE(name) struct name##__ { int unused; }; \ 
          typedef struct name##__ *name 

Entonces, en lugar de

typedef void* FOOHANDLE; 
typedef void* BARHANDLE; 

Ellos hacer:

DECLARE_HANDLE(FOOHANDLE); 
DECLARE_HANDLE(BARHANDLE); 

Así que ahora, esto funciona:

FOOHANDLE make_foo(); 
BARHANDLE make_bar(); 
void do_bar(BARHANDLE); 

FOOHANDLE foo = make_foo(); /* ok */ 
BARHANDLE bar = foo;   /* won't work! */ 
do_bar(foo);     /* won't work! */ 
7

Use una pelusa. Ver Splint:Types y strong type check.

La comprobación de tipos fuertes a menudo revela errores de programación. Splint puede verificar tipos de primitiva C más estrictamente y de forma flexible que los compiladores típicos (4.1) y proporciona compatibilidad con un tipo booleano (4.2). Además, los usuarios pueden definir tipos de resumen que proporcionan información oculta (0).

4

En C, la única distinción entre los tipos definidos por el usuario que es forzada por el compilador es la distinción entre estructuras. Cualquier typedef que implique estructuras distintas funcionará. ¿Su principal pregunta de diseño es si los diferentes tipos de estructuras usan los mismos nombres de miembro? Si es así, puede simular un código polimórfico utilizando macros y otros trucos de escorbuto. Si no, estás realmente comprometido con dos representaciones diferentes. Por ejemplo, ¿desea ser capaz de

#define INCREMENT(s, k) ((s).n += (k)) 

y utilizar INCREMENT tanto byte_idx y char_idx? Luego nombre los campos de manera idéntica.

3

Preguntas sobre las extensiones. El CQual de Jeff Foster es muy bueno, y creo que podría hacer el trabajo que desee.

+0

¿Hay programas similares que todavía están activos (la última actualización de la página web de CQual fue en 2004) – CodeMonkey

14

Lo que quiere es lo que se llama "strong typedef" o "strict typedef".

Algunos lenguajes de programación [Rust, D, Haskell, Ada, ...] proporcionan algo de soporte a este nivel de lenguaje, C [++] no. Hubo una propuesta para incluirlo en el idioma con el nombre "opade typedef", pero no fue aceptado.

Sin embargo, la falta de soporte de idiomas no es realmente un problema. Simplemente ajuste el tipo alias en una clase nueva que tenga exactamente 1 miembro de datos, de tipo T. Gran parte de la repetición se puede tener en cuenta mediante plantillas y macros. Esta técnica simple es tan conveniente como en los lenguajes de programación con soporte directo.

1

con C++ 11 se puede utilizar una clase de enumeración, por ejemplo,

enum class char_idx_t : unsigned int {}; 
enum class byte_idx_t : unsigned int {}; 

El compilador aplicará una conversión explícita entre los dos tipos; es como una clase de envoltura delgada. Lamentablemente, no tendrá la sobrecarga del operador, p. si desea agregar dos char_idx_t juntos, tendrá que convertirlos a unsigned int.

+0

Véase la revisión de la propuesta (3) http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf – qub1n

Cuestiones relacionadas