Bitfält i C

Elektronik- och mekanikrelaterad mjukvara/litteratur. (T.ex schema-CAD, simulering, böcker, manualer mm. OS-problem hör inte hit!)
Användarvisningsbild
cykze
EF Sponsor
Inlägg: 1539
Blev medlem: 8 april 2004, 10:40:28
Ort: Uppsala

Bitfält i C

Inlägg 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
cyr
Inlägg: 2712
Blev medlem: 27 maj 2003, 16:02:39
Ort: linköping
Kontakt:

Inlägg av cyr »

Är det inte bara för att kompilatorn paddar ut den till jämna 32bitars ord?
Användarvisningsbild
cykze
EF Sponsor
Inlägg: 1539
Blev medlem: 8 april 2004, 10:40:28
Ort: Uppsala

Inlägg av cykze »

cyr: Ändrar jag de två första 5:orna till 4:or så blir sizeof = 3, så det är nog inte det.
cyr
Inlägg: 2712
Blev medlem: 27 maj 2003, 16:02:39
Ort: linköping
Kontakt:

Inlägg 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.
Användarvisningsbild
cykze
EF Sponsor
Inlägg: 1539
Blev medlem: 8 april 2004, 10:40:28
Ort: Uppsala

Inlägg av cykze »

Den förklaringen köper jag. :)

avr-gcc verkar dock göra som jag vill.
gille
Inlägg: 69
Blev medlem: 28 november 2004, 18:06:09
Ort: Stockholm
Kontakt:

Inlägg 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.
Användarvisningsbild
cykze
EF Sponsor
Inlägg: 1539
Blev medlem: 8 april 2004, 10:40:28
Ort: Uppsala

Inlägg 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.
henkebenke
Inlägg: 515
Blev medlem: 31 maj 2003, 10:42:37
Ort: Helsingborg

Inlägg 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.
sodjan
EF Sponsor
Inlägg: 43243
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg 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å...
Användarvisningsbild
Abra Hana
Inlägg: 94
Blev medlem: 12 maj 2005, 13:20:58

Inlägg 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 .


*
sodjan
EF Sponsor
Inlägg: 43243
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg 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.
Användarvisningsbild
Abra Hana
Inlägg: 94
Blev medlem: 12 maj 2005, 13:20:58

Inlägg 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]
Användarvisningsbild
Icecap
Inlägg: 26624
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg 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.....
sodjan
EF Sponsor
Inlägg: 43243
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg 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...
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 46881
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Inlägg 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.
Skriv svar