Enkla men fatala buggar

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Enkla men fatala buggar

Inlägg av blueint »

När skillnad i precedens saknas skall det evalueras från vänster till höger.

Det svåra är väl att tänka igenom uttrycken och att en del kompilatorer inte följer standard. En genväg är då att använda explicita paranteser för att tvinga igenom precedens. Men det kan bli många paranteser..
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 45168
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Re: Enkla men fatala buggar

Inlägg av TomasL »

Nja, det finns inget krav i C-standarden om det, vill jag minnas, utan är plattforms/kompilator beroende.
K&R skrev:The moral is that writing code that depends on order of evaluation is bad programming practice in any language
Ta till exempel

Kod: Markera allt

X = f() + g();
F kan evalueras före g eller viceversa, så om då en av funktionerna påverkar variabler som används i den andra, kan vad som helst hända.
Samma gäller till exempel:

Kod: Markera allt

printf ( "%d %D\n", ++n, power(2,n));
a[i] = i++;
Ovanstående två exempel ger vilt skilda resultat beroende på kompilatorn, och kan faktiskt ge olika resultat mpå samma kompilator, vid två påföljande kompileringar.
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Enkla men fatala buggar

Inlägg av blueint »

Följer program inte specifikationer så kan vad som helst hända.. :vissla:
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 45168
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Re: Enkla men fatala buggar

Inlägg av TomasL »

Vilka specifikationer?
Användarvisningsbild
jesse
Inlägg: 9233
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Enkla men fatala buggar

Inlägg av jesse »

blueint skrev:Följer program inte specifikationer så kan vad som helst hända.. :vissla:
Följer man inte goda råd så kan vad som helst hända.... t.ex. att man struntar i att använda parenteser.
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Enkla men fatala buggar

Inlägg av blueint »

C89, C90, C99, C11 osv. Man kan förstås välja att inte följa dessa. Men då får skaparen av kompilatorn vara tydlig med detta.
Användarvisningsbild
sodjan
EF Sponsor
Inlägg: 43148
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping
Kontakt:

Re: Enkla men fatala buggar

Inlägg av sodjan »

Problemet är när specen säger "unspecified" eller "undefined".
Användarvisningsbild
Andax
Inlägg: 4373
Blev medlem: 4 juli 2005, 23:27:38
Ort: Jönköping

Re: Enkla men fatala buggar

Inlägg av Andax »

Oavsett om man följer standarden eller inte så är det dålig programmering att inte vara tydlig i vad som görs. Så kör man utan parenteser anser jag att koden är ofullständig och dålig.
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Enkla men fatala buggar

Inlägg av blueint »

Står det "unspecified" eller "undefined" så kör man stenhårt med paranteser. Kanske man t.om slänger in en enkel funktion som kontrollerar att kompilatorn gör rätt.
superx
Inlägg: 1127
Blev medlem: 19 juni 2012, 23:28:16
Ort: Linköping

Re: Enkla men fatala buggar

Inlägg av superx »

I de fallen jag kommer att tänka på där det är odefinierat (som i TomasLs exempel) så hjälper det inte med parenteser. Men det kanske finns sådana fall också?
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Enkla men fatala buggar

Inlägg av blueint »

Om det inte hjälper att t.ex göra om:
printf ( "%d %D\n", ++n, power(2,n));
Till:
n++;
printf ( "%d %D\n", n, power(2,n));
Eller t.om:
n++;
pw = power(2,n);
printf ( "%d %D\n", n, pw);
Samt "low = input & 0x0F << 4" till "low = (input & 0x0F) << 4" då är det illa! :vissla:
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 45168
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Re: Enkla men fatala buggar

Inlägg av TomasL »

De exemplen jag visade måste delas upp så att man använder mellanresultat, för att få korrekt funktion på det hela och i den oordningen man vill ha det.

Generellt gäller dock alltid parenteser och ofta mellanresultat (vilka naturligtvis är enklare att debugga).
Användarvisningsbild
bit96
Inlägg: 2492
Blev medlem: 3 september 2007, 10:04:29
Ort: Säffle

Re: Enkla men fatala buggar

Inlägg av bit96 »

blueint:

Kod: Markera allt

printf ( "%d %D\n", ++n, power(2,n));
Självklart skall det skrivas om, men kanske inte på det sätt du föreslår.
Det beror på om programmeraren vill använda det 'gamla' eller 'nya' värdet på 'n' vid anrop av power().
Och det vet bara denne (förhoppningsvis). Och eftersom det saknas kommentarer så kan ingen veta hur det skall vara. :)
Det enda vi kan säga är att resultatet inte är entydigt.

Vid funktionsanrop kan argumenten beräknas i valfri ordning (kompilatorberoende) enligt standard.
Just därför kan/skall man inte både beräkna och använda en variabel flera gånger i ett funktionsanrop.
Användarvisningsbild
bit96
Inlägg: 2492
Blev medlem: 3 september 2007, 10:04:29
Ort: Säffle

Re: Enkla men fatala buggar

Inlägg av bit96 »

TomasL skrev: Ta till exempel

Kod: Markera allt

X = f() + g();
F kan evalueras före g eller viceversa, så om då en av funktionerna påverkar variabler som används i den andra, kan vad som helst hända.
T.ex. kan man skriva:

Kod: Markera allt

float X, f_del, g_del; /* xxx-funktionernas summa samt del-resultat */
...
/* Beräkna delresultaten från ggg och fff. OBS! g() måste beräknas först eftersom vissa globala variabler påverkas som f() behöver */
g_del=g():
f_del=f();
X=f_del+g_del; /* Summan av ggg och fff är klar. Även de globala variablerna har uppdaterats */
Då har man kommenterat vad som händer, sett till att slutsumma och delresultat har samma cast, samt förklarat att globala variabler används.
Förhoppningsvis är kodsnutten tolkningsbar för näste programmerare om 18 månader.
Dessutom ger den förhoppningsvis samma resultat även om kompilator ändras eller byts till annat fabrikat.
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Enkla men fatala buggar

Inlägg av blueint »

Glabala variabler och sidoeffekter är rena minfältet.. :vissla:
Skriv svar