Nog heel veel meer ontwerptips en domme fouten

Volgens mij wordt bij "a = b = c = 0;" niet de waarde van a, b, en c teruggelezen, maar dat zou wel eens compiler afhankelijk kunnen zijn, net als 1001 andere dingen waarvan we gemakkelijk denken dat ze standaard zijn.

@REW: een ; achter } mag volgens mij altijd; je mag zelfs extra ;'s aan het eind van een regel zetten. Ik zou niet weten in welke situatie die {} in een macro fout zou gaan, maar wellicht bestaat die wel. Tot dusver heb ik er nooit problemen mee gehad, maar ik probeer macro's altijd te beperken tot een enkele statement, anders maak ik er een inline functie van, of een gewone functie, en dan mag de compiler uitzoeken of inlining nuttig is.
Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken
Als je
code:
#define MYMACRO(x) {this;that} 

doet, dan wordt
code:
if (somecondition)
   MYMACRO (zz);
else 
   somethingelse; 

ineens fout. De ; voor de else mag niet.

Wat het ook al weer precies was moest ik opzoeken. Ik heb hen zojuist hier gevonden.

[Bericht gewijzigd door rew op 14 april 2019 22:23:44 (31%)]

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Volgens mij wordt bij "a = b = c = 0;" niet de waarde van a, b, en c teruggelezen, maar dat zou wel eens compiler afhankelijk kunnen zijn, net als 1001 andere dingen waarvan we gemakkelijk denken dat ze standaard zijn.



Uit de avr-libc FAQ http://nongnu.org/avr-libc/user-manual/FAQ.html


Why is assigning ports in a "chain" a bad idea?

Suppose a number of IO port registers should get the value 0xff assigned. Conveniently, it is implemented like this:
DDRB = DDRD = 0xff;

According to the rules of the C language, this causes 0xff to be assigned to DDRD, then DDRD is read back, and the value is assigned to DDRB. The compiler stands no chance to optimize the readback away, as an IO port register is declared "volatile". Thus, chaining that kind of IO port assignments would better be avoided, using explicit assignments instead:
DDRB = 0xff;
DDRD = 0xff;

Even worse ist this, e. g. on an ATmega1281:
DDRA = DDRB = DDRC = DDRD = DDRE = DDRF = DDRG = 0xff;

The same happens as outlined above. However, when reading back register DDRG, this register only implements 6 out of the 8 bits, so the two topmost (unimplemented) bits read back as 0! Consequently, all remaining DDRx registers get assigned the value 0x3f, which does not match the intention of the developer in any way.


Altijd opletten dus :-) in dit geval met 'volatile' variabelen.

Groetjes,
eSe
I am an expert of electricity. My father occupied the chair of applied electricity at the state prison.
De Avr-libc-faq heeft het fout.

IN "a=b=c=val;" staat er niet "c=val; b=c; a=b;", maar "a= (b= (c=val));". En in de C-standaard staat dat een assignment die gebruikt wordt waar een waarde verwacht wordt de ge-assignde waarde teruggeeft.

In de praktijk:
code:
volatile int a, b, c;

void testit (int val)
{
  a=b=c=val;
}

Met "volatile" geef ik aan dat de variabele zonder waarschuwing tussendoor veranderd kan worden. Dit is ook de manier waarop hardware registers gedefinieerd zijn.

code:
while (!(PINB & 1)); 
zou anders iets worden als: laad PINB in een register, herhaal: test bit 1 in het register of dat al 1 geworden is. Met volatile vertel je de compiler dat ie steeds PINB weer op moet halen alvorens dat ie de test gaat doen.


Met de avr compiler wordt dat:
code:
testit:
        sts c+1,r25
        sts c,r24
        sts b+1,r25
        sts b,r24
        sts a+1,r25
        sts a,r24
        ret
De functie parameter in R24/R25 wordt eerst in c, dan in b en dan in a gezet.

De arm-compiler doet:
code:
testit:
        ldr     r1, .L3
        ldr     r2, .L3+4
        ldr     r3, .L3+8
        str     r0, [r1]
        str     r0, [r2]
        str     r0, [r3]
        bx      lr
Hierbij optimaliseert ie ook nog r1 en r2 weg als ik "static" voor de abc declaratie zet. (*) Merk op dat elders c op het laagste adres wordt gezet, dus weer is het eerst c, dan b, dan a.

En als laatste bij x86 wordt het:
code:
testit:
        movl    %edi, c(%rip)
        movl    %edi, b(%rip)
        movl    %edi, a(%rip)
        ret
met de functie parameter in %edi en gewoon een enkele instructie om de store-naar-memory te regelen.


(*) Dat had ik eerst gedaan, en omdat er in m'n source niets anders bevat was ik bang dat ie misschien toch aannames ging doen van: omdat deze variabelen buiten deze source niet bekend mogen zijn, en ik in deze source kan zien dat ze niet gewijzigd worden, weet ik zeker dat er tussendoor geen wijzigingen zijn. Dat is een foute gedachte van me: die a-b-c variabelen hadden zomaar een hardware register kunnen zijn wat door de hardware veranderd wordt. Ook als er in deze source geen code is die ze verandert!
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Van een eenvoudiger orde: de programmeer/debug aansluiting bereikbaar houden als de behuizing dicht is:



Wel hetzelfde lichtwekker-project. Meer in SyP.
Blog // Backwards Lightspeed Bus: i*i=-1, so iic=-c.