2010-11-28 18 views
19

No estoy totalmente seguro de C, pero C++ permite campos de bits sin nombre de 0 longitud. Por ejemplo:Uso práctico de campos de bits de longitud cero

struct X 
{ 
    int : 0; 
}; 
  • Primera pregunta: ¿Qué usos prácticos de esta puede que pensar?
  • Pregunta dos: ¿Qué usos prácticos del mundo real (si los hay) conoce?

Editado el ejemplo después de la respuesta de hielo crimen

Editar: OK, gracias a las respuestas actuales que ahora saben el propósito teórico. Pero las preguntas se refieren a usos prácticos por lo que todavía mantienen :)

+1

C99 permite matrices de longitud cero para admitir mejor las estructuras de tamaño dinámico. – falstro

+0

@roe: Sí, bueno, es el equivalente de las matrices de 0 longitud asignadas dinámicamente, que son realmente útiles. Creo que el problema aquí es que la longitud del campo de bits debe ser una constante en tiempo de compilación. –

+6

@roe: Su comentario es incorrecto. C ** no permite ** 'char a [0];' en ninguna versión del estándar. Por otro lado, 'char a [];' está permitido en estructuras en C99; se llama miembro flexible de la matriz y debe aparecer al final. 'char a [];' es ** not ** a "abreviado para 'char a [0];' ". –

Respuesta

26

Utiliza un campo de bits de longitud cero para que el compilador diseñe una estructura que coincida con algún requisito externo, ya sea la noción del diseño de otro compilador o arquitectura (estructuras de datos multiplataforma, como un formato de archivo binario) o los requisitos de un nivel de bit (paquetes de red o códigos de operación).

Un ejemplo del mundo real es cuando NeXT transfirió el kernel xnu de la arquitectura Motorola 68000 (m68k) a la arquitectura i386. NeXT tenía una versión en funcionamiento de m68k de su kernel. Cuando lo trasladaron a i386, descubrieron que los requisitos de alineación del i386 diferían de los m68k de tal forma que una máquina m68k y una máquina i386 no coincidían en el diseño de la estructura BOOTP específica del proveedor NeXT.Para hacer que el diseño de la estructura i386 concuerde con el m68k, agregaron un campo de bit sin nombre de longitud cero para forzar que la unión estructura NV1/nv_U esté alineada con 16 bits.

Estas son las partes pertinentes de la Mac OS X 10.6.5 código fuente xnu:

/* from xnu/bsd/netinet/bootp.h */ 
/* 
* Bootstrap Protocol (BOOTP). RFC 951. 
*/ 
/* 
* HISTORY 
* 
* 14 May 1992 ? at NeXT 
* Added correct padding to struct nextvend. This is 
* needed for the i386 due to alignment differences wrt 
* the m68k. Also adjusted the size of the array fields 
* because the NeXT vendor area was overflowing the bootp 
* packet. 
*/ 
/* . . . */ 
struct nextvend { 
    u_char nv_magic[4]; /* Magic number for vendor specificity */ 
    u_char nv_version; /* NeXT protocol version */ 
    /* 
    * Round the beginning 
    * of the union to a 16 
    * bit boundary due to 
    * struct/union alignment 
    * on the m68k. 
    */ 
    unsigned short :0; 
    union { 
    u_char NV0[58]; 
    struct { 
     u_char NV1_opcode; /* opcode - Version 1 */ 
     u_char NV1_xid; /* transcation id */ 
     u_char NV1_text[NVMAXTEXT]; /* text */ 
     u_char NV1_null; /* null terminator */ 
    } NV1; 
    } nv_U; 
}; 
19

El estándar (9,6/2) sólo permite campos de bits de longitud 0 como un caso especial :

Como caso especial, una el campo de bits sin nombre con un ancho de cero especifica la alineación del siguiente campo de bits en una unidad de asignación límite. Solo cuando se declara un campo de bits sin nombre , la expresión constante puede tener un valor igual a hasta cero.

El único uso se describe en esta cita, aunque nunca lo he encontrado en el código práctico todavía.


Para el registro, he intentado el código siguiente en VS 2010:

struct X { 
    int i : 3, j : 5; 
}; 

struct Y { 
    int i : 3, : 0, j : 5; // nice syntax huh ? 
}; 

int main() 
{ 
    std::cout << sizeof(X) << " - " << sizeof(Y) << std::endl; 
} 

La salida en mi máquina es, en efecto: 4 - 8.

+4

Un ejemplo práctico: http://stackoverflow.com/questions/9229601/what-is-it-in-c-code – whitequark

5

Esto es de MSDN y no marcado como Microsoft específico, así que supongo que esto es común C++ estándar:

Un campo de bits sin nombre de la anchura de la alineación 0 fuerzas del campo de bits junto al siguiente límite de tipo, donde tipo es el tipo de miembro

6
struct X { int : 0; }; 

es un comportamiento indefinido en C.

Sede (el énfasis es mío):

(C99, 6.7.2.1p2) "La presencia de una struct-declaration-list en una struct-o-union-specifier declara un nuevo tipo, dentro de una unidad de traducción. declaración-lista es una secuencia de declaraciones para los miembros de la estructura o unión. Si la declaración de lista de estructura no contiene miembros nombrados, el comportamiento es indefinido "

(C11 tiene la misma redacción.)

Se puede utilizar un campo de bits sin nombre con 0 ancho pero no si no hay otro miembro nombrado en la estructura

por ejemplo:.

struct W { int a:1; int :0; }; // OK 
struct X { int :0; };   // Undefined Behavior 

por el camino para la segunda declaración, gcc emite un diagnóstico (no requerido por el estándar C) con -pedantic.

Por otro lado:

struct X { int :0; }; 

se define en GNU C. Se utiliza por ejemplo, por el núcleo de Linux (include/linux/bug.h) para forzar un error de compilación utilizando la siguiente macro si la condición es verdadera:

#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) 
+0

+1; quizás podría mencionar que http://stackoverflow.com/questions/9229601/what-is-in-c-code describe esa macro con más detalle. –