2010-01-24 17 views
13

que necesita para empacar algunos bits en un byte de esta manera:C/C++ bitfields versus operadores bit a bit para seleccionar bits individuales, ¿qué es más rápido, mejor y más portátil?

struct 
{ 
    char bit0: 1; 
    char bit1: 1; 
} a; 

if(a.bit1) /* etc */ 

o:

if(a & 0x2) /* etc */ 

Desde la claridad del código fuente que es bastante obvio para mí que son campos de bits más ordenado. Pero, ¿qué opción es más rápida? Sé que la diferencia de velocidad no será demasiado si la hay, pero como puedo usar cualquiera de ellos, si uno es más rápido, mejor.
Por otro lado, he leído que no se garantiza que los campos de bits organicen bits en el mismo orden en todas las plataformas, y quiero que mi código sea portátil.

Notas: Si planeas responder "Perfil" bien, lo haré, pero como soy flojo, si alguien ya tiene la respuesta, mucho mejor.
El código puede estar equivocado, puede corregirme si lo desea, pero recuerde cuál es el punto de esta pregunta y por favor intente y responda también.

+0

Puede estar interesado en http://stackoverflow.com/questions/1044654/bitfield-manipulation-in-c. Hay al menos otra pregunta muy similar de la que recuerdo haber comentado (no parece ser esta). –

+0

Bitfields: ¡estás fuera! Gracias a todos. – Petruza

+0

Wow. Enseñamos una valiosa lección aquí. –

Respuesta

6

Preferiría usar el segundo ejemplo en preferencia por la máxima portabilidad. Como señaló Neil Butterworth, el uso de bitfields es solo para el procesador nativo. Ok, piensen en esto, ¿qué pasa si el x86 de Intel dejara de funcionar mañana, el código se bloqueará, lo que significa tener que volver a implementar los campos de bits para otro procesador, digamos RISC?

Tienes que ver la imagen más grande y preguntar cómo logró OpenBSD portar sus sistemas BSD a muchas plataformas usando una sola base de código. Vale, admito que es un poco exagerado, discutible y subjetivo, pero hablando de forma realista, si quieres transferir el código a otra plataforma, es la manera de hacerlo usando el segundo ejemplo que usaste en tu pregunta .

No solo eso, los compiladores para diferentes plataformas tendrían su propia forma de relleno, alineando bitfields para el procesador donde está el compilador. Y, además, ¿qué pasa con la endianess del procesador?

Nunca confíe en bitfields como una bala mágica. Si desea velocidad para el procesador y se fijará en él, es decir, no tiene intención de transferir, puede utilizar los campos de bits. ¡No puede tener ambas cosas!

+0

+1: No es solo que no tiene intención de portar, es que no tiene la intención de utilizar todo el contenido de la variable como un entero (frente a bits individuales) en cualquier contexto en lugar de en la memoria de un procesador. Si envía el valor entero de una estructura de campo de bits a un disco, a través de la red o a algún periférico del sistema integrado, es mejor que se asegure de que el compilador ubique los campos de bits en el orden correcto. –

+6

¿Desea explicar cómo el uso de bitfields integrados sobre los definidos manualmente es más portátil? Puedo creerlo si confía en que el diseño de la memoria de la estructura se establezca de una manera muy cierta, pero si todo lo que hace es acceder a cada campo a través de la sintaxis incorporada, no veo ningún problema de portabilidad. –

+0

La matriz es incorrecta, no es un problema de portabilidad de la CPU, es un problema de portabilidad del compilador. Cada compilador es libre de alinear bitfields de la forma que quiera, lo que significa que el código compilado con dos compiladores diferentes no puede vincularse entre sí y compartir datos que contengan bitfields. Hacer el enmascaramiento y cambiarse a ti mismo elimina este problema. – naasking

4

Si desea portabilidad, evite los campos de bits. Y si está interesado en el rendimiento de un código específico, no hay alternativa a escribir sus propias pruebas. Recuerde, Bitfields usará las instrucciones bit a bit del procesador debajo del capó.

+0

¿Por qué, aparte del orden de bitfields, los bitfields no serían portátiles? También algunos procesadores admiten inserción/extracción de bitfield. El 68020 lo hizo, por ejemplo. –

+3

También hay problemas de embalaje. Y solo porque un procesador tiene una instrucción de propósito especial, no hay garantía de que el compilador lo use, es por eso que dije que una prueba es esencial. –

+2

Ah, pero solo porque un campo de bits podría usar más o menos espacio según la implementación no lo hace no portátil. Y si un compilador no aprovecha lo que el procesador puede hacer, debería ser mejorado o reemplazado. –

1

Creo que un programador C tenderá hacia la segunda opción de usar máscaras de bits y operaciones lógicas para deducir el valor de cada bit. En lugar de tener el código lleno de valores hexadecimales, las enumeraciones se configurarían o, por lo general, cuando se trata de operaciones más complejas, macros para obtener/establecer bits específicos. He escuchado en la vid, que los campos de bit implementados de la estructura son más lentos.

