Sida 1 av 2
Bitfält i C
Postat: 31 oktober 2006, 17:53:29
av cykze
Det är inte så ofta jag använder bitfält i C, men nu skulle jag behöva ett. Provade lite och kom fram till lite konstiga saker. Nu har jag iaf stött på en underlighet. Koden nedan skriver ut att storleken på structen är 4, istället för 3 som jag tycker den borde vara.
5 + 5 + 5 + 1 + 1 + 1 + 1 = 19
19bitar / 8 = 2.375 bytes, dvs det krävs 3 hela bytes för att hålla 19 bitar.
Har jag missat något väsentligt?
Kod: Markera allt
#include <stdio.h>
struct Time
{
unsigned char
b0 : 5,
b1 : 5,
b2 : 5,
b3 : 1,
b4 : 1,
b5 : 1,
b6 : 1;
};
int main()
{
printf("sizeof(Time) = %d\n", sizeof(struct Time));
return 0;
}
edit: Testat med gcc 3.4, 4.0 och 4.1
Postat: 31 oktober 2006, 18:17:30
av cyr
Är det inte bara för att kompilatorn paddar ut den till jämna 32bitars ord?
Postat: 31 oktober 2006, 18:44:09
av cykze
cyr: Ändrar jag de två första 5:orna till 4:or så blir sizeof = 3, så det är nog inte det.
Postat: 31 oktober 2006, 18:52:52
av cyr
OK, ny teori
Förmodligen gillar inte kompilatorn att ha ett bitfält som är utspritt över två byte.
Så det skapas 4 byte, 3 med 5 bitar använda och den sista med de övriga 4 bitarna.
Postat: 31 oktober 2006, 21:07:12
av cykze
Den förklaringen köper jag.
avr-gcc verkar dock göra som jag vill.
Postat: 31 oktober 2006, 22:03:03
av gille
Det är inte så klurigt.
Ett svar är att man oftar paddar till jämna 32-bits gränser, men det behövs inte i AVR.
Om du definerar de första som 5 bitar kommer den läggas ut såhär:
byte 0: b0
byte 1: b1
byte 2: b2, b3, b4, b5
byte 3: b6
Vilket ger 4 bytes.
Om du definierar som 4 bits blir det:
byte 0: b0, b1
byte 1: b2, b3, b4, b5
byte 2: b6
Om du skyfflar om lite kan du packa in det bättre.
Eventuellt kan __attribute__ ((packed)) i slutet av strukten även minska storleken. Det är iofs ett GCC direketiv så det kommer inte fungera i en annan kompilator.
Postat: 31 oktober 2006, 22:21:40
av cykze
Gäller det där du skriver bara för GCC? Efter att ha läst lite mer på internet så verkar det som att det är upp till kompilatorn hur bitarna ska läggas ut.
Postat: 31 oktober 2006, 23:29:05
av henkebenke
Hur bit-fields hanteras är helt kompilatorberoende, hur det är praktiken låter jag vara osagt.
K&R har iallafall lämnat den biten ospecad. Däremot säger de att det måste vara int och att de inte har adresser. Men det finns kompilatorer som avviker från standarden på dessa punkter.
IAR använder bit-fields för adressering av portpinnar på m16c iallafall, där SFR:erna går att bitadressera.
Postat: 31 oktober 2006, 23:29:38
av sodjan
> det är upp till kompilatorn hur bitarna ska läggas ut.
Helt rimligt. Det är ju helt beroende på vilken hårdvaruarkitektur som
kompilatorn skapar kod till. Skulle vara konstigt om de i C-standarden
skulle space det på bit-nivå...
Postat: 1 november 2006, 16:20:50
av Abra Hana
*
Nej , jag tror inte på att det är olika kompilatorn bestämmer olika hur bitarna ska läggas in .
visual C++ 6 standard visar ju samma resultat . altså .
-----------------------------------------------------------------------------
#include <stdio.h>
struct Time
{
unsigned char
b0 : 5,
b1 : 5,
b2 : 5,
b3 : 1,
b4 : 1,
b5 : 1,
b6 : 1;
};
int main()
{
printf("sizeof(Time) = %d\n", sizeof(struct Time));
return 0;
}
resultatet är : sizeof(Time) = 4 .
-------------------------------------------------------------------------------
Jag tror att det används nån bestämd C standard kompilerings algoritm för att räkna storleken på en structure som innehåller medlemmar som betraktas som datatyp bit .
min gissning är :
b1 + b2 = 10 bitar = 8 bitar + 2bitar =>
=> 1byte för 8 bitar + 1 byte för 2 bitar = 2 bytes
b2 + b3 + b4 + b5 = 8 bitar = 1 byte för 8 bitar = 1 byte .
b6 = 1bit = lagras i en byte = 1byte
resultatet blir 4 .
*
Postat: 1 november 2006, 16:57:49
av sodjan
> Nej , jag tror inte på att det är olika kompilatorn bestämmer olika hur bitarna ska läggas in .
Kan du skriva om det där så att det framgår vad du menar.
Att du har hittat två kompilatorer som gör likadant bevisar ingenting.
Postat: 1 november 2006, 17:31:23
av Abra Hana
*
Det jag menade är att :
----------------------------------------------------------------------------------
>henkebenke skrev :
Hur bit-fields hanteras är helt kompilatorberoende.
--------------------------------------------------------------------------------
-------------------------------------------------------------------------------
> och du ( sodjan ) skrev:
det är upp till kompilatorn hur bitarna ska läggas ut.
Helt rimligt. Det är ju helt beroende på vilken hårdvaruarkitektur som
kompilatorn skapar kod till. Skulle vara konstigt om de i C-standarden
skulle space det på bit-nivå
-----------------------------------------------------------------------------
Och Jag , demokratiskt bestred denna teori
(olika kompilatorn bestämmer olika hur bitarna ska läggas in . )
Det jag menade är att det kan finnas ett bestämt kompilerings algoritm som alla C kompilatorer måste följa ( beroende på plattform ) för att räkna storleken på en structure beroende av dess data medlemmar .
> sodjan du skrev :
Att du har hittat två kompilatorer som gör likadant
bevisar ingenting.
Dessa två kompilatorer är nog för mycket för att avgöra saken .
GCC kompilatorn : dominerar helt i lunix unix världen .
Visual C++ kompilatorn : dominerar helt i windows världen .
[/b]
Postat: 1 november 2006, 17:39:25
av Icecap
"Visual C++ kompilatorn : dominerar helt i windows världen"???
Om det är M$ Visual C++ du menar är du ganska fel ute, den har inte ett bra rykte och den dominerar definitivt inte heller.....
Postat: 1 november 2006, 17:41:43
av sodjan
> "olika kompilatorn bestämmer olika hur bitarna ska läggas in"
Den där "teorin" är något du själv har hittat på! Ingen har sagt så här.
(Om jag tolkar din meningsbyggnad rätt...)
Att något är kompilatorberoende betyder ju inte att det
*måste* vara olika...
Och att använda en Microsoft produkt för att bevisa en standard !?
Kreativt men lite vågat, skulle jag säga...
Notera också att med "standard" avses att det finns dokumenterat i
en gällande överenskommelse. Det räcker inte med att alla (?)
kompilatorer *i praktiken* gör på ett visst sätt...
Postat: 1 november 2006, 19:01:23
av TomasL
Citat från K&R, svenska upplagan.
Nästan allt som rör (bit)fält är implementationsberoende. Huruvida fält får överlappa en ordgräns är implementationsdefinerat...........Den speciella bredden 0 används för att framtvinga placering vid nästa ordgräns.................Fält får deklareras endast som int. sppecificera för portabilitetens skull uttryckligen signed eller unsigned.
Som jag tolkar det, så är deklarationen felaktig, det skall vara "unsigned int" istället för "unsigned char", så kompilatorn skall egenteligen ge ett felmedelande.
Sedan är det tydligen helt upp till kompilatorn att bestämma hur mycket plats fältet tar.