C data types, tar knäcken på mig

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: C data types, tar knäcken på mig

Inlägg av sodjan »

Allt har två sidor. På de flesta arkitekturer är det snabbare att köra med den
storlek som passar arkitekturen bäst och låta kompilatorn välja en optimal
storlek på "int". På större maskiner kan det vara snabbare att hantera 32
eller 64 bitars heltal än 8 eller 16.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: C data types, tar knäcken på mig

Inlägg av jesse »

Kompilatorn kan ju inte veta vad som är optimal storlek för en "int" i mitt program. Om jag behöver 32 bitar så anger jag det, annars anger jag 16 bitar. Det tar inte mera kraft för en 32-bitars processor att hantera 16-bitars int (eftersom det då automatiskt blir 32 bitars i alla fall).
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: C data types, tar knäcken på mig

Inlägg av sodjan »

Jorå, det kan det visst göra. Man kan få "alignment faults" och liknande fenomen.
Processorn kanske måste dela ett 32 eller 64 bitars ord i mondre delar o.s.v.
Om du t.ex gör en struct med 2 16-bit tal så kan de hamna intill varandra
(om man inte ber kompilatorn att utföra alignment och lägga varje
struct del på en jämn adress.

> Kompilatorn kan ju inte veta vad som är optimal storlek för en "int" i mitt program.

Nej, men den vet normalt vad som är optimalt på den aktuella arkitekturen.
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 46920
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Re: C data types, tar knäcken på mig

Inlägg av TomasL »

Kompilatorn är ju naturligtvis optimerad för den arkitektur och ordlängd för processorn den är avsedd för, konstigt vore väl annars.
Jobbar du med en 8-bitars processor, så är kompilatorn optimerad för just detta, samma gäller 16, 32 och 64-bitars prollar.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: C data types, tar knäcken på mig

Inlägg av jesse »

Jo, exakt. Därför kan jag ju bättre själv välja vilken längd jag vill ha på en int. T.ex 8 bitar eller 64 bitar. Sedan optimerar kompilatorn detta till arkitekturen. Men det finns ju inget smart med att den bara trunkerar bort halva mitt 64-bitars tal bara för att 32 bitar passar bättre i arkitekturen, dessutom utan att jag vet om det, om jag inte särskilt inför varje kompilering tar reda på hur många bitar jag råkar få lov att använda just då.
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 46920
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Re: C data types, tar knäcken på mig

Inlägg av TomasL »

Nja, om du använder det som är optimalt för arkitekturen i fråga, slipper kompilatorn att generera en massa extra kod.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: C data types, tar knäcken på mig

Inlägg av jesse »

Så du kör vanligtvis med 32 bitars variabler överallt , även om det skulle duga med en 8-bitars?

t.ex.

Kod: Markera allt

for (uint32_t i = 0; i < 10; i++) { ... kod ... }
hellre än

Kod: Markera allt

for (uint8_t i = 0; i < 10; i++) { ... kod ... }
Du tror inte att kompilatorn ändå snurrar ett 32-bitars register, och därmed blir det ingen skillnad?
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 46920
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Re: C data types, tar knäcken på mig

Inlägg av TomasL »

Naturligtvis inte, eftersom den kan packa variabler och gör det.
Men kunskap om hur olika saker optimeras är rätt bra, speciellt om man får ont om plats.
sodjan
EF Sponsor
Inlägg: 43247
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: C data types, tar knäcken på mig

Inlägg av sodjan »

Problemet har med alignment att göra. Processorn kan få lägga extra
tid på att fixa till mindre variabler som har hamnat i samma "native word"
eller en variable som är delad över två "words".

Nu så kan "member alignment" ju vara default för kompilatorn, och
då kommer den att lägga in dummy utrymme i structen så att datat
ligger på naturliga adresser för den aktuella data typen. T.ex en struct
med en char med en long direkt efter så kommer det att läggas till 3 st
dummy bytes mellan char'en och long'en, så att longen blir "aligned".
Visst, det tar lite mer plats än vad man kanske trodde, men det
blir snabbare.

En long som inte ligger på ett jämt "longword" är väldigt ineffektivt. Det
blir dubbla minnesaccesser och ett pusslande med två halvor.
gkar
Inlägg: 1584
Blev medlem: 31 oktober 2011, 15:28:29
Ort: Linköping

Re: C data types, tar knäcken på mig

Inlägg av gkar »

thebolt skrev:
gkar skrev: Är det så?! Visa mig texten i standarden som specificerar long till minst 32bitar.
ISO/IEC 9899:TC2
"5.2.4.2.1 Sizes of integer types <limits.h>
— minimum value for an object of type long int
LONG_MIN -2147483647 // −(231 − 1)
— maximum value for an object of type long int
LONG_MAX +2147483647 // 231 − 1
— maximum value for an object of type unsigned long int
ULONG_MAX 4294967295 // 232 − 1
"
Dvs en long måste vara minst 32 bitar.

Tackar!
gkar
Inlägg: 1584
Blev medlem: 31 oktober 2011, 15:28:29
Ort: Linköping

Re: C data types, tar knäcken på mig

Inlägg av gkar »

jesse skrev:Kompilatorn kan ju inte veta vad som är optimal storlek för en "int" i mitt program. Om jag behöver 32 bitar så anger jag det, annars anger jag 16 bitar. Det tar inte mera kraft för en 32-bitars processor att hantera 16-bitars int (eftersom det då automatiskt blir 32 bitars i alla fall).
Jo, det går långsammare på många RISCar, även x86 för den delen, men av en annan anledning, och nej det sker inte automatiskt i alla fall.
Får se om jag kan förklara detta enkelt?

Det ena fallet:
I en 32 bitars RISC finns bara 32 bitars ALU, inget konstigt med det, det är en RISC.
Dvs allt kommer att vara 32 bitars när man räknar med det, men måste bete sig exakt som 16 bitars variabler om man specificerat det i koden.

Lite fulkod...
void foo(int32_t b, int32_t c, inte32_t d){
short a;
volatile apa;
for (a = b; a != 0; a+=d){
apa = 0;
}
}

Hur många varv skall vi lopa egentligen?

Låt oss kompilera detta för ARM likadant som ARMs SDT kompilator skulle ha gjort.

mov r4, r0 ; a = 0

label:
...
...

add r0, r0, r1 ;a+=d
mov r0, r0 lsl #16 ; ARM löser detta med 2st skiftningar eftersom and r0,r0,0xffff inte finns direkt tillgängligt.
mov r0, r0, lsr #16
cmp r0,r2

Dessa 16 bitars skiftningar(maskning) måste utföras eftersom vi bara skall göra jämförelse med de undre 16 bitarna och det bla kan finnas ettor i d som är 32 bitar.
Detta eftersom variabeln är registeroptimerad.


Det andra fallet är tex X86, instruktionsmässigt behövs inte maskningen, eller skiftningarna. Processorn har 16 bitars stöd i instruktionsuppsättningen.
Dock är fortfarande ALU numera 32bitar+, 16 bitars aritmetik emuleras och orsakar låsningar i pipelinen. Intel säger inte så mycket men gissningsvis orsakar det en read-modify-write historia i registerfilen.
Detta varierar mellan X86 tillverkare och generation, men långsamma 16bitare har vi haft nu sedan millenieskiftet.

Slutligen:

Om vi har 16 bitarsvariabler på en risc (ARM) och vi råkar ha högt registertryck(så att en vanlig diskret 16_t hamnar på stacken) eller vi har datat i en array[] eller vi har specificerat att variabeln skall vara volatile, eller vi har tagit adressen på den, kommer den att hamna i minnet.

På moderna ARMar finns stöd för LDRH/STRH (Ladda och skriv 16 bitars,) på de äldre saknas detta helt.
Då behövs inte maskningen, eftersom vi skriver tillbaka värdet helatiden till minnet med 16 bitars accesser. Detta blir dock långsamt eftersom vi skriver mot minnet ofta, men 32 bitars data hade också varit långsamt.
Med 16 bitars data kan det ta en extra late cycle(risk för pipelinebubbla) beroende på ARM eftersom den behöver göra sign eller zero extend vid inläsningen.
Om det kommer att ta en extra cykel i praktiken beror på om vi har någon annan instruktion utan databeroende att exekvera under tiden.


Så vad skall man göra om man vill skriva effektiv kod.

Ryms datat i 16 bitar och man inte är beroende på MSB overflow (add, lsl etc) använd int.
Ryms det inte, använd long.
Måste du har en viss storlek, använd den(int16_t, int32_t etc), men det kanske inte kommer att att exekveras optimalt på alla plattformar.

Sedan är ju läsbarhet och kodstandard etc en annan historia...

Mer glögg!
thebolt
Inlägg: 248
Blev medlem: 10 februari 2008, 17:41:40
Ort: Taipei Taiwan

Re: C data types, tar knäcken på mig

Inlägg av thebolt »

jesse skrev:Det är väl det största misstaget i C-språkets historia att de inte definierade heltalstyperna fast. Det hade inte varit svårt att uppkalla dem efter antal bitar, eller varför inte antal bytes? Är det lika tokigt i C++ och C# att de har ärvt denna förvirring?
Nu har ju C99 korrigerat detta genom att införa de storleksfasta versionerna (u)int8_t, (u)int16_t osv samt diverse andra versioner så som (u)int_least16_t (typ med minst 16 bitar) och (u)int_fast16_t ("type being usually fastest on architecture with at least 16 bits") samt motsvarande defines i limit.h med deras område.
Användarvisningsbild
MiaM
Inlägg: 12780
Blev medlem: 6 maj 2009, 22:19:19

Re: C data types, tar knäcken på mig

Inlägg av MiaM »

ekman skrev:Nä för att testa. Jag såg inte varför det inte skulle funka, så jag testade. Så nu har jag lärt mig lite mer hur Char fungerar :)
Fast det här är ju inte specifikt för char, utan felet är att unsigned long start_sector; är en enkel variabel medan unsigned char start_sector[4]; är en array om fyra variabler och arrayer hanteras syntaxmässigt som pekare till variabler istället för som en vanlig variabel.