+0

Más al punto, no se garantiza que los campos de bits estén en orden en todas las plataformas. Entonces, si está utilizando un campo de bits para un registro de hardware, tendrá dificultades para depurar por qué su hardware no está haciendo lo que debería. –

5

El primero es explícito y sea cual sea la velocidad, la segunda expresión es propensa a errores porque cualquier cambio en su estructura puede hacer que la segunda expresión sea incorrecta.

Utilice el primero.

+0

No. La primera usa una característica inusual que la mayoría de los codificadores nunca tocan y no entienden, mientras que la segunda es simplemente idiomática C. Por lo tanto, es la segunda opción más clara sobre su intención y menos probable que se rompa por descuido mantenedores. – Porculus

+0

Lo único que está mal con la segunda expresión es que '0x02' necesita ser una constante definida para que el desarrollador sepa lo que significa. Lo que está mal con la primera es que el compilador puede poner los dos bits en el byte de 8 bits donde quiera. El kernel de Linux define un conjunto completo de constantes para declarar el orden y el empaquetamiento de los bits, lo que conduce a bloques '# ifdef' difíciles de mantener. Y eso es suponiendo que la plataforma define 'char' como 8 bits; Me he desarrollado para plataformas que definían 'char' como 16 bits porque el DSP no podía abordar bytes, solo palabras. –

12

Los campos de bits hacen que el código sea mucho más claro si se usan de forma adecuada. Yo usaría bitfields solo como un dispositivo de ahorro de espacio. Un lugar común en el que los he visto es en los compiladores: a menudo, la información de tipo o símbolo consiste en un grupo de indicadores de verdadero/falso. Los bitfields son ideales aquí ya que un programa típico tendrá muchos miles de estos nodos creados cuando se compile.

No utilizaría bitfields para hacer un trabajo de programación incrustado común: leer y escribir registros de dispositivos. Prefiero usar turnos y máscaras aquí porque obtienes exactamente los bits que la documentación te dice que necesitas y no tienes que preocuparte por las diferencias en la implementación de varios bitios de los compiladores.

En cuanto a la velocidad, un buen compilador dará el mismo código para los campos de bits que el enmascarado.

+0

El problema con el uso de bitfields es que no tiene garantía de que ahorrará espacio. El compilador podría asignar 32 bits para cada campo de bits, como si hubiera sido un int. ¿Por qué no? Será más rápido en la mayoría de los casos. – jalf

+0

Derecha. pero podría ahorrar espacio. Cualquier persona inteligente cuenta con bitfields para hacer eso. –

+0

@jaif: llamo BS. ¿Tiene algo que apoye esa afirmación? Soy demasiado flojo para mirar las especificaciones, pero realmente dudo que eso esté permitido. – SoapBox

6

C bitfields nacieron muertos desde el momento en que se inventaron, por razones desconocidas. A la gente no les gustó y usó operadores bit a bit en su lugar. Tienes que esperar que otros desarrolladores no entiendan el código de bit de C.

Con respecto a cuál es más rápido: irrelevante. Cualquier compilador de optimización (lo que significa prácticamente todo) hará que el código haga lo mismo en cualquier notación. Es un concepto erróneo común de los programadores C que el compilador simplemente busque y reemplace las palabras clave en el ensamblado. Los compiladores modernos usan el código fuente como un plan para lo que se debe lograr y luego emiten un código que a menudo se ve muy diferente pero que logra el resultado deseado.

1

No lea mucho en los "campos de bits no portátiles". Hay dos aspectos de los campos de bits que están definidos por la implementación: la firma y el diseño y uno no especificado: la alineación de la unidad de asignación en la que están empaquetados. Si no necesita nada más que el efecto de embalaje, usarlos es tan portátil (siempre que especifique explícitamente una palabra clave signed cuando sea necesario) como llamadas a funciones que también tienen propiedades no especificadas.

En cuanto al rendimiento, el perfil es la mejor respuesta que puede obtener. En un mundo perfecto, no habría diferencia entre las dos escrituras. En la práctica, puede haber algunos, pero puedo pensar en tantas razones en una dirección como en la otra. Y puede ser muy sensible al contexto (diferencia lógicamente sin sentido entre sin firma y firmada por ejemplo) así que mida en contexto ...

En resumen, la diferencia es principalmente una diferencia de estilo en los casos donde realmente tiene la opción (es decir, no si el diseño preciso es importante). En esos casos, se trata de una optimización (en tamaño, no en velocidad) y, por lo tanto, tendía primero a escribir el código sin él y agregarlo después si fuera necesario. Por lo tanto, los campos de bits son la elección obvia (las modificaciones que se deben realizar son las más pequeñas para lograr el resultado y están contenidas en el lugar único de definición en lugar de extenderse a todos los lugares de uso).

Cuestiones relacionadas