Der skete noget sjovt...

Der skete noget sjovt på vej til GCC 4.2.

Hvor mange af jer kan forudsige hvad den her programstump printer, uden at prøve efter:

include

struct foo {
int i:1;
};

int
main(int argc, char **argv)
{
struct foo bar;

    bar.i = 1;

    printf("%d\n", bar.i);  
    return (0);  

}

Svaret kommer her, men lad være med at læse det før du har tænkt ordentligt over problemet:

Feltet 'i' i strukturen er et heltal med fortegn.

Hvis der kun er en bit til at lagre variablen i, bliver der kun plads til fortegnet.

Når man tildeler en værdi til en heltals variabel fra en anden heltalsvariabel bliver der ikke rundet af, der bliver sign-extended eller trunkeret og den binære værdi af feltet bliver derfor en sat bit.

I printf(3) kaldet blive feltet konverterte til en fuldbredde int af compileren ved signextension og på den måde bliver vores "plus en" til "minus en".

Hånden på hjertet, hvor mange af jer vidste det ?

phk

Kommentarer (16)
sortSortér kommentarer
  • Ældste først
  • Nyeste først
  • Bedste først
Casper Thomsen

Hej Ove.

Vores blog-system er desværre bygget sådan op, at bloggerne lige skal mærke af, at der er tale om et blog-indlæg og ikke en nyhedsartikel, hvilket styrer annoncerne på siden.

Nogle gange går det lidt hurtigt, og det er ikke altid, at man ser det i preview. Jeg har ændret indstillingen, så der nu kun er én annonce af den type på indlægget.

I den løbende udvikling af vores CMS arbejder vi på at gøre livet lettere for vores bloggere, så den slags fejl ikke kan ske. Annoncer på version2.dk er grundlaget for, at vi kan køre dette site, men de er der ikke for at irritere folk, så det skal der selvfølgelig være styr på.

Mvh Casper, Version2

  • 0
  • 0
Dennis Krøger

Heh, jeg kan bestemt ikke påstå at jeg lige havde regnet den ud, jeg begyndte at overveje om de havde lavet ting så den brugte de øverste bits, eller andre lige så forrykte ting (jeg havde en ret kraftig fornemmelse af at du ikke havde spurgt hvis svaret var "1")... :)

Men hvad har det at gøre specielt med 4.2?

  • 0
  • 0
Casper Thomsen

Hej Benjamin.

I takt med øget trafik på version2.dk forsøger vi også at forbedre systemets caching af sider. Den seneste udgave har dog vist sig at have en uheldig bivirkning på forsiden, som du - og mange andre - har bemærket.

Efter planen opgraderer vi i denne uge til forbedret sidecaching, der blandt andet betyder, at en nyhed på forsiden gerne skulle holde sig til én placering og ikke stjæle unødig spalteplads fra kammeraterne :-)

Mvh Casper, Version2

  • 0
  • 0
Gorm Jensen

Det havde jeg ikke lige gennemskuet, nej.
En gammel oplevelse har dog fået mig til at passe på med bit operationer i C. Så vidt jeg husker var problemet i >> 2, hvor det er udefineret om der skal "sign extendes" eller bare fyldes nuller ind.

Med venlig hilsen
Gorm Vognsen Jensen

  • 0
  • 0
Poul-Henning Kamp Blogger

Jeg ved faktisk ikke hvorfor det var GCC4.2 der bragte dette i fokus i FreeBSD, men sandsynligvis er det vores brug af -Werror der fik det frem, sammen med strengere check i GCC4.2

Personligt bruger jeg aldrig bitfelter i C, for jeg synes definitionen af dem er ubrugelig, hvert fald når man vil skrive portabel kode der skal rode rundt med hardware.

Poul-Henning

PS: Undskyld det sene svar & Undskyld til Casper fordi jeg glemte at sætte alle de magiske options, der er lidt vel meget tryk på her fortiden og et lidt højt murphyfelt.

  • 0
  • 0
Karsten Nyblad

En af mine kæpheste indenfor sprogdesign er, at man skal undgå automatisk typeconvertering, eller hvad det nu hedder på de enkelte sprog. Der ligger mange muligheder for fejl gemt, som er sværre at se. Hvad er der f.eks. galt med denne her kode:

int x;
double y;
y = (float)x;

Jeg fandt eksemplet i noget kode, hvor det var tydeligt, at programmøren vidste noget var galt, men på trods af det, opdagede han ikke, hvad han havde gjort galt.

En anden gang kunne jeg ikke selv finde en fejl i et 50 linier langt Pascal program. Koden var noget i retning af:

i, j : integer;
d : double;

d := i/j;

Fejlen var, at jeg dividere to heltal med hinanden og fik en 4 bytes real, som så blev konverteret til en 8 byte real. Jeg fandt først ud af, hvad der var galt, da jeg skrev assemblerkoden ud, og husk lige på, at programmet var på ca 50 linier.

Eller hvad er betydningen af:

short i,i;
long k;

k = i*j;

Skal i og j laves om til long før de ganges, eller skal i og j ganges og resultatet trunkeres til hvad der kan være i en short, før resultatet lægges i k? Det varierer fra sprog til sprog, og nogen gange har nært beslægtede sprog ikke samme regler, eller det er implementeringsafhængigt. F.eks. har C og C++ ikke de samme regler. Under alle omstændigheder er løsningen, hvor produktet trunkeres til, hvad der kan være i en short, en oplagt kilde til programmeringsfejl, for hvilken programmør ville tænke over, at det er sådan.

  • 0
  • 0
Log ind eller Opret konto for at kommentere