[C++] kan void een waarde teruggeven aan main?

Pagina: 1
Acties:
  • 361 views sinds 30-01-2008
  • Reageer

  • lonkhuijzen
  • Registratie: December 2001
  • Laatst online: 01:53
Ik heb als huiswerk de opdracht gekregen om 11 cijfers op volgorde te leggen. De main was gegeven en er moesten 3 voids onder hangen.

Alleen in mijn boek staat dat de aangeroepen functie geen waarde terug kan geven.. dit strookt ook wel met de uitkomst van dit programma namelijk steeds hetzelfde getal ergens uit het geheugen.

Toch zou het moeten kunnen... kan iemand mij vertellen wat ik nou fout doe

Hoe kan ik een waarde invoeren die door de sorteer algoritme halen en dan laten printen.
het is dus welzo dat het deze volgorde moet hebben
main-void(invoer)-void(sorteer)-void(uitvoer)
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <stdio.h>
#include <conio.h>
#define AANTAL 11

main ()
{
    int x[AANTAL];
    void invoer(int[]);
    void werkfun(int[]);
    void afdruk(int[]);
    invoer(x);
    werkfun(x);
    afdruk(x);
    getch();
    return 0;
}
 
void invoer(int[])
{
    int x[AANTAL];
    int i;
    printf("Voer 11 getallen in: ");
    for (i=0; i<AANTAL; i=i+1)
        scanf(" %d", &x[i]);
}


void werkfun(int[])
{
    int x[AANTAL];
    int i,j,tijdelijk;
    for (j=0; j<AANTAL-1;j=j+1)
    {
        for (i=0; i<AANTAL-1-j; i=i+1)
            if (x[i+1] < x[i])
        {
            tijdelijk = x[i+1];
            x[i+1] = x[i];
            x[i] = tijdelijk;
        }
    }
}

void afdruk(int[])
{
    int x[AANTAL],i;
    printf("Gesorteerde getallen: \n");
    for (i=0; i<AANTAL; i=i+1)
    printf(" %d", x[i]);
}

5,85kWp 15x Sunpower Max3 390Wp OZO | live PV output | LabelA@‘78


Verwijderd

Als ik jou was, zou ik de syntax van C++ doornemen voordat ik een RTFM vraag stelde.

Het antwoord is nee, een void functie kan geen waarde retourneren. Wat denk je dat void betekent?

  • lonkhuijzen
  • Registratie: December 2001
  • Laatst online: 01:53
Dan denk ik dat er maar eens een leraar ontslagen moet worden.... omdat hij specifiek deze vraag zo stelde..

pfff loop ik daarvoor te zwoegen...

5,85kWp 15x Sunpower Max3 390Wp OZO | live PV output | LabelA@‘78


  • hufkes
  • Registratie: Maart 2000
  • Laatst online: 26-08 18:43

hufkes

nee, daar staat niet hufter!

het is inderdaad wel een beetje erg basic, maar omdat je 3 functies moet hebben die void zijn - geen waarden teruggeven dus - moet je het systeem zo opzetten dat je geen retourwaardes nodig hebt. In C++ kun je dit heel mooi doen door middel van pointers, je maakt dus een globale array aan (liever ook niet 'x' noemen, maar een zinvolle naam geven, dus wat komt erin) en bij de functie-aanroepen geef je de pointer naar bovengenoemde globale array mee. Op die manier hoeft de functie dus geen waardes terug te geven, maar kan rechtstreeks in de gegeven waardes veranderen.

Lees dus vooral even het stuk in je boek over pointers. Lees het daarna direct nog een keer, want waarschijnlijk zie je wel wat dingetjes over het hoofd, en pointers is heel belangrijk in C++

Onderstaande signature is al >20jr oud ***hoe dan***
---
Het internet is een veelbelovend medium
....dat maar heel weinig van zijn beloftes nakomt.
Wat weg is... raak je nooit meer kwijt :P


  • lonkhuijzen
  • Registratie: December 2001
  • Laatst online: 01:53
Alleen het grote probleem is nu dat ik mijn main dus niet mag veranderen, omdat deze zo gegeven is..

5,85kWp 15x Sunpower Max3 390Wp OZO | live PV output | LabelA@‘78


  • Fuzzillogic
  • Registratie: November 2001
  • Laatst online: 01-07-2025
Hoezo onmogelijk? Een variabele via pass by reference doorgeven en hupsa.
code:
1
void DoeDing(int &getal)

enzo.

En i=i+1? GADverdamme zeg :P Als C-coder gaan me de haren hiervan overeind staan. Doe es gauw i++ van maken? :) (or better (because faster) ++i, hoewel ik niet zeker weet of het hier ook sneller is.. (stack-gedoe))

  • Fuzzillogic
  • Registratie: November 2001
  • Laatst online: 01-07-2025
[edit]
ARG ik word gek van die knoppen! ik ram altijd de verkeerde! :( En waar blijft de cancel knop? :) (oh :P)

Verwijderd

Hoezo onmogelijk? Een variabele via pass by reference doorgeven en hupsa.
Hoeft niet, er wordt al een pointer gebruikt. Tenminste, dat is de bedoeling.

  • lonkhuijzen
  • Registratie: December 2001
  • Laatst online: 01:53
Mooi dank allemaal heb hem nu gevonden
code:
1
void invoer(int x[AANTAL])

5,85kWp 15x Sunpower Max3 390Wp OZO | live PV output | LabelA@‘78


  • hufkes
  • Registratie: Maart 2000
  • Laatst online: 26-08 18:43

hufkes

nee, daar staat niet hufter!

Op vrijdag 24 mei 2002 02:03 schreef Pluk het volgende:
Mooi dank allemaal heb hem nu gevonden
code:
1
void invoer(int x[AANTAL])
>:)
Op vrijdag 24 mei 2002 01:46 schreef hufkes het volgende:
[...]
Lees het daarna direct nog een keer, want waarschijnlijk zie je wel wat dingetjes over het hoofd

Onderstaande signature is al >20jr oud ***hoe dan***
---
Het internet is een veelbelovend medium
....dat maar heel weinig van zijn beloftes nakomt.
Wat weg is... raak je nooit meer kwijt :P


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 21:50
Ter informatie: dit heeft helemaal niets met C++ te maken. Dit is C.

Verder vind ik het opzetje al ontzettend ranzig. Ik weet niet wat je voor docent hebt, maar ik zou een student die zulke code zou schrijven er op willen aanspreken. Dat betekent dus ook dat ik als student zulke code van een docent niet zou accepteren.

Prototypes declareren hoort niet in gelokaliseerde scope te gebeuren (ook al mag 't van de compiler wel). Precompiler directives worden alleen gebruikt als er geen andere oplossing (een constante bijvoorbeeld) is. Het meest-standaard-loopje aller tijden gaat met x++ of eventueel met ++x (wat ik zelf prettiger vind, maar minder gebruikelijk is). In ieder geval niet met "x = x + 1". Verder hoort het return type van main gespecificeerd te zijn (liefst int, eventueel void).

En dan heb ik het nog niet over variabele naamgeving en dergelijke. 'invoer' en 'uitvoer' zou een logische combinatie zijn geweest, maar in plaats daarvan heet de uitvoerfunctie 'afdruk'. Functies afsluiten met 'fun' ('werkfun()')kan al helemaal niet. invoer() is de invoer-functie, die zou je dan ook wel 'invoerfun()' kunnen noemen. Niet doen dus!

Tenslotte weet ik niet wat je uiteindelijke code is geworden, maar een limiet op een array in je functie zetten doet niets. Als je dus je functie met 'void invoer(int[20])' begint, dan weerhoud niets de buitenwereld ervan om die functie met een array met meer of minder argumenten aan te roepen.

  • lonkhuijzen
  • Registratie: December 2001
  • Laatst online: 01:53
tja dit was hoofdstuk 7 en pointers hoofdstuk 9.. :)
en vooruit lezen is ook zoveel werk :Z

maarja tis nu gelukt lol

5,85kWp 15x Sunpower Max3 390Wp OZO | live PV output | LabelA@‘78


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 21:50
Het verbaast me trouwens dat de code zelf niet werkte. Omdat je je array X elke keer niet initialiseerde, maar wel steeds als eerste gedeclareerd had, zou 'ie toevallig elke keer op dezelfde plaats op de stack geplaatst moeten worden, waardoor X elke keer dezelfde inhoud had. Dat is natuurlijk een stom toevallig gevolg van de implementatie van de taal.

  • lonkhuijzen
  • Registratie: December 2001
  • Laatst online: 01:53