Du skulle få samma fel om du bytte ut unsigned long start_sector; mot unsigned long start_sector[1];

Det här är väl ett av de vanligaste nybörjarfelen när man håller på med C, och dessutom är det nog ett av skälen till att folk helt enkelt inte orkade lära sig C när de använde PC-burkar på den tiden de flesta körde operativsystem utan vettigt minnesskydd (DOS och eventuellt windows 3.x) eftersom fel ofta ledde till att hela burken tvärhängde.

Man kan för övrigt tycka att de flesta läroböcker är rätt usla på att förklara detta - man undrar om de som skrivit böckerna verkligen till 100% förstår vad som händer?

Det blir ju inte lättare för nybörjare att lära sig när *foo = 42 och foo[0] = 42 gör samma sak. :wink:
Användarvisningsbild
bit96
Inlägg: 2528
Blev medlem: 3 september 2007, 10:04:29
Ort: Säffle

Re: C data types, tar knäcken på mig

Inlägg av bit96 »

Väldig förvirrande är ju att a == b[a].
Det brukar sätta griller i huvudet på många att man byta plats på fältets namn och indexet.
Hur kan indexet plötslig bli ett fält, och hur kan fältet, som just fattat är en pekare(minnesadress) plötsligt bli ett index?

Men a beräknas som *(a+b), d.v.s. "adressen a + offset b, och hämta värdet på den nya beräknade adressen"
Efter som det är en addition spelar det ju ingen roll om vi kastar om a och b, *(b+a) blir samma sak.

Men det rekommendera inte att göra så vid "normal" programmering. :)
hummel
Inlägg: 2535
Blev medlem: 28 november 2009, 10:40:52
Ort: Stockholm

Re: C data types, tar knäcken på mig

Inlägg av hummel »

Om du undviker int, long osv och i stället definierar upp INT8, INT16 osv så kan du även byta/uppgradera kompilator och endast modifiera dina typ definitioner.
Skriv svar