Hoy descubrí un comportamiento alarmante al experimentar con campos de bits. Por el bien de la discusión y la simplicidad, aquí es un programa de ejemplo:GCC, -O2 y bitfields: ¿se trata de un error o una característica?
#include <stdio.h>
struct Node
{
int a:16 __attribute__ ((packed));
int b:16 __attribute__ ((packed));
unsigned int c:27 __attribute__ ((packed));
unsigned int d:3 __attribute__ ((packed));
unsigned int e:2 __attribute__ ((packed));
};
int main (int argc, char *argv[])
{
Node n;
n.a = 12345;
n.b = -23456;
n.c = 0x7ffffff;
n.d = 0x7;
n.e = 0x3;
printf("3-bit field cast to int: %d\n",(int)n.d);
n.d++;
printf("3-bit field cast to int: %d\n",(int)n.d);
}
El programa está causando el propósito campo de bits de 3 bits se desborde. Aquí está la salida (correcto) cuando se compila utilizando "g ++ -O0":
3-bit fundido campo para INT: 7
3-bit fundido campo para INT: 0
Así es la salida cuando se compila utilizando "g ++ -O2" (y -O3):
3-bit fundido campo para iNT: 7
fundido campo de 3 bits a int: 8
Comprobación del montaje de este último ejemplo, encontré esto:
movl $7, %esi
movl $.LC1, %edi
xorl %eax, %eax
call printf
movl $8, %esi
movl $.LC1, %edi
xorl %eax, %eax
call printf
xorl %eax, %eax
addq $8, %rsp
Las optimizaciones han acaba de insertar "8", suponiendo 7 + 1 = 8, cuando en realidad el número desborda y es cero
Afortunadamente, el código que me importa no se desborda por lo que yo sé, pero esta situación me asusta: ¿se trata de un error conocido, una característica o es este comportamiento esperado? ¿Cuándo puedo esperar que gcc tenga razón sobre esto?
Editar (re: firmado/sin signo):
Está siendo tratado como sin firmar porque está declarado como sin signo. Declarar como int se obtiene la salida (con O0):
3-bits fundido campo para INT: -1
3-bits fundido campo para INT: 0
Un incluso lo más divertido sucede con O2 en este caso:
3-bits fundido campo a int: 7
3-bits fundido campo para iNT: 8
Admito que atributo es algo sospechoso de usar; en este caso, me preocupa una diferencia en la configuración de optimización.
chedcked gcc 4.4.1 - la salida es 7/0 con/sin optimización – dimba
Admito que estoy usando 4.1.2 - gracias por el aviso. – Rooke
¿Qué sucede si pones '__attribute __ ((__ packed __))' después de toda la estructura? –