Op vrijdag 24 mei 2002 02:27 schreef Soultaker het volgende:
Ik zal je uitleg als goed advies gebruiken, klinkt allemaal erg logisch.. het probleem is nou eenmaal dat ik alleen maar doe wat me geleerd wordt, en dat die leraar nou eenmaal niet een echte programmeur is... het boek praat trouwens ook steeds over x=x+1 |:(

5,85kWp 15x Sunpower Max3 390Wp OZO | live PV output | LabelA@‘78


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 06-09 22:39
Op vrijdag 24 mei 2002 01:49 schreef Nexxennium het volgende:
code:
1
void DoeDing(int &getal)

.... Als C-coder ....
Als C coder weet jij dan ook wel dat dat in C onmogelijk is.

Antwoord op de vraag: ja, een void functie kan wel een waarde teruggeven, maar dan zul je, zoals gezegd, wel met pointers moeten gaan werken.

[edit]
Oh, er werd een C++ vraag gesteld. |:( Excuse moi...

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • whoami
  • Registratie: December 2000
  • Laatst online: 19:30
Op vrijdag 24 mei 2002 01:49 schreef Nexxennium het volgende:

En i=i+1? GADverdamme zeg :P Als C-coder gaan me de haren hiervan overeind staan. Doe es gauw i++ van maken? :) (or better (because faster) ++i, hoewel ik niet zeker weet of het hier ook sneller is.. (stack-gedoe))
Het verschil tsn i++ en ++i heeft niets met performance te maken, maar met de volgorde van bewerkingen.

Bv:
code:
1
2
3
4
5
int i, j;
i = 5;
j = i++;
cout << "i = " << i << endl;
cout << "j = " << j << end;

In dit voorbeeld zal de output:
code:
1
2
i = 6
j = 5

zijn

en met dit voorbeeld:
code:
1
2
3
4
5
int i, j;
i = 5;
j = ++i;
cout << " i = " << i << endl;
cout << " j = " << j << endl;

zal de output
code:
1
2
i = 6
j = 6

zijn.

https://fgheysels.github.io/


  • whoami
  • Registratie: December 2000
  • Laatst online: 19:30
Op vrijdag 24 mei 2002 08:57 schreef farlane het volgende:

Antwoord op de vraag: ja, een void functie kan wel een waarde teruggeven, maar dan zul je, zoals gezegd, wel met pointers moeten gaan werken.

[edit]
Oh, er werd een C++ vraag gesteld. |:( Excuse moi...
In C++ werk je beter met references ipv met pointers om variablen die moeten gewijzigd worden door te geven aan een functie. (Maar als het slechts om 1 variable gaat, is een return waarde natuurlijk veel mooier).

https://fgheysels.github.io/


  • JayTaph
  • Registratie: Oktober 1999
  • Laatst online: 28-11-2025

JayTaph

Portability is for canoes.

[b]Op vrijdag 24 mei 2002 01:49 schreef Nexxennium
En i=i+1? GADverdamme zeg :P Als C-coder gaan me de haren hiervan overeind staan. Doe es gauw i++ van maken? :) (or better (because faster) ++i, hoewel ik niet zeker weet of het hier ook sneller is.. (stack-gedoe))
Heeft niet zo veel met de stack te maken, ++i wil zeggen dat i geincrement wordt VOORDAT er andere bewerkingen plaatsvinden (printf ("%d", ++i); en printf ("%d, i++);")

I is en blijft een stackvalue, omdat je deze lokaal declareert (en dan komen de variabelen per definitie op de stack terecht) en i++;, i=i+1;, ++i; worden alledrie naar hetzelfde code gecompiled (inc [ebp+48] bijvoorbeeld).


Maar het is inderdaad geen code om trots op te zijn :+

Yo dawg, I heard you like posts so I posted below your post so you can post again.


  • whoami
  • Registratie: December 2000
  • Laatst online: 19:30
Ik vind de notatie van z'n functie-argumenten nogal raar:
code:
1
2
3
void invoer(int[])
{
    int x[AANTAL];

volgens mij heeft dit niet het gewenste resultaat. :?

https://fgheysels.github.io/


  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 20:26

Creepy

Tactical Espionage Splatterer

Op vrijdag 24 mei 2002 02:27 schreef Soultaker het volgende:
Ter informatie: dit heeft helemaal niets met C++ te maken. Dit is C.

Verder vind ik het opzetje al ontzettend ranzig. Ik weet niet wat je voor docent hebt, maar ik zou een student die zulke code zou schrijven er op willen aanspreken. Dat betekent dus ook dat ik als student zulke code van een docent niet zou accepteren.
Prototypes declareren hoort niet in gelokaliseerde scope te gebeuren (ook al mag 't van de compiler wel). Precompiler directives worden alleen gebruikt als er geen andere oplossing (een constante bijvoorbeeld) is.
Als je die functies op deze manier in main wilt gebruiken zul je die prototypes toch echt moeten hebben, tenzij je je main onderaan zet. Maar ranzig is het wel ja
Het meest-standaard-loopje aller tijden gaat met x++ of eventueel met ++x (wat ik zelf prettiger vind, maar minder gebruikelijk is). In ieder geval niet met "x = x + 1".
x=x+1 of x++ maakt echt niks uit. De compiler optimaliseert dit zelf wel. x++ is alleen minder typ werk. Of je moet echt gebruik maken van de post (of pre) increment.
Verder hoort het return type van main gespecificeerd te zijn (liefst int, eventueel void).
Return type is standaard een int.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • whoami
  • Registratie: December 2000
  • Laatst online: 19:30
Op vrijdag 24 mei 2002 09:19 schreef Creepy het volgende:


Als je die functies op deze manier in main wilt gebruiken zul je die prototypes toch echt moeten hebben, tenzij je je main onderaan zet. Maar ranzig is het wel ja
Hij had het over de plaats van de prototypes, ze staan in de main(), en eigenlijk zouden ze er buiten moeten staan.
x=x+1 of x++ maakt echt niks uit. De compiler optimaliseert dit zelf wel. x++ is alleen minder typ werk. Of je moet echt gebruik maken van de post (of pre) increment.
Da's ook waar.
Return type is standaard een int.
Al is het standaard, eigenlijk zou je er het toch bij moeten zetten. Al was het voor de consistentie, en daarbij, it's bad practise to rely on defaults. Het is toch beter vind ik om alles expliciet te vermelden.

https://fgheysels.github.io/


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 06-09 22:39
Op vrijdag 24 mei 2002 09:05 schreef whoami het volgende:

[..]

In C++ werk je beter met references ipv met pointers om variablen die moeten gewijzigd worden door te geven aan een functie. (Maar als het slechts om 1 variable gaat, is een return waarde natuurlijk veel mooier).
Ik geef de voorkeur aan pointers als ik variabelen in een functie wil aanpassen, en const references als ik objecten e.d. wil doorgeven die ik niet wil aanpassen.

Naar mijn idee is het in de code waar de aanroep zit dan duidelijker dat er in de functie wat met de variabele gebeurt, doordat je expliciet het adres meegeeft.

Maar een returnwaarde daarvoor gebruiken heeft idd ook mijn voorkeur.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • JungleJim
  • Registratie: December 2000
  • Laatst online: 19:49
Op vrijdag 24 mei 2002 09:01 schreef whoami het volgende:

[..]

Het verschil tsn i++ en ++i heeft niets met performance te maken, maar met de volgorde van bewerkingen.
Wel, hoor: i++ levert de oude waarde van i op, en zorgt dus voor een extra object. ++i levert meteen de nieuwe waarde van i, en daarvoor is dus geen extra object nodig.

Voor de built-in types zal dit niet zo'n probleem zijn, maar wanneer je een class hebt (bijvoorbeeld een iterator uit de standard c++ library), dan heb je met i++ te maken met een extra kopie voor een tijdelijk object.

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:30
Op vrijdag 24 mei 2002 11:31 schreef JungleJim het volgende:

[..]

Wel, hoor: i++ levert de oude waarde van i op, en zorgt dus voor een extra object. ++i levert meteen de nieuwe waarde van i, en daarvoor is dus geen extra object nodig.

Voor de built-in types zal dit niet zo'n probleem zijn, maar wanneer je een class hebt (bijvoorbeeld een iterator uit de standard c++ library), dan heb je met i++ te maken met een extra kopie voor een tijdelijk object.
We hadden het hier dan ook over een primitief type, nl. een integer en niet over een object. :)

https://fgheysels.github.io/


  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06-2025

drm

f0pc0dert

woei :) ik zit in een verschrikkelijke tweestrijd... aan de ene kant denk ik dat je idd een extra plekkie op de stack nodig hebt voor i++, (dat wil zeggen, wanneer het voorkomt in een expressie als ( a == i ++ )), maar aan de andere kant twijfel ik daar een beetje aan...

Is er hier nog een of andere compilerguru aanwezig die mij uit kan leggen hoe een compiler omgaat met een dergelijke expressie? Waar laat hij de oorspronkelijke waarde van i als er een i++ ophoging plaatsvindt :?

Of wordt het geoptimaliseerd op zo'n manier dat je geen extra plek nodig hebt? Want ik zit er over na te denken, en ik kan geen manier bedenken dat je dat plekje niet nodig hebt, maar ik kan me voorstellen die manier wel bestaat.... ofzo (8>

* drm is namelijk (compiler/parser)-ofiel en wil alles erover weten :D ;)

edit: ff wat extra

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
In deze situatie maakt het denk ik helemaal niets uit omdat i++ of ++i een StatementExpression is. Het resultaat van de expressie ++i of i++ is dus helemaal nergens nodig en dus zal een goede compiler ook zorgen dat i niet opgeslagen wordt in een register of op de stack voor gebruik in de (niet bestaande) omringende expressie. Een compiler kan dit natuurlijk ook niet doen, maar das dan matig van de compiler :P .

Dan ga je natuurlijk vragen wat dan het verschil is als i++ of ++i wel als echte expressie gebruikt zou worden ;) . Allereerst moet je in dit geval bedenken dat i als loop-counter waarschijnlijk niet op de stack maar in een register zal staan. Op zich maakt dat voor deze situatie echter niet zo heel erg veel uit.

In de situatie van ++i kan het register wat de waarde i bevat direct worden opgehoogd en kan de volgende berekening gebruik maken van dit register, de oude waarde van het register is dan immers niet meer nodig.

In de situatie van i++ zal het register van i worden opgehoogd, maar is het resultaat van i ook nog nodig. Dit zal dus in een temporary worden opgeslagen (dit kan op de stack, maar waarschijnlijk zal dit in een register zijn omdat het resultaat wellicht gelijk gebruikt kan worden in de volgende instructie).

Mijn verhaal is alleen te kort door de bocht omdat het in realiteit vaak niet zo gaat. Voor de instructie-selectie worden statements zoals i++ of ++i vaak uit de expressie-bomen gefilterd zodat er geen side-effects meer zijn in de boom. De statements zullen dus omhoog gelift worden zodat de volgorde waarin de expressies in de boom worden uitgerekend niet meer relevant is.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 06-09 22:39
Op vrijdag 24 mei 2002 12:16 schreef mbravenboer wat tekst
Je hebt je compilerstudie afgerond zie ik ? :)

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06-2025

drm

f0pc0dert

valt me mee dat je zo snel reageert? stiekem toch nog veel aan 't lurken hier? </ot>
mbravenboer:
De statements zullen dus omhoog gelift worden zodat de volgorde waarin de expressies in de boom worden uitgerekend niet meer relevant is.
Zoiets vermoedde ik al, ja. Maar hoe gebeurt dit dan in detail? Want als je een for-loop gebruikt, kan er bijvoorbeeld binnen de iteratie ook nog e.e.a. gebeuren met de counter i. Wat bijvoorbeeld als ik een rand () functie aanroep en toeken aan i? Snappie waar ik heen wil?

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 21:50
Op vrijdag 24 mei 2002 09:19 schreef Creepy het volgende:
x=x+1 of x++ maakt echt niks uit. De compiler optimaliseert dit zelf wel. x++ is alleen minder typ werk. Of je moet echt gebruik maken van de post (of pre) increment.
Het voordeel van standaardpatronen als deze is dat het makkelijk is om de patronen te herkennen. Ik kan een for-lusje ook schrijven als:
code:
1
2
3
i=0; do {
  [..]
} while(++i<10);

(om waar wat te verzinnen), maar dan kost het iemand anders (een docent, bijvoorbeeld), meer moeite om de code te begrijpen.
Return type is standaard een int.
Niet volgens de ANSI C standaard. Die verplicht je tot het specificeren van het return type. Een ANSI C compiler verwerpt deze code.

Zelf ga ik meestal alleen uit van defaults als het me niet kan schelen wat hun waarde is (in het algemeen, dus ook voor andere programmeertalen, HTML, etcetera). In dit geval stond er een 'return 0' in main(), dus zal de return type in ieder geval numeriek moeten zijn. Als ik dat verwacht, vind ik dat ik ook de default moet overriden. (Hier was die overweging trouwens niet aan de orde, het return type weglaten was gewoon fout.)

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
farlane: Je hebt je compilerstudie afgerond zie ik ? :)
Ik pruts af en toe wat ;) .
drm: stiekem toch nog veel aan 't lurken hier?
In perioden van verveling ben ik af en toe nog weleens wanhopig op zoek naar een topic waar ik kan reageren ;) .
Zoiets vermoedde ik al, ja. Maar hoe gebeurt dit dan in detail?
Detail? Tja, daar zou ik toch maar een goed boek over compilerbouw voor nemen ;) . Ik kan wel een beetje schetsen, wat er gebeurd.
Wat bijvoorbeeld als ik een rand () functie aanroep en toeken aan i? Snappie waar ik heen wil?
Hum nee, eigenlijk niet... Je bedoelt een ingewikkeldere statement ipv i++ in een for-loop? Als je dat bedoelt: ik weet niet wat er het meestal gebeurt, maar ik heb het zelf gedesugard naar een while-loop waarin de step-statement de laatste statement van het block is... De while loop wordt daarna weer omgezet in labels, goto's en een ifje.

In principe is het uberhaupt zo dat wanneer je statements gaat 'liften' er geen abstractere constructies meer zijn zoals for, while etc. Lifting van statements wordt gedaan op intermediate representations vlak voor de instructie-selectie. intermediate representations bevatten over het algemeen geen abstracte control-flow meer (itt Java Bytecode en .NET IL ;) ).

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • JayTaph
  • Registratie: Oktober 1999
  • Laatst online: 28-11-2025

JayTaph

Portability is for canoes.

Op vrijdag 24 mei 2002 11:54 schreef drm het volgende:
woei :) ik zit in een verschrikkelijke tweestrijd... aan de ene kant denk ik dat je idd een extra plekkie op de stack nodig hebt voor i++, (dat wil zeggen, wanneer het voorkomt in een expressie als ( a == i ++ )), maar aan de andere kant twijfel ik daar een beetje aan...

Is er hier nog een of andere compilerguru aanwezig die mij uit kan leggen hoe een compiler omgaat met een dergelijke expressie? Waar laat hij de oorspronkelijke waarde van i als er een i++ ophoging plaatsvindt :?

Of wordt het geoptimaliseerd op zo'n manier dat je geen extra plek nodig hebt? Want ik zit er over na te denken, en ik kan geen manier bedenken dat je dat plekje niet nodig hebt, maar ik kan me voorstellen die manier wel bestaat.... ofzo (8>

* drm is namelijk (compiler/parser)-ofiel en wil alles erover weten :D ;)
Djee werpt zich op als compiler-guru :+
code:
1
2
3
4
5
6
int main (void) {
  int a;
  int i = 0;
  
  (a=(i++));
}

Uit mijn hoofd gecompilde code :+
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
main:
  ; stack frame goedzetten
  push %esp
  movl %ebp %esp
  subl $8,(%esp)

  ; i = 0
  movl $0, -8(%ebp)

  ; a = i
  movl -8(%ebp), %eax
  movl %eax, -4(%ebp)

  ; i++
  incl -8(%ebp)
 
  ; Destroy stack frame (LEAVE kan ook)
  movl %ebp, %esp
  popl %ebp
  
  ; return  (wat in %eax staat, wordt meestal teruggegeven)
  ret

Wat gebeurt er:
Als eerste wordt er de stackframe goedgezet, meestal houdt dat in dat ebp op de stack wordt geplaatst, en ebp de waarde krijgt van esp. [esp+0] wijst dus naar de gesavede ebp, [esp+4] wijst naar het return adres.

Daarna wordt er wat ruimte gedefineerd voor de locale variabelen, in dit geval 8 bytes (2x een int (a en i)).
(sommige stack-alignment opties willen hier wel meer van maken, bijvoorbeeld gcc gooit dit al meteen naar 24 toe :)).

Nu heb je dus een situatie waarin -4(%ebp) wijst naar A, en -8(%ebp) wijst naar I.

Als eerste gaat de compiler A=I compilen, dat is dus niets meer als het kopieeren van -8(%ebp) naar -4(%ebp). Dit moet wel met een tussenstap in %eax, omdat "movl -8(%ebp), -4(%ebp) niet mag.

Daarna wordt er bij I 1 opgeteld, dit mag wel direct: incl %-8(ebp).


a=++i zou dus worden:
code:
1
2
3
4
5
6
  ; i++
  incl -8(%ebp)

  ; a = i
  movl -8(%ebp), %eax
  movl %eax, -4(%ebp)

Als dus dus veel met deze variabelen werkt (in loopjes bijvoorbeeld), dan moet de processor elke keer een offset-lookup gaan doen vanuit EBP, hetgeen niet al te snel is (piping, caching etc doen wonderen, maar toch)..
Daarom kun je het keyword "register" voor een variabele zetten:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int register i;
int j=123;

for (i=0; i!=100; i++) {
  j++;
}

  movl $123, -8(%ebp)    ; j =123
  movl %eax, -4(%ebp)    ; dump i naar register
.forlabel:
  cmpl $100, %eax        ; i!=100
  je   .forend        ; jawel, dan einde
  incl -8(%ebp)      ; j++

  incl  %eax            ; i++
  jmp   .forlabel        ; en terug naar for-loop
.forend
  movl  -4(%ebp), %eax  ; i wordt weer weggesaved in zijn eigen var, voor het geval dat de compiler het dadelijk niet meer in een register kan laden.

Zoals je ziet wordt er in de for-loop geen referentie meer gemaakt naar I "as-in" (dus -4(%ebp)), maar naar %eax, de register waarin i zich (tijdelijk) bevind.



++i, of i++ heeft dus geen enkele invloed op de stack, alleen op de plaatsing van de code in de compiler-output (wel natuurlijk als je dit als operator overloading gebruikt, maar dat is een compleeeeeeet ander verhaal :+)).

Yo dawg, I heard you like posts so I posted below your post so you can post again.


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Daarom kun je het keyword "register" voor een variabele zetten
Dat heb ik nooit leuk gevonden, is het niet de taak van de compiler om uit te zoeken of iets in een register kan? Zeker in het geval van dergelijke loop-counters zou dat toch geen probleem mogen zijn.
i wordt weer weggesaved in zijn eigen var, voor het geval dat de compiler het dadelijk niet meer in een register kan laden.
Dit kan toch ook at compile-time ganalyseerd worden? Als de variabele i nog live is na de for-loop, maar de registers na de for-loop beter gebruikt kunnen worden, kan je hem opslaan op de stack. Als i niet live is of er genoeg registers zijn, hoef je hem ook niet op de stack te zetten :) .
++i, of i++ heeft dus geen enkele invloed op de stack
Dat komt dus denk ik in dit geval doordat i++ en ++i als een statement-expressie worden gebruikt: het resultaat van de expressie is niet relevant. In andere sitatuaties denk ik toch wel dat er performance verschil kan zijn, alhoewel dit erg moeilijk te voorspellen is ivm het liften van side-effects wat ik net noemde.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06-2025

drm

f0pc0dert

* drm heeft nu even geen tijd, maar gaat zeer binnenkort toch nog even reageren :)

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


  • JayTaph
  • Registratie: Oktober 1999
  • Laatst online: 28-11-2025

JayTaph

Portability is for canoes.

Op vrijdag 24 mei 2002 13:09 schreef mbravenboer het volgende:

[..]

Dat heb ik nooit leuk gevonden, is het niet de taak van de compiler om uit te zoeken of iets in een register kan? Zeker in het geval van dergelijke loop-counters zou dat toch geen probleem mogen zijn.
Nee, dat klopt. Maar een compiler zoekt dat standaard niet uit, misschien wel als je eem heftig op optimizen zet, maar je compile-tijd schiet als een raket de lucht in, omdat ie alles moet gaan analiseren wat jij normaal in 1 oogopslag kan zien. En het verschil tussen %eax en -4(%ebp) is meestal niet zodanig drastisch dat je daar een optimalisatie voor wilt hebben.
Dit kan toch ook at compile-time ganalyseerd worden? Als de variabele i nog live is na de for-loop, maar de registers na de for-loop beter gebruikt kunnen worden, kan je hem opslaan op de stack. Als i niet live is of er genoeg registers zijn, hoef je hem ook niet op de stack te zetten :) .
Sterker nog, in mijn voorbeeld zou er niet eens ruimte voor i gemaakt worden op de stack :). Pas als ik i in een later stadium weer zou gaan gebruiken, dan pas krijgt hij een plekje op de stack.
Dat komt dus denk ik in dit geval doordat i++ en ++i als een statement-expressie worden gebruikt: het resultaat van de expressie is niet relevant. In andere sitatuaties denk ik toch wel dat er performance verschil kan zijn, alhoewel dit erg moeilijk te voorspellen is ivm het liften van side-effects wat ik net noemde.
Performance verschil speelt altijd mee. Maar dat heeft niet zozeer te maken met de ++i of i++, maar meer met het feit dat bepaalde instructies zodanig achter elkaar zitten, dan ze in een keer door gepaired kunnen worden door de CPU. Maar dat zou met ++i net zo makkelijk het geval kunnen zijn als met i++.

In welke situaties is dan de performance beter (of slechter)? Ik kan er zo geen verzinnen namelijk.

Yo dawg, I heard you like posts so I posted below your post so you can post again.


  • whoami
  • Registratie: December 2000
  • Laatst online: 19:30
Dit topic begin wel een hoog (8> - gehalte te krijgen.

Niet dat dat erg is btw. 'k Vind het interessant.

https://fgheysels.github.io/


  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06-2025

drm

f0pc0dert

whoami:
Dit topic begin wel een hoog (8> - gehalte te krijgen.

Niet dat dat erg is btw. 'k Vind het interessant.
't gaat ook een beetje boven mijn pet. Weet je wat, een nieuw topic in LA:
TE hoog niveau in P&W :D

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 20:26

Creepy

Tactical Espionage Splatterer

Op vrijdag 24 mei 2002 12:38 schreef Soultaker het volgende:

[..]
Niet volgens de ANSI C standaard. Die verplicht je tot het specificeren van het return type. Een ANSI C compiler verwerpt deze code.
Hmm.. ik moet nodig weer eens wat aan mijn C skills gaan doen geloof ik :)
Zelf ga ik meestal alleen uit van defaults als het me niet kan schelen wat hun waarde is (in het algemeen, dus ook voor andere programmeertalen, HTML, etcetera). In dit geval stond er een 'return 0' in main(), dus zal de return type in ieder geval numeriek moeten zijn. Als ik dat verwacht, vind ik dat ik ook de default moet overriden. (Hier was die overweging trouwens niet aan de orde, het return type weglaten was gewoon fout.)
Tja.. default waarden gebruiken. Ik probeer alles altijd te definieren (returntype, default values van niet geinitialiseerde var's etc), zodat er geen twijfel over kan bestaan.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
JayTaph: maar je compile-tijd schiet als een raket de lucht in
Das waar, toch zullen compilers met een RISC back-end hier echt wel iets mee moeten doen. Het is een beetje lullig om al die leuke registers daar onbenut te laten, behalve voor echte intermediate resultaten ;) .
En het verschil tussen %eax en -4(%ebp) is meestal niet zodanig drastisch dat je daar een optimalisatie voor wilt hebben.
Nou ja, met loop of andere zwaar gebruikte variabelen kan het plaatsen in een register natuurlijk nog wel aardig effectief zijn.
Sterker nog, in mijn voorbeeld zou er niet eens ruimte voor i gemaakt worden op de stack :). Pas als ik i in een later stadium weer zou gaan gebruiken, dan pas krijgt hij een plekje op de stack.
Je plaatst de waarde van i toch weer op de stack bij 'forend'? Ik doelde vooral op dit voorbeeld waar je de waarde van i in het register dus weer terug zet op de stack voor later gebruik. Als i niet meer gebruikt wordt (niet meer 'live' dus) of als hij in het register kan blijven (wat onwaarschijnlijk is op een CISC) kan je dat dus nog weglaten. Het is natuurlijk wel een heel klein lullig puntje, maar als het net een hotspot is in een MP3 encoder of iets dergelijks is het wellicht toch effectief :) .
In welke situaties is dan de performance beter (of slechter)? Ik kan er zo geen verzinnen namelijk.
Ik denk dat je daarvoor ontiegelijk veel details moet kennen van de processor architectuur waarnaar je compileert en de compiler die je gebruikt.

Je zou wel zeggen dat ++i ooit echte voordelen kan opleveren. Omdat ++i dus een statement met een side-effect is zal die vrijwel altijd uit een expressie zal worden gehaald. De oude waarde van i in een i++ expressie moet in dat geval bewaard worden (ook als i++ in de expressie had gestaan trouwens) omdat de oude waarde van i de waarde van deze expressie is. Dit kan je ruimte en tijd kosten op de stack of in een register lijkt mij :? . De precieze gevolgen zijn echter erg lastig te bepalen denk ik... Zelfs de assmebly code zegt lang niet alles als de processor zelf nog aan het schedulen gaat.
Dit topic begin wel een hoog (8> - gehalte te krijgen.
Tsss, ik hou m'n mond wel weer ;) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op vrijdag 24 mei 2002 14:02 schreef JayTaph het volgende:

[..]

Nee, dat klopt. Maar een compiler zoekt dat standaard niet uit, misschien wel als je eem heftig op optimizen zet, maar je compile-tijd schiet als een raket de lucht in, omdat ie alles moet gaan analiseren wat jij normaal in 1 oogopslag kan zien. En het verschil tussen %eax en -4(%ebp) is meestal niet zodanig drastisch dat je daar een optimalisatie voor wilt hebben.
[..]
Volgens een recente thread in comp.lang.c++.moderated doen alle moderne compilers aan register-allocatie. ( en daar reageerden dus de compiler bouwers) De winst is te groot en de algoritmes te goed. 'register' wordt in C++ keihard genegeerd.
Voor een 8086 heb je nog kans om 't zelf te bedenken, 486 misshien, maar een Pentium4 met register renaming?
Performance verschil speelt altijd mee. Maar dat heeft niet zozeer te maken met de ++i of i++, maar meer met het feit dat bepaalde instructies zodanig achter elkaar zitten, dan ze in een keer door gepaired kunnen worden door de CPU. Maar dat zou met ++i net zo makkelijk het geval kunnen zijn als met i++.
Nou nee; i++ zou je op lage optimalisatie niveaux een hogere register druk kunnen geven, waardoor het paire slechter gaat. Maar i++ geeft je natuurlijk nooit een lagere register druk.
In welke situaties is dan de performance beter (of slechter)? Ik kan er zo geen verzinnen namelijk.
Primair als de CPU een register moet vrijmaken voor de temporary, en de variable in dat register naar main memory
moet. Dan wint ++i; van i++;

Evengoed; moderne compiler herkennen de i++; temporary
(de overbodige in het losse statement) betouwbaar.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 06-09 22:39
Weten we eigenlijk al _of_ een void een waarde kan teruggeven? >:) :)

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • MBV
  • Registratie: Februari 2002
  • Laatst online: 04-09 22:20

MBV

Ik weet zeker hoe het moet (ik had hetzelfde boek). Je moet een array gebruiken. de naam van een array is een pointer naar de eerste waarde. Bij een array moet je dus nooit een &teken gebruiken. als je in de andere functies je array veranderd verandert hij in je hele programma. Dus gewoon de array als functieargument. ik wil je mijn code wel opsturen :)

  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06-2025

drm

f0pc0dert

die vraag is dacht ik al beantwoord...

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


  • JayTaph
  • Registratie: Oktober 1999
  • Laatst online: 28-11-2025

JayTaph

Portability is for canoes.

Op vrijdag 24 mei 2002 16:26 schreef MSalters het volgende:

Primair als de CPU een register moet vrijmaken voor de temporary, en de variable in dat register naar main memory
moet. Dan wint ++i; van i++;
Dit snap ik niet helemaal. Voor i++; zou ik dan wel een register moeten vrijmaken, en voor ++i; niet?

Yo dawg, I heard you like posts so I posted below your post so you can post again.


  • whoami
  • Registratie: December 2000
  • Laatst online: 19:30
Kunnen we even recapituleren?

Is ++i nu performanter dan i++ of hangt het eigenlijk allemaal af van hoe goed de compiler is?

https://fgheysels.github.io/


  • Ericston
  • Registratie: Maart 2001
  • Laatst online: 05-09 18:58
Op vrijdag 24 mei 2002 18:53 schreef whoami het volgende:
Kunnen we even recapituleren?

Is ++i nu performanter dan i++ of hangt het eigenlijk allemaal af van hoe goed de compiler is?
Ik had dit al gefixt ( bedankt Curry ), maar het compilet niet in VC++, dus ga van het laatste uit. :)
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// ------------------------------------------------------------------------
// IdiotProof Benchmark Code
// Written by Curry, original idea from OiSyN
//
// Benchmarks are accurate no matter what thread priority since time
// elapsed is taken from kernel thread monitoring data
// ------------------------------------------------------------------------

#include <windows.h>
#include <stdio.h>
#include <conio.h>

// ------------------------------------------------------------------------
// Helper macros
// ------------------------------------------------------------------------

// Use this macro at the beginning of the function to declare local
// variables used by the benchmark. 10 million iterations gives a fault
// of max. 1 procent
#define MPrepareBenchmark(p_Iterations)                      \
        LARGE_INTEGER     l_Before, l_After;                  \
        FILETIME        l_CreationTime, l_ExitTime, l_KernelTime;   \
        int        l_Index;                     \
        HANDLE      l_ThreadHandle = GetCurrentThread();      \
        const int      c_Iterations = (p_Iterations)

// The MBeginBenchmark macro initializes loop and prints the method name
#define MBeginBenchmark(p_Name) printf("Method '" #p_Name "'");      \
        GetThreadTimes(l_ThreadHandle, &l_CreationTime, &l_ExitTime,  \
               &l_KernelTime, (LPFILETIME)&l_Before);          \
        for(l_Index = 0; l_Index != c_Iterations; l_Index++) {    

// The MEndBenchmark macro finalizes the loop and prints time results
#define MEndBenchmark }                                \
        GetThreadTimes(l_ThreadHandle, &l_CreationTime, &l_ExitTime,  \
               &l_KernelTime, (LPFILETIME)&l_After);            \
        printf(" took %d milliseconds\n",                    \
             (l_After.QuadPart - l_Before.QuadPart) / 10000)     

// ------------------------------------------------------------------------
// Main program
// ------------------------------------------------------------------------
        
int main()
{
// Define benchmark code
MPrepareBenchmark(10000000);

// I++ version
MBeginBenchmark(I++);
  int i;
  i++;
MEndBenchmark;

// ++I version
MBeginBenchmark(++I);
  int j;
  ++j;
MEndBenchmark;

// Wait for keypress before exit
printf("\nPress any key to exit...");
while(!getch());
return 0;
}
// ------------------------------------------------------------------------

  • Orphix
  • Registratie: Februari 2000
  • Niet online
ohjee het B-woord :X ;)

toch grappig hoe die C(++) vragen elke keer uitlopen :)

  • 845
  • Registratie: September 2001
  • Laatst online: 09-08 13:53

845

en dat nog terwijl het om C code gaat :P

  • whoami
  • Registratie: December 2000
  • Laatst online: 19:30
Op vrijdag 24 mei 2002 19:40 schreef Orphix het volgende:
toch grappig hoe die C(++) vragen elke keer uitlopen :)
Ja, 'k heb dat ook onlangs in een ander C++ topic gezegd. Maar het is een welkome afwisseling als je sommig andere topics ziet.

https://fgheysels.github.io/


  • Sjaaky
  • Registratie: Oktober 2000
  • Laatst online: 03-09 23:48
Om de discussie nog een beetje aan te wakkeren (of zou dat in een nieuw topic moeten??), het volgende stukje code.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  int i, j;
  i = 5;
  j = ++i + i;
  cout << " j = " << j << endl;
  i = 5;
  j = i + ++i + i;
  cout << " j = " << j << endl;
  i = 5;
  j = i + i + ++i + i;
  cout << " j = " << j << endl;
  i = 5;
  j = i + 5 + ++i + i;
  cout << " j = " << j << endl;
  i = 5;
  j = i + i + i + ++i + i;
  cout << " j = " << j << endl;

Bij dit stuk code verwacht ik de uitvoer:
12
17
22
22
27
Maar in g++ 2.95.2 krijg ik het antwoord:
12
18 <-- deze waarde is vaag.
22
23 <-- deze ook, vooral vergeleken met de bovenstaande 22
27
Bovenstaande resultaten krijg ik ook msvc6.0 Debug mode terug, in release mode krijg ik:
12
18
24 <-- vaag was eerst 22.
23
30 <-- i wordt dus eerst 6, daarna bij elkaar opgeteld.

Nu weet ik dat de expressies behoorlijk ranzig zijn, maar het gedrag van msvc6 vind ik eigenlijk om te :r.
Ik snap bij j = i + ++i + i; dat de compilers eerst ++i gaan uitrekenen en daarna de rest pas, maar dan houden ze dus geen rekening met de side-effects van ++i;

Bij gebruik van i++ wordt i trouwens altijd pas als allerlaatste in de expressie opgehoogd.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Ik vraag me af of het uberhaupt in de standaard gedefineerd is wat de semantiek van een expressie is, waarin zowel i als ++i op i++ voorkomt?

Vanwege deze vraag moet je het dus ook maar voorkomen :+ .

Er is eigenlijk dus wel erg veel voor te zeggen dat je een assignment ( en dus ook ++i of i++) nooit als expressie zou moeten gebruiken en dat een taal een assignment eigenlijk ook niet als expressie zou mogen toestaan.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Orphix
  • Registratie: Februari 2000
  • Niet online
Op zaterdag 25 mei 2002 16:51 schreef mbravenboer het volgende:
Ik vraag me af of het uberhaupt in de standaard gedefineerd is wat de semantiek van een expressie is, waarin zowel i als ++i op i++ voorkomt?
Ja blijkbaar wordt ook niet gespecificeerd in welke volgorde de operaties opvolgen. En terecht, als een compiler kan optimaliseren door van
a + b + c
te maken:
c + b + a
dan zou dat mogen imo. Het is de taak van de programmeur dit soort gevaarlijke truukjes niet te doen.

Ik vind het wel opmerkelijk trouwens, ik had anders verwacht.
Moraal van het verhaal: Als je onzeker bent enkel 'statische' componenten gebruiken in een expressie :Y)

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Grappig dat niemand heftig gaat protesteren als ik stel dat een taal assignments niet als expressie zou mogen toelaten 8-) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Orphix
  • Registratie: Februari 2000
  • Niet online
Op zaterdag 25 mei 2002 20:47 schreef mbravenboer het volgende:
Grappig dat niemand heftig gaat protesteren als ik stel dat een taal assignments niet als expressie zou mogen toelaten 8-) .
Tja ik denk dat iedereen het direct in een bepaalde context leest ipv het letterlijk interpreteren.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Orphix: Tja ik denk dat iedereen het direct in een bepaalde context leest ipv het letterlijk interpreteren.
En als ik het nu eens letterlijk meen? >:)

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • SWfreak
  • Registratie: Juni 2001
  • Niet online
Op zaterdag 25 mei 2002 16:51 schreef mbravenboer het volgende:
Er is eigenlijk dus wel erg veel voor te zeggen dat je een assignment ( en dus ook ++i of i++) nooit als expressie zou moeten gebruiken en dat een taal een assignment eigenlijk ook niet als expressie zou mogen toestaan.
Voor de compiler-programmeur makkelijk. Voor de overige programmeurs vervelend. Je zou misschien kunnen zorgen dat je i++ en ++i en i niet in een expressie (of een RHS) voor mag komen. Maar dat is weer lastig waarschijnlijk. Allermakkelijkst zou zijn om i++ alleen 'los' toe te staan.

Overigens:
code:
1
2
3
4
int i = 0;
char * b = "test";
i = ++i + i + i++;
printf("%d", i);

levert 4 op (bij mij althans). Dit is wel een beetje tegenstrijdig, want je zou zeggen dat het 3 zou moeten opleveren??

  • Sjaaky
  • Registratie: Oktober 2000
  • Laatst online: 03-09 23:48
In een grijs verleden ben ik begonnen met programmeren in pascal. Al snel kwam de situatie dat ik een variabele wilde ophogen. Dus ik zoeken naar iets dat dat deed. Toen zag ik ergens in een voorbeeld i := i + 1; staan. Eigenlijk vond ik dat maar vreemd, want i := i + 1; is in principe, gelezen als wiskundige vergelijking, niet correct. Maar goed het was een assignment en geen expression.
Later toen ik overstapte op assembly (tja je bent jong, onwetend en wilt snelheid >:) ), kreeg je gewoon eenvoudige statements als inc ax en add ax, 4. Dat vond ik eigenlijk al logischer. Weer later vond ik gerechtigheid in talen als C/C++/java, waar je i++; en i+=4; kon doen. Op school werden constructies als a = 4 + i++; evil beschouwd, vanwege de side-effects op i. Daarom gebruik ik een expressie als i++; alleen los, dus niet als deel van een grotere expressie. In deze talen vond ik het wel weer vreemd dat je bijv a = b = c = d; of if((a=malloc(..))==null)kon doen (dat was in good-old pascal immers niet).

Als je i++ wilt afschaffen, moet de 'industry standard' for-loop for(int i=0; i < size; i++){..} herschreven worden naar for(int i=0; i < size; i=i+1){..}. Eigenlijk is de for-loop in C een andere notatie voor een while-loop. Dus als we toch bezig zijn kunnen we hem beter meteen omschrijven naar iets mooiers als for( i = 0 to 100 by 2 ). Niet dat ik iemand ben die vb-achtige notatie fijner vind (integendeel zelfs), maar zo'n for-loop geeft wel beter de intentie van de for-loop weer.
Je kan het hele euvel wel oplossen door i++; gewoon een statement en geen expressie te laten zijn. i++ 'heeft' dan geen waarde. Dus kan je i++ alleen los gebruiken. Dan zit je ook niet meer met het verschil tussen ++i en i++ (1 van de 2 zou dan gewoon niet meer bestaan).
Dit sluit (bij mij in ieder geval) beter aan bij de intuïtie, dan de manier die nu door de meeste talen wordt gebruikt.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
SWfreak: Voor de compiler-programmeur makkelijk. Voor de overige programmeurs vervelend.
Mwah, dat vind ik wel meevallen. Het ligt er een beetje aan wat 'vervelend' is. Ik vind het vervelend als gedrag niet duidelijk is en er in feite een bad-smell ontstaat die toegestaan wordt door de taal. Onervaren programmeurs of luiwammessen kunnen hier in trappen en er kunnen hierdoor lastig te verklaren fouten ontstaan. Voor de compilerbouwer maakt het niet zoveel uit als het gedrag niet gedefinieerd is. Als het gedrag wel gedefinieerd is, wordt het een stukje vervelender idd ;) .
Je zou misschien kunnen zorgen dat je i++ en ++i en i niet in een expressie (of een RHS) voor mag komen. Maar dat is weer lastig waarschijnlijk.
Mwah, dat is niet zo erg lastig hoor. Qua performance is het ook niet echt een probleem omdat traversals over expressies waar een assignment in zit nooit erg groot zullen zijn (omdat expressies niet groot zijn).

Allereerst zou ik het willen generaliseren naar alle assignments omdat i++ immers een syntaxtische afkorting is (die eventueel geoptimaliseerd kan worden, maar dat is nu even irrelevant). Het is dan best mogelijk om te vereisen dat de variabelen die in de LHS (want daar gaat het om) van een assigment worden gebruikt, niet in de rest van de expressie mogen voorkomen. Dat is dus op zich best een aardige oplossing als je niet te 'streng' wilt zijn. Wel is deze eigenschap niet te beschrijven in een grammatica en zijn het dus extra voorwaarden. Dat is wel onprettig denk ik.
Allermakkelijkst zou zijn om i++ alleen 'los' toe te staan.
En alle andere assignments dan? Het gaat niet alleen over i++ of ++i, maar over assignments als expressies in het algemeen. Mijn stelling is dat dat obscure situaties kan veroorzaken en dus vermeden zou moeten worden, ten bate van de programmeurs desnoods opgelegd door de taal en compiler.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Sjaaky
  • Registratie: Oktober 2000
  • Laatst online: 03-09 23:48
int i = 0;
i = ++i + i + i++;
printf("%d", i);

levert idd 4 op. Het is redelijk vaag, maar valt te beredeneren. ++i levert 1 op, i levert 1 op en i++ levert ook 1 op. Dus aan i wordt de waarde 3 toegekend. Maar er stond nog een i++ in de expressie. Dus i wordt 4 gemaakt, voordat hij geprint wordt.

Als je
a = ++i + i + i++;
printf("%d", a);
doet,zal daar gewoon 3 uitkomen.

Maar dat de side-effects van ++i en i++ vaag zijn en lastig zijn voor een compiler, daar zijn we nu wel achter.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Sjaaky: Toen zag ik ergens in een voorbeeld i := i + 1; staan. Eigenlijk vond ik dat maar vreemd, want i := i + 1; is in principe, gelezen als wiskundige vergelijking, niet correct. Maar goed het was een assignment en geen expression.
Tja, je moet een assignment natuurlijk ook niet lezen als een wiskundige vergelijking ;) . Juist om dat onderscheid duidelijk te maken is er in Pascal gekozen voor := ipv = net als in veel andere talen (overigens ben ik ook hier een voorstander van).
Daarom gebruik ik een expressie als i++; alleen los, dus niet als deel van een grotere expressie.
Das in ieder geval mooi ;) .
Als je i++ wilt afschaffen, moet de 'industry standard' for-loop for(int i=0; i < size; i++){..} herschreven worden naar for(int i=0; i < size; i=i+1){..}.
Ho ho, nu begrijp je mijn ideeen verkeerd. Ik wil i++ absoluut niet afschaffen. Ik wil dat i++ geen expressie meer is. In de bekende for-loop wordt i++ niet als een expressie gebruikt, dus dit kan je gewoon blijven toepassen. Ik wil juist dat wat jij net beschrijft:
Op school werden constructies als a = 4 + i++; evil beschouwd, vanwege de side-effects op i. Daarom gebruik ik een expressie als i++; alleen los
niet alleen op school wordt aangeleerd, maar ook door de taal wordt afgedwongen. Waarom zou je evil-constructies toestaan in een taal en dan tegen iedereen gaan vertellen dat het zo evil is?
Je kan het hele euvel wel oplossen door i++; gewoon een statement en geen expressie te laten zijn. i++ 'heeft' dan geen waarde. Dus kan je i++ alleen los gebruiken.
Ja, en dat is dus precies wat ik voorstelde :? . Als je een assignment een statement maakt en geen expressie kan je i++ en ++i (inderdaad geen verschil meer dan) gewoon blijven gebruiken.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • SWfreak
  • Registratie: Juni 2001
  • Niet online
Duidelijk is dat als assignments geen expressies meer zijn je een heleboel vage situaties niet meer tegenkomt. Toch doe ik liever dit:
code:
1
2
if( NULL == (fp = fopen(...)))
 //error code

dan dit:
code:
1
2
3
fp = fopen(...)
if( fp == NULL )
 //error code

Maar dat is misschien een kwestie van smaak. Volgens mij is het het beste als i++ gewoon geen resultaat oplevert. Ik echter zie niet in wat het probleem zou moeten zijn met expressies als j = i = i + x. (j = i++ is eigenlijk ook niet eens zo raar :))

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 21:50
Op zondag 26 mei 2002 14:28 schreef SWfreak het volgende:
Volgens mij is het het beste als i++ gewoon geen resultaat oplevert.
En al die mooie 'while(x++)' constructies dan? Als ik inefficiente lappen code wil schrijven, met overvloedige flow control statements, gebruik ik wel Java. De verworvenheid van C (en in iets mindere mate C++) is juist dat je zo efficient kan programmeren als je zelf maar wilt. Niemand verplicht je verder om 'a = x++' te schrijven, maar het zou van pas kunnen komen.

Daarbij heb ik beginners vaak genoeg onleesbare code zien schrijven met eenvoudige en onomstrede constructies als if-then-else, die zo gecombineerd waren dat elke vorm van structuur uit het programma verdwenen was.

Het uit een taal verwijderen van krachtige constructies ten behoeve van mensen die er fouten mee zouden kunnen maken is een nobel streven, maar het leidt er wel toe dat je uitkomt op een programmeertaal waar je niets mee kan.

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op zaterdag 25 mei 2002 23:06 schreef mbravenboer het volgende:
... Ik wil i++ absoluut niet afschaffen. Ik wil dat i++ geen expressie meer is. In de bekende for-loop wordt i++ niet als een expressie gebruikt, dus dit kan je gewoon blijven toepassen.
't Is vervelend, maar <expr>++ blijkt een essentiele expressie te zijn om sommige C++ constructies exception-safe te krijgen. De temporary die gegenereerd wordt kan veilig gebruikt worden, omdat het origineel een andere waarde gekregen heeft. En de enige manier waarop je de temporary kunt gebruiken is via de rvalue van de postfix increment expressie.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op zaterdag 25 mei 2002 16:51 schreef mbravenboer het volgende:
Ik vraag me af of het uberhaupt in de standaard gedefineerd is wat de semantiek van een expressie is, waarin zowel i als ++i op i++ voorkomt?
Expliciet gedefinieerd dat het niet gedefinieerd is.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op vrijdag 24 mei 2002 17:45 schreef JayTaph het volgende:

[..]

Dit snap ik niet helemaal. Voor i++; zou ik dan wel een register moeten vrijmaken, en voor ++i; niet?
code:
1
2
3
4
int i=2;

f(i++); // i==3 in f, maar f is aangeroepen met arg==2
f(++i); // Maar een integer; i==arg(f)==4

i++ levert twee ongelijke waarden op; die twee waarden moet natuurlijk op twee locaties bewaard worden.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op zaterdag 25 mei 2002 15:47 schreef Sjaaky het volgende:
Om de discussie nog een beetje aan te wakkeren (of zou dat in een nieuw topic moeten??), het volgende stukje code.
code:
1
  [bugs]

Bij dit stuk code verwacht ik de uitvoer:
12 17 22 22 27
Maar in g++ 2.95.2 krijg ik het antwoord:
12
18 <-- deze waarde is vaag.
22
23 <-- deze ook, vooral vergeleken met de bovenstaande 22
27
Bovenstaande resultaten krijg ik ook msvc6.0 Debug mode terug, in release mode krijg ik:
12
18
24 <-- vaag was eerst 22.
23
30 <-- i wordt dus eerst 6, daarna bij elkaar opgeteld.

Nu weet ik dat de expressies behoorlijk ranzig zijn, maar het gedrag van msvc6 vind ik eigenlijk om te :r.
Ik snap bij j = i + ++i + i; dat de compilers eerst ++i gaan uitrekenen en daarna de rest pas, maar dan houden ze dus geen rekening met de side-effects van ++i;

Bij gebruik van i++ wordt i trouwens altijd pas als allerlaatste in de expressie opgehoogd.
Tsja, de laatste regel geeft het al aan: Je weet niet precies wat i++ doet, of ++i.
Legitiem gedrag voor je code is een lowlevel HD format, en een post naar GoT om te laten zien wat je gedaan hebt. Wat je namelijk doet is een variabele (i) lezen op het moment dat de compiler hem legitiem mag schrijven. Dat is undefined behavior. In een expressie waarin je i++ of ++i gebruikt mag je verder i niet gebruiken. De update is pas gegarandeerd na een functie call , een ; of een ander sequence point.

Dit verschilt van Java, waar de JVM minder mogelijkheden heeft om de i++ write te doen. Effectief heeft Java veel meer sequence points.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
MSalters: 't Is vervelend, maar <expr>++ blijkt een essentiele expressie te zijn om sommige C++ constructies exception-safe te krijgen.
Ik ben niet erg goed bekend met C++ en ik snap (wellicht daarom) niet waar je op doelt. Wat heeft de assignment met exceptions te maken? Kan je een concreet voorbeeld geven?
MSalters: Expliciet gedefinieerd dat het niet gedefinieerd is.
Ah, daar kan ik me wel in vinden :) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Sjaaky
  • Registratie: Oktober 2000
  • Laatst online: 03-09 23:48
Op maandag 27 mei 2002 10:13 schreef MSalters het volgende:
Legitiem gedrag voor je code is een lowlevel HD format, en een post naar GoT om te laten zien wat je gedaan hebt.
Als ze dat in de specs zetten, waarom niet? :+
Zijn de officiële specs eigenlijk ergens gratis vandaan te halen?

Ik was idd niet op de hoogte van de specs.
Ik weet dat het voor een compiler wellicht lastig te implementeren is, maar zou het geen idee zijn, om de compiler de warning "Expression on line x is relying on undefined behaviour." te laten geven.

  • JayTaph
  • Registratie: Oktober 1999
  • Laatst online: 28-11-2025

JayTaph

Portability is for canoes.

Op maandag 27 mei 2002 10:06 schreef MSalters het volgende:

f(i++); // i==3 in f, maar f is aangeroepen met arg==2
f(++i); // Maar een integer; i==arg(f)==4[/code]
i++ levert twee ongelijke waarden op; die twee waarden moet natuurlijk op twee locaties bewaard worden.
Theoretisch klopt je verhaal, helaas verteld gcc mij iets anders:
code:
1
2
3
4
5
6
7
8
9
10
11
12
  ; f(++i)
  incl -4(%ebp)     <- i = i + 1
  movl -4(%ebp), %eax
  pushl %eax         <- i naar parameter stack
  call f
  addl $4, %esp     <- pop/destroy i from stack

  movl -4(%ebp), %eax
  pushl %eax         <- EERST "oude" i op de stack zetten
  incl -4(%ebp)     <- daarna pas increasen
  call f
  addl $4, %esp     <- meuk weer weggooien

Het klopt dat er tijdens de expressie 2 verschillende waardes onstaan voor i, alleen wordt dit opgelost door i op de parameter stack te pushen voordat er iets gedaan wordt met deze variabele. Het maakt (in dit geval althans) niets uit of ik hier ++i of i++ gebruik, aangezien de i zowiezo op de stack gezet moet worden. Het gebeurd met ++i gewoon een paar instructies eerder.



Maar wat zegt gcc -S van de "buggy" msvc code (wat ik nog steeds heeeeel vreemd vind, maar goed :))
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  ; i = 5;
  movl $5, -4(%ebp)
  ; j = ++i + i;
  incl -4(%ebp)     ; ++i als eerste (i = 6)
  movl -4(%ebp), %ecx   ; i in temp register  (6)
  addl -4(%ebp), %ecx   ; add i (12)
  movl %ecx, -8(%ebp)   ; en resultaat in j

  ; i = 5;
  movl $5, -4(%ebp)   
  ; j = i + ++i + i;
  incl -4(%ebp)     ; ++i als eerste (i = 6)
  movl -4(%ebp), %eax   ; eax = i (6)
  addl -4(%ebp), %eax   ; eax+= i (12)
  movl -4(%ebp), %ecx   ; ecx = i (6)
  addl %eax, %ecx       ; ecx +=eax = 18
  movl %ecx, -8(%ebp)   ; j = 18 
  ; beetje kromme code voor de laatste addition, maar goed :+
  
  ; i = 5;
  movl $5, -4(%ebp)
  ; j = i + i + ++i + i;
[b]
  movl -4(%ebp), %eax        ; EERST WORDT I + I GEDAAN!    
  addl -4(%ebp), %eax
[/b]
  incl -4(%ebp)          ; EN NU PAS ++I
  addl -4(%ebp), %eax        ; 5 + 5 + 6 = 16
  movl -4(%ebp), %ecx        ; 6
  addl %eax, %ecx            ; 16 + 6 = 22
  movl %ecx, -8(%ebp)        ; j = 22


  ; i = 5;
  movl $5, -4(%ebp)
  ; j = i + 5 + ++i + i;
  incl -4(%ebp)          ; Nu wel eerst ++i
  movl -4(%ebp), %eax        ; 6
  addl $5, %eax          ; constante 5 toevoegen = 11
  movl %eax, %edx            ; edx = 11
  addl -4(%ebp), %edx        ; edx = 17
  movl -4(%ebp), %ecx        ; ecx = 6
  addl %edx, %ecx            ; ecx = 6 + 17 = 23
  movl %ecx, -8(%ebp)       

  ; i = 5;
  movl $5, -4(%ebp)
  ; j = i + i + i + ++i + i;
  movl -4(%ebp), %eax        ; 5
  addl -4(%ebp), %eax        ; + 5 = 10
  movl %eax, %edx
  addl -4(%ebp), %edx        ; 15
[b]
  incl -4(%ebp)          ; NA 3 KEER EEN OPTELLING PAS ++I!!
[/b]
  movl %edx, %eax
  addl -4(%ebp), %eax       ; eax = 21
  movl -4(%ebp), %ecx       ; ecx = 6
  addl %eax, %ecx           ; 27
  movl %ecx, -8(%ebp)

Er zitten dus een vreemde eigenaardigheid aan ++i, namelijk dat je er niet op kunt vertrouwen |:(

Volgens de normale operator precendence gaat ++i (unary ++) voor een binary + (dus een optelling tussen 2 getallen, een + als in positief getal heeft een gelijke precendence met ++). Dit doet GCC dus niet in alle gevallen (in het voorbeeld tijdens een "i + i +" in het statement).

Yo dawg, I heard you like posts so I posted below your post so you can post again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op maandag 27 mei 2002 11:12 schreef mbravenboer het volgende:

[..]

Ik ben niet erg goed bekend met C++ en ik snap (wellicht daarom) niet waar je op doelt. Wat heeft de assignment met exceptions te maken? Kan je een concreet voorbeeld geven?
Dat wordt een vrij lang verhaal; het zou met afstand het meest (8> topic ooit worden in P&W. Maar het principe valt wel uit te leggen:
Om code exception-safe te krijgen moet je zorgen dat er geen informatie verloren gaat in de processing. Zo moet je in een (class) assignment zorgen dat de oude waarde van de members bewaard blijft totdat je alle throwing copies gemaakt hebt. i++ maakt he mogelijk om veilig op een oude
kopie te werken terwijl i een nieuwe waarde heeft.

erase() heeft vergelijkbare problemen; neem b.v
[code] list_iterator i; // pseudo-
code:
1
erase(i++);

Afhankelijk van exceptions uit erase en de excate list implementatie is de oude waarde van i onbruikbaar, maar de post-increment gebeurt nu precies op het goede punt om i veilig te stellen. De temporary list_iterator verdwijnt precies op het goede punt, nl. zodra die onbruikbaar is.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • JayTaph
  • Registratie: Oktober 1999
  • Laatst online: 28-11-2025

JayTaph

Portability is for canoes.

>Afhankelijk van exceptions uit erase en de excate list
>implementatie is de oude waarde van i onbruikbaar, maar de
>post-increment gebeurt nu precies op het goede punt om i
>veilig te stellen. De temporary list_iterator verdwijnt >precies op het goede punt, nl. zodra die onbruikbaar is.

Ik weet intern niet genoeg af van C++ om hiervan zeker te zijn, maar volgens mij wordt dit ook gewoon met de stack opgelost (op dezelfde manier als mijn bovenstaande post)

>het zou met afstand het meest (8> topic ooit worden in P&W.
Och, er zitten af en toe interessante (lees: php+ niveau) topics in P&W. Alleen hoef je meestal niet te verwachten dat er veel mensen op reageren dus worden dat soort topics ook al niet eens geopend (wat ik trouwens nog steeds wel jammer vind)

Yo dawg, I heard you like posts so I posted below your post so you can post again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op maandag 27 mei 2002 11:38 schreef Sjaaky het volgende:

[..]

Als ze dat in de specs zetten, waarom niet? :+
Zijn de officiële specs eigenlijk ergens gratis vandaan te halen?
Nee natuurlijk; de kosten van het "officiele" moeten toch ergens door betaald worden. Maar $18 is niet zo gek veel voor professionals, en voor de rest is er een redelijke gratis draft ( en die is dan ook nog eens van 2001 )
Ik was idd niet op de hoogte van de specs.
Ik weet dat het voor een compiler wellicht lastig te implementeren is, maar zou het geen idee zijn, om de compiler de warning "Expression on line x is relying on undefined behaviour." te laten geven.
Als dat mogelijk was hadden we het wel "diagnosable behavior" gemaakt. Iha kan de compiler niet opmerken dat't
fout gaat:
code:
1
2
3
4
5
6
7
8
int foo( int& a, int& b )
{
  return ++a + ++b;
}
// --- andere file ---
int i,j=0;
foo( i,j ); // ok
foo( i,i ); // niet ok

Geen van beide files is op zich fout, maar de combinatie werkt niet. De linker zou't kunnen opmerken, maar die checkt normaal gesproken alleen interfaces.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op maandag 27 mei 2002 12:08 schreef JayTaph het volgende:
Volgens de normale operator precendence gaat ++i (unary ++) voor een binary + (dus een optelling tussen 2 getallen, een + als in positief getal heeft een gelijke precendence met ++). Dit doet GCC dus niet in alle gevallen (in het voorbeeld tijdens een "i + i +" in het statement).
Nee, je vergist je. Ten eerste is de C++ grammar niet precedence-based; de interpretatie is gebaseerd op "producties" die vergelijkbare resultaten leveren. Precendences gaven IIRC problemen met ?: (want ternaire operatie).
Ten tweede is dit alleen relevant voor het parsen. De increment moet plaatsvinden na de evaluatie van de increment-subexpressie, en voor de ;. Evaluatie van andere sub-expressies, ook als ze toevallig i gebruiken gebeurt in parallel met de increment. Daarom kun je in theorie ook een buserror krijgen met dat soort statements.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • JayTaph
  • Registratie: Oktober 1999
  • Laatst online: 28-11-2025

JayTaph

Portability is for canoes.

Geen van beide files is op zich fout, maar de combinatie werkt niet. De linker zou't kunnen opmerken, maar die checkt normaal gesproken alleen interfaces.
Mochten twee pointers dan gelijk zijn (bijvoorbeeld bij sortering, of bij link lists dan) dan zou dat een waarschuwing opleveren.
code:
1
2
3
4
5
6
ITEM *root;
ITEM *item1;

root = (ITEM *)malloc (sizeof (ITEM));
item1 = root;
do_iets_met_item1_waarbij_root_ook_nodig_is (root, item1);

(en het is de compiler die over dit soort dingen gaat :))

Yo dawg, I heard you like posts so I posted below your post so you can post again.


  • packman
  • Registratie: November 2000
  • Laatst online: 17-12-2024
Op vrijdag 24 mei 2002 12:38 schreef Soultaker het volgende:

...

Niet volgens de ANSI C standaard. Die verplicht je tot het specificeren van het return type. Een ANSI C compiler verwerpt deze code.

...
Dit is niet waar. Standaard ansi C neemt inderdaad int als default return type (en dan zijn int nog 16 of 32 bit - afhankelijk van het targetplatform :r - waarom konden ze dat niet ineens GOED specifieren - tsja - komt ervan als je een type wil hebbe dat zo performant mogelijk is op het target platform).
En je kan in een void functie zelfs perfect een waarder returnen met een mooie return :P - wordt gewoon op je stack gezet volgens standaard ansi C - je stack gaat er enkel een beetje rommelig van worden als je compiler er dan mee in de knoei geraakt >:) - voor C++ weet ik het niet. Veel compilers tegenwoordig (lees: de meeste) reclameren er wel op - of fixen het zelf - maar ik werk hier soms met embedded dinosaurus-compilertjes - en die laten dat meestal rustig toe... Een C compiler is niet zo strikt als een java compiler he :P

overigens wel fijn dat een "n00b" topic ontaard in een topicje met niveau :P

I heard if you play the XP CD backwards, you get a satanic message. Thats nothing compared to what happens if you play it forward, then it installs Windows XP born2oc.be - Facts Of Life


  • JayTaph
  • Registratie: Oktober 1999
  • Laatst online: 28-11-2025

JayTaph

Portability is for canoes.

Op maandag 27 mei 2002 12:42 schreef MSalters het volgende:

[..]

Nee, je vergist je. Ten eerste is de C++ grammar niet precedence-based; de interpretatie is gebaseerd op "producties" die vergelijkbare resultaten leveren. Precendences gaven IIRC problemen met ?: (want ternaire operatie).
De gcc-assembly is pure C-code ;)
Ten tweede is dit alleen relevant voor het parsen. De increment moet plaatsvinden na de evaluatie van de increment-subexpressie, en voor de ;. Evaluatie van andere sub-expressies, ook als ze toevallig i gebruiken gebeurt in parallel met de increment. Daarom kun je in theorie ook een buserror krijgen met dat soort statements.
Ok, wat ik dus begrijp van dit bericht is dat subexpressies in willekeurige volgorde mogen worden geevalueerd en dat de precedence daar geen zegenschap over heeft. In dat geval zou het hele verhaal dus wel kloppen en zou je dus de evaluatie-order moeten forcen mocht je ooit gebruik willen maken van een dergelijke constructie (die een normaal denkend persoon nooit zou doen, vandaar ik ook nooit het precendence/evaluatie verschil heb bemerkt :)).

Yo dawg, I heard you like posts so I posted below your post so you can post again.


Verwijderd

a = ++i + i + i++;
doet,zal daar gewoon 3 uitkomen.
Uh is toch ook gewoon 4 of zit ik er nu helemaal naast???
de unaire operatoren gaan toch gewoon voor de binaire operatoren???

er staat toch eigelijk gewoon:
i = 0;
++i;
a = i + i;
i++;
a = a + i;

Verwijderd

En zo willekeurig is de volgorde ook niet tijdens de evaluatie:
code:
1
2
3
4
5
a = 0;
if (a++) // zal false zijn

b = 0;
if (++b) // zal true zijn

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op maandag 27 mei 2002 12:47 schreef JayTaph het volgende:

[..]

Mochten twee pointers dan gelijk zijn (bijvoorbeeld bij sortering, of bij link lists dan) dan zou dat een waarschuwing opleveren.
code:
1
2
3
4
5
6
ITEM *root;
ITEM *item1;

root = (ITEM *)malloc (sizeof (ITEM));
item1 = root;
do_iets_met_item1_waarbij_root_ook_nodig_is (root, item1);

(en het is de compiler die over dit soort dingen gaat :))
Maar hoe weet de compiler, gegeven deze code en de declaratie
code:
1
do_iets_met_item1_waarbij_root_ook_nodig_is(ITEM*, ITEM*)

dat'ie een warning moet uitspugen? :? Dat wordt leuk voor alle functies die een range als pointers accepteren, bv. alle STL functies

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • JayTaph
  • Registratie: Oktober 1999
  • Laatst online: 28-11-2025

JayTaph

Portability is for canoes.

Op maandag 27 mei 2002 13:52 schreef markvleth het volgende:

[..]

Uh is toch ook gewoon 4 of zit ik er nu helemaal naast???
de unaire operatoren gaan toch gewoon voor de binaire operatoren???

er staat toch eigelijk gewoon:
i = 0;
++i;
a = i + i;
i++;
a = a + i;
Nee dus (ben ik ook net achter sinds een klein uurtje :)). De volgorde van sub-expressies hebben niets te maken met de precendence. Met andere woorden: je compiler mag er gerust

a = i + i;
i++;
a = a + i;

van maken, en doet dat ook gerust.

Wat ik begrepen heb, is dat precendence aangeeft wat de subexpressies zijn. De expressie a = 1 + 2 * 3 heef 2 expressies: 1 en 2 * 3. Maar deze hoeven niet in die volgorde worden uitgevoerd. Vandaar dat dit ook invloed kan hebben op eventuele veranderingen van variabelen binnen de expressie (bijvoorbeeld met ++i, i++, functie(i) etc).

Yo dawg, I heard you like posts so I posted below your post so you can post again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op maandag 27 mei 2002 13:52 schreef markvleth het volgende:

[..]

Uh is toch ook gewoon 4 of zit ik er nu helemaal naast???
de unaire operatoren gaan toch gewoon voor de binaire operatoren???

er staat toch eigelijk gewoon:
i = 0;
++i;
a = i + i;
i++;
a = a + i;
Nee - jij zet er opeens heel veel sequence points (met ;) tussen, waardoor de compiler verplicht die volgorde moet volgen. De waarde van 'i' is tussen twee sequence points is alleen bruikbaar als je'm daar niet wijzigt.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • JayTaph
  • Registratie: Oktober 1999
  • Laatst online: 28-11-2025

JayTaph

Portability is for canoes.

Op maandag 27 mei 2002 14:00 schreef MSalters het volgende:

[..]

Maar hoe weet de compiler, gegeven deze code en de declaratie
code:
1
do_iets_met_item1_waarbij_root_ook_nodig_is(ITEM*, ITEM*)

dat'ie een warning moet uitspugen? :? Dat wordt leuk voor alle functies die een range als pointers accepteren, bv. alle STL functies
Niet, maar aangezien deze dingen runtime op de stack worden gezet, *KAN* de compiler in sommige gevallen (maar meestal niet) het wel zien dat er 2 keer een dezelfde pointers worden gebruikt. Het zouden dan wel twee constantes moeten zijn anders werkt het niet..

Al met al is het dus niet echt iets waarop je een warning wilt krijgen dus :)

Yo dawg, I heard you like posts so I posted below your post so you can post again.


Verwijderd

Op maandag 27 mei 2002 14:00 schreef JayTaph het volgende:

[..]

Nee dus (ben ik ook net achter sinds een klein uurtje :)). De volgorde van sub-expressies hebben niets te maken met de precendence. Met andere woorden: je compiler mag er gerust

a = i + i;
i++;
a = a + i;

van maken, en doet dat ook gerust.
[..]
Oh dat wist ik, maar ja, gelukkig wil je ook nooit praktisch onleesbare code als ++i + i + i++ schrijven. Dus vanuit dat oogpunt zou de compiler er inderdaad mee mogen doen wat deze wil.

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op maandag 27 mei 2002 12:51 schreef packman het volgende:

[..]

Dit is niet waar. Standaard ansi C neemt inderdaad int als default return type (en dan zijn int nog 16 of 32 bit - afhankelijk van het targetplatform :r - waarom konden ze dat niet ineens GOED specifieren - tsja - komt ervan als je een type wil hebbe dat zo performant mogelijk is op het target platform).
Ja - eigenlijk zou main() een enum moeten retourneren.
En je kan in een void functie zelfs perfect een waarder returnen met een mooie return :P - wordt gewoon op je stack gezet volgens standaard ansi C - je stack gaat er enkel een beetje rommelig van worden als je compiler er dan mee in de knoei geraakt >:) - voor C++ weet ik het niet. Veel compilers tegenwoordig (lees: de meeste) reclameren er wel op - of fixen het zelf - maar ik werk hier soms met embedded dinosaurus-compilertjes - en die laten dat meestal rustig toe... Een C compiler is niet zo strikt als een java compiler he :P
Standaard ANSI C (of C++) heeft niet eens een stack. Dat is een gangbare implementatie, maar een RISC machien kant best een register voor de return value gebruiken. Als je dan in een void() functie iets in dat register schrijft, tsja, dan heb je geen idee wat je overschrijft.

Maar C en C++ hebben sowieso speciale regels voor embedded compilers; een koffiezetter mag wel void main() doen.
Geeft een beetje aan op wat voor soort machines MSVC thuishoort >:)

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • JayTaph
  • Registratie: Oktober 1999
  • Laatst online: 28-11-2025

JayTaph

Portability is for canoes.

>Maar C en C++ hebben sowieso speciale regels voor embedded
>compilers; een koffiezetter mag wel void main() doen.
Hangt dat niet gewoon af van je crt0?

Yo dawg, I heard you like posts so I posted below your post so you can post again.


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
MSalters: Om code exception-safe te krijgen moet je zorgen dat er geen informatie verloren gaat in de processing. Zo moet je in een (class) assignment zorgen dat de oude waarde van de members bewaard blijft totdat je alle throwing copies gemaakt hebt.
Ik lees je posts met stijgende verbazing... Met diverse colleges compilerbouw achter de rug zijn termen als throwing copies volledig nieuw voor me ;) . Overigens weet ook Google er geen raad mee, dus helaas heb ik niet uit kunnen vinden waar deze term exact over gaat.

Gelukkig kon ik op exception-safe wel veel vinden en toen werd het mij wat duidelijker :) . Je doelt op atomaire operaties mbt exceptions...

De link met de behoefte aan een post-increment operatie als expressie ontgaat mij alleen nog. Dat er een kopie wordt gemaakt die je dan kunt gebruiken is mij duidelijk, maar die temporary kan je toch ook zelf aanmaken in een assignment aan een tijdelijke variabele? Leidt deze aanpak dan tot de onmogelijkheid om een bepaalde constructie exception-safe te krijgen?

Sterker nog, ik heb wat rond zitten bladeren in documenten over exception-safety, maar daar wordt de increment instructie bijvoorbeeld afgeraden in de LHS van een assigment als de RHS een exception kan opleveren. Dit lijkt mij dus juist nog een extra argument tegen het gebruik van increment als een expressie.

Ik heb dit als voornaamste bron gebruikt.

Het is misschien een beetje veel gevraagd om dit allemaal uit te gaan leggen, maar ik kon dus echt geen bronnen vinden die goed aansluiten op dit probleem. Misschien kan jij wat bronnen geven?

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
MSalters: Nee, je vergist je. Ten eerste is de C++ grammar niet precedence-based; de interpretatie is gebaseerd op "producties" die vergelijkbare resultaten leveren.
Idd, maar prioriteiten en associativiteit bepalen op basis van producties (dmv herschrijving van je voorheen duidelijke grammatica) is naar mijn mening toch wel een techniek die vooral is voortgekomen uit de beperkingen aan de grammatica's die de generatie parser-generators accepteren waar we nu al flinke tijd mee zitten...

Als je overstapt op volledig context-vrije grammatica's kan je zulke zaken best met prioriteiten regelen, wat bijvoorbeel gedaan wordt in Generalized LR Parsing en het Sytax Defintion Formalism (SDF)
Ten tweede is dit alleen relevant voor het parsen.
Das waar :) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 21:50
Op maandag 27 mei 2002 12:42 schreef MSalters het volgende: [over precedence van operators]
Nee, je vergist je. Ten eerste is de C++ grammar niet precedence-based; de interpretatie is gebaseerd op "producties" die vergelijkbare resultaten leveren. Precendences gaven IIRC problemen met ?: (want ternaire operatie).
Hmm, dit heb ik eigenlijk niet begrepen, kun je dat nog een beetje toelichten? (Wat zijn producties en wat voor problemen geeft een ternaire operator als ?: )?
Ten tweede is dit alleen relevant voor het parsen. De increment moet plaatsvinden na de evaluatie van de increment-subexpressie, en voor de ;. Evaluatie van andere sub-expressies, ook als ze toevallig i gebruiken gebeurt in parallel met de increment. Daarom kun je in theorie ook een buserror krijgen met dat soort statements.
Het is jammer dat dit zo gespecificeerd is. Het lijkt mij veel logischer om te stellen dat bij het evalueren van de increment operator (of 't nou om post- of pre-increment gaat) de waarde gewijzigd wordt.

Als je in het voorbeeld:
code:
1
++i + i + i++

stelt dat expressies van links naar rechts worden geevalueerd en de increment operaties precedence hebben over de optelling, is dan maar één interpretatie mogelijk en dat is ook de meest logische.

In de praktijk zal mag de compiler die increments natuurlijk best later pas uitvoeren, maar dat is voor de programmeur niet interessant.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Soultaker: Hmm, dit heb ik eigenlijk niet begrepen, kun je dat nog een beetje toelichten? (Wat zijn producties en wat voor problemen geeft een ternaire operator als ?: )?
Producties worden gebruikt in context-vrije grammatica's.

Vb:
code:
1
2
3
Plus: Exp "+" Exp -> Exp
Mul: Exp "+" Exp -> Exp
BinOp: Op * Exp * Exp -> Exp

De eerste beschrijft een productie regel met het label "Plus" en als resultaat type "Exp". De argumenten van deze constructor/productie zijn twee expressies, welke gescheiden zijn door een "+". Merk op dat hier dus geen lexicale informatie instaat over bijvoorbeeld layout.

De laatste is een generalisatie van expressies met een binaire operator en wordt meestal in latere fasen van een compiler gebruikt.

Met behulp van het herschrijven van je productie-regels kan je de prioriteiten van operatoren beinvloeden. Het meest bekende voorbeeld is wel de combinatie van rekenkundige expressies met * en +.
code:
1
1 + 2 * 3

Dit moet uiteraard geinterpreteerd worden als
code:
1
1 + (2 * 3)

Maar als je de bovenstaande twee producties gebruikt kan de parser deze expressie ook eigenwijs opbouwen door haakjes rond 1 + 2 te zetten (die haakjes zijn hier eigenlijk een soort visualisatie van de manier waarop de parse-trees zijn opgebouwd. In werkelijkheid zijn er helemaal geen haakjes bij betrokken.

Omdat de meeste parser-generators maar een subklasse van context-vrije grammatica's accepteren en geen ambiguiteiten kunnen oplossen moet je deze zelf oplossen door je grammatica zo te herstructureren dat de prioriteiten volgen uit de producties van je grammatica.

Het nadeel van deze aanpak is dat je eigenlijk je grammatica onduidelijk aan het maken bent ten behoeve van de beperkingen van de parser-generator. Dat is niet prettig, maar het functioneert wel :) .

In C++ zijn de prioriteiten van de operatoren dus kennelijk gebaseerd op basis van producties (wat ik overigens ook niet wist en wat ik jammer vind).

Overigens kan je C++ eigenlijk sowieso al niet context-vrij parsen, wat best wel vervelend... Wat precies het probleem is met de :? operator weet ik eigenlijk zo ook niet...
stelt dat expressies van links naar rechts worden geevalueerd en de increment operaties precedence hebben over de optelling, dan is er maar één interpretatie mogelijk. Hoe de compiler dit realiseert is verder niet relevant.
De parser bepaald aan de hand van de grammatica hoe deze expressie geinterpreteerd moet worden in boom vorm. Dit zal dan zorgen voor dit:
code:
1
(++i) + i + (i++)

of in boomvorm bijvoorbeeld:
code:
1
2
3
4
5
6
7
        +
        /   \
 pre-incr    +
   |         / \
   i        i  post-incr
              |
              i

Andere vormen zijn eigenlijk niet mogelijk (behalve herstructering van deze boom) en de prioriteiten spelen hier daarom eigenlijk geen rol: (i + i)++ is namelijk niet echt een geldige expressie (misschien wel als de ++
overloaded is, maar goed...)

De semantische betekenis van deze expressie is echter wel ambigu omdat het niet gespecificeerd is wanneer en in welke volgorde de assigments uitgevoerd moeten worden.

Jij stelt:
dat expressies van links naar rechts worden geevalueerd
Als ik het goed begrepen heb van MSalters kan je dat dus niet stellen (gelukkig). Als dit gespecificeerd zou zijn, zou een compiler maar weinig vrijheid meer hebben om de expressies zo optimaal mogelijk te compileren.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op maandag 27 mei 2002 14:15 schreef JayTaph het volgende:
>Maar C en C++ hebben sowieso speciale regels voor embedded
>compilers; een koffiezetter mag wel void main() doen.
Hangt dat niet gewoon af van je crt0?
Ja - koffiezetter mag crt0 hebben die void main() support

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op maandag 27 mei 2002 16:41 schreef mbravenboer het volgende:

[..]

Ik lees je posts met stijgende verbazing... Met diverse colleges compilerbouw achter de rug zijn termen als throwing copies volledig nieuw voor me ;) . Overigens weet ook Google er geen raad mee, dus helaas heb ik niet uit kunnen vinden waar deze term exact over gaat.
C::C( C const& ) {
if (rand()%2 ) throw"I'm a throwing copy ctor";
}
Kopieert wat lastiger...
Het is misschien een beetje veel gevraagd om dit allemaal uit te gaan leggen, maar ik kon dus echt geen bronnen vinden die goed aansluiten op dit probleem. Misschien kan jij wat bronnen geven?
www.gotw.ca. Taaie kost, ook in 3 cm boekvorm.
edit:
't Is Item 9 in MEC++

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
MSalters: www.gotw.ca. Taaie kost, ook in 3 cm boekvorm.
Ah, bedankt :) . Die was ik inderdaad ook al eerder tegen gekomen. Ik zal eens overwegen om dat materiaal aan te schaffen.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 21:50
Op maandag 27 mei 2002 17:55 schreef mbravenboer het volgende:
[knip]uitleg over productieregels[/knip]
Ah, cool, thanks. Die theorie is me bekend, maar ik kon de term "productie" even niet plaatsen.
Omdat de meeste parser-generators maar een subklasse van context-vrije grammatica's accepteren en geen ambiguiteiten kunnen oplossen moet je deze zelf oplossen door je grammatica zo te herstructureren dat de prioriteiten volgen uit de producties van je grammatica.
Voor een deel kan dat natuurlijk automatisch, door je regels in de goede 'volgorde' te zetten. Je wilt ten behoeve van de efficientie natuurlijk wel voorkomen dat een parser een heel bestand in z'n geheel moet verwerken voordat de eerste uitvoer gegenereert kan worden.

Ik denk trouwens dat dat argument vroeger belangijker was dan tegenwoordig (hoewel sommige compilers nog steeds wel ontzettend traag zijn).
Overigens kan je C++ eigenlijk sowieso al niet context-vrij parsen, wat best wel vervelend...
Hmm, dat zou zomaar de reden kunnen zijn dat de GCC compiler C++ een factor 10 trager compileert dan C code (hoewel het parsen natuurlijk maar een deel van het compileerproces is).
De parser bepaald aan de hand van de grammatica hoe deze expressie geinterpreteerd moet worden in boom vorm. Dit zal dan zorgen voor dit:
code:
1
(++i) + i + (i++)

of in boomvorm bijvoorbeeld:
code:
1
2
3
4
5
6
7
        +
        /   \
 pre-incr    +
   |         / \
   i        i  post-incr
              |
              i

Andere vormen zijn eigenlijk niet mogelijk (behalve herstructering van deze boom) en de prioriteiten spelen hier daarom eigenlijk geen rol: (i + i)++ is namelijk niet echt een geldige expressie (misschien wel als de ++
overloaded is, maar goed...)

De semantische betekenis van deze expressie is echter wel ambigu omdat het niet gespecificeerd is wanneer en in welke volgorde de assigments uitgevoerd moeten worden.
Dat klopt. Ik wilde ook alleen maar zeggen dat deze ambiguiteit eenvoudig weggewerkt kan worden door (bijvoorbeeld) te stellen dat expressies verwerkt worden in de volgorde waarin ze in de code staan. Ik kan me voorstellen dat een andere afspraak handiger is, maar dat maakt voor de eenduidigheid natuurlijk niet uit.
Als ik het goed begrepen heb van MSalters kan je dat dus niet stellen (gelukkig). Als dit gespecificeerd zou zijn, zou een compiler maar weinig vrijheid meer hebben om de expressies zo optimaal mogelijk te compileren.
Dat zal in C de overweging inderdaad wel geweest zijn. Natuurlijk staat het de compiler vrij om de volgorde van evaluatie aan te passen, als de uitkomst maar overeenkomt met de specificatie. Dat wordt natuurlijk moeilijk als er veel termen tussen zitten met (mogelijke) side-effects, zoals functies en dergelijke.

Als ik er over nadenk is de door de SWFreak gevonden oplossing (side-effects pas nadat een statement volledig is uitgevoerd toepassen) zo slecht nog niet. Het schept in ieder geval duidelijkheid over wat de code doet, zonder veel aan efficientie te hoeven inboeten. Weet iemand misschien of dit zo in de C specificatie staat of dat dit een implementatiekeuze was?

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op maandag 27 mei 2002 17:55 schreef mbravenboer het volgende:

[..]
De parser bepaald aan de hand van de grammatica hoe deze expressie geinterpreteerd moet worden in boom vorm. Dit zal dan zorgen voor dit:
code:
1
(++i) + i + (i++)

of in boomvorm bijvoorbeeld:
code:
1
2
3
4
5
6
7
        +
        /   \
 pre-incr    +
   |         / \
   i        i  post-incr
              |
              i

Andere vormen zijn eigenlijk niet mogelijk (behalve herstructering van deze boom) en de prioriteiten spelen hier daarom eigenlijk geen rol: (i + i)++ is namelijk niet echt een geldige expressie (misschien wel als de ++
overloaded is, maar goed...)

De semantische betekenis van deze expressie is echter wel ambigu omdat het niet gespecificeerd is wanneer en in welke volgorde de assigments uitgevoerd moeten worden.

Jij stelt:
[ volgorde staat vast ]

Als ik het goed begrepen heb van MSalters kan je dat dus niet stellen (gelukkig). Als dit gespecificeerd zou zijn, zou een compiler maar weinig vrijheid meer hebben om de expressies zo optimaal mogelijk te compileren.
Precies. De compiler mag zelfs increments paralliseren omdat'ie weet dat je nooit (++i) + i + (i++) mag gebruiken in C++ (als i==int); op een Itanic is dat zelfs te verwachten. Krijg je een core dump of zo...

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Soultaker: Voor een deel kan dat natuurlijk automatisch, door je regels in de goede 'volgorde' te zetten.
Dat kan deels een oplossing zijn, maar dan heb je alleen nog vele problemen meer op te lossen, want de producties die ik hierboven gaf zullen ook niet geaccepteerd worden vanwege recursiviteit.

In het SDF wat ik eerder noemde kan dit wel en kan je bovendien tussen productie-regels de prioriteiten aangeven ipv deze vast te leggen dmv het aanpassen van je grammatica (zoals nu over het algemeen gebeurd). Deze herschrijvingen kunnen niet automatisch uitgevoerd worden omdat hier toch wel enkele voorwaarden aan verbonden zijn mbt de toegepaste operator...
Je wilt ten behoeve van de efficientie natuurlijk wel voorkomen dat een parser een heel bestand in z'n geheel moet verwerken voordat de eerste uitvoer gegenereert kan worden.
Hum, compilers werken toch meestal op bomen en niet event-gebaseerd zoals bijvoorbeeld met XML mogelijk is (SAX). Ik denk dat je daarom toch wel uit moet gaan van het volledig opbouwen van de abstract syntax tree voordat er daadwerkelijk gecompileerd kan gaan worden.
hoewel sommige compilers nog steeds wel ontzettend traag zijn
Ik denk dat het aantal traversals en de mate van analyse die wordt uitgevoerd tijdens deze traversals veruit de grootste invloed heeft op de performance. Parser technologie (en in het bijzonder generators) is al zo lang in ontwikkeling dat de performance daarvan toch wel behoorlijk goed is.
Dat klopt. Ik wilde ook alleen maar zeggen dat deze ambiguiteit eenvoudig weggewerkt kan worden door (bijvoorbeeld) te stellen dat expressies verwerkt worden in de volgorde waarin ze in de code staan.
Ah ok, je bedoelde het zo... Dat is inderdaad waar.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op maandag 27 mei 2002 18:32 schreef Soultaker het volgende:
[..]
Natuurlijk staat het de compiler vrij om de volgorde van evaluatie aan te passen, als de uitkomst maar overeenkomt met de specificatie. Dat wordt natuurlijk moeilijk als er veel termen tussen zitten met (mogelijke) side-effects, zoals functies en dergelijke.

Als ik er over nadenk is de door de SWFreak gevonden oplossing (side-effects pas nadat een statement volledig is uitgevoerd toepassen) zo slecht nog niet. Het schept in ieder geval duidelijkheid over wat de code doet, zonder veel aan efficientie te hoeven inboeten. Weet iemand misschien of dit zo in de C specificatie staat of dat dit een implementatiekeuze was?
Wat is een "hoofd"-effect, en wat een side-effect?
Denk aan while(*p++=*q++);
Volgende vraag: wat is de volgorde van side-effects?

Overigens denk ik dat de efficiency-impact van SWFreak's oplossing gigantich kan zijn; zeker op register-challenged architecturen (x86) is de kans groot dat je een register moet spillen, om'm later terug te lezen. Nu kan een compiler de spill nog voorkomen door het side-effect meteen uit te voeren en de waarde dan te schrijven; dan hoeft die later niet teruggelezen te worden. Dat scheelt fors.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Verwijderd

Op maandag 27 mei 2002 12:35 schreef MSalters het volgende:
voor de rest is er een redelijke gratis draft ( en die is dan ook nog eens van 2001 )
Ik heb met Google gezocht op het web en in newsgroups maar niks kunnen vinden over een nieuwere draft dan die van '96. Ook op IRC werd mij verteld dat dit de meest actuele gratis publieke draft is.

Heb je misschien een linkje of zo ?

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op maandag 27 mei 2002 20:50 schreef Sneechy het volgende:

[..]

Ik heb met Google gezocht op het web en in newsgroups maar niks kunnen vinden over een nieuwere draft dan die van '96. Ook op IRC werd mij verteld dat dit de meest actuele gratis publieke draft is.

Heb je misschien een linkje of zo ?
Document N1316 van SC22/WG21 site. Ik denk dat'ie publiek is, maar 't zu ook een cookie van mij kunnen zijn.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Sjaaky
  • Registratie: Oktober 2000
  • Laatst online: 03-09 23:48
Yep die is publiek, bedankt.
C++ DRAFT: 13 September 2001 hoofdstuk 5
4)

Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified. Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored.
The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full
expression; otherwise the behavior is undefined.
[Example:
i = v[i++]; // the behavior is unspecified
i = 7, i++, i++; // i becomes 9
i = ++i + 1; // the behavior is unspecified
i = i + 1; // the value of i is incremented
end example]
Dus dan ga ik voortaan maar specs lezen voor ik blaat :)

Verwijderd

Ik vindt dat in geen enkele programmeertaal ungespecificeerd gedrag mag voorkomen omdat je dan niet met zekerheid van alle constructies gebruik kunt maken doordat verschillende compiler het anders interpreteren.
Ze hadden het vrij makkelijk kunnen voorkomen toen c/c++ werd ontworpen maar nu het al vele jaren zo gebruikt wordt is het praktisch onmogelijk om nog ingrijpende veranderingen te maken van de specificatie.
Als ze de van prefix ++/-- expliciet hadden bepaald dat die vooraf uitgevoerd moeten worden en de postfix ++/-- als aller laatste, dan waren de in/de-credement toch op een handige/tricky manier te gebruiken.
En voor de huidige multipass optimalisaties van de compilers heeft het geen voordeel meer dat het gedrag ongedefineerd is.

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 07-09 08:58
Op dinsdag 28 mei 2002 10:56 schreef borganism het volgende:
Ik vindt dat in geen enkele programmeertaal ungespecificeerd gedrag mag voorkomen omdat je dan niet met zekerheid van alle constructies gebruik kunt maken doordat verschillende compiler het anders interpreteren.
Dat is maar heel gedeeltelijk waar. Zelfs binnen een enkele programmeeromgeving komt meestal ongespecificeerd gedrag voor, bv. hoe groot het scherm is of hoeveel geheugen je hebt. Dan kun je dus blindelings klagen dat je text op pixel 800,1200 onzichtbaar is op je laptop, maar da's gewoon gezeur.
Ze hadden het vrij makkelijk kunnen voorkomen toen c/c++ werd ontworpen maar nu het al vele jaren zo gebruikt wordt is het praktisch onmogelijk om nog ingrijpende veranderingen te maken van de specificatie.
In C en C++ wordt nog steeds, en met opzet, nieuw ongedefinieerd gedrag toegevoegd ( bv. http://std.dkuug.dk/JTC1/SC22/WG21/docs/cwg_active.html#195 ). Ongedefinieerd gedrag in de standaard kan nl. op platform/compiler nivo gebruikt worden om nuttige dingen toe te voegen.
Als ze de van prefix ++/-- expliciet hadden bepaald dat die vooraf uitgevoerd moeten worden en de postfix ++/-- als aller laatste, dan waren de in/de-credement toch op een handige/tricky manier te gebruiken.
1) Niet waar
code:
1
 (*(p++))++

2) Als he nuttig was had GCC 't vast gedaan
3) Code wordt er mogelijk langzamer van
En voor de huidige multipass optimalisaties van de compilers heeft het geen voordeel meer dat het gedrag ongedefineerd is.
Iets meer onderbouwing graag.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein

Pagina: 1