/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
jdjespers.. 500
kyllekylle 500
Bech_bb 500
scootergr.. 300
gibson 300
molokyle 287
10  strarup 270
hønen eller ægget?
Fra : Henrik Koksby Hansen


Dato : 12-06-02 16:15


Vi kom til at diskutere, i vores studiegruppe, om følgende kan
følgende give problemer (MS Visual C++) :


void funktion1() {

   bla bla, en masse kode med lokale variable;

   funktion2(a,b,c); // hvor a,b og c er lokale variable

}

void funktion2(int *d, int *e, int *f) {

   behandling_af d,e og f;
}


Spørgsmålet går på, om funktion1() fortsætter udførslen af koden (evt.
afslutter), før funktion2() er færdig.
Jeg mener ikke selv, at dette er tilfældet ?

Det ville kunne give nogle problemer, eftersom de lokale variable a,b
og c (af funktion 1) vil blive destrueret.

- Er der nogle tilfælde, hvor dette vil kunne ske?


MVH
Henrik

 
 
J. Martin Petersen (12-06-2002)
Kommentar
Fra : J. Martin Petersen


Dato : 12-06-02 16:29

Henrik Koksby Hansen <henrik@koksby.dk> writes:

> Vi kom til at diskutere, i vores studiegruppe, om følgende kan
> følgende give problemer (MS Visual C++) :
>
> void funktion1() {
>    bla bla, en masse kode med lokale variable;
>    funktion2(a,b,c); // hvor a,b og c er lokale variable
> }
>
> void funktion2(int *d, int *e, int *f) {
>    behandling_af d,e og f;
> }
>
> Spørgsmålet går på, om funktion1() fortsætter udførslen af koden (evt.
> afslutter), før funktion2() er færdig.

Det gør den ikke. Den første funktion er jo ikke færdigudført før
funktion2 returnerer.

--
J. Martin Petersen "Atter springer gnuerne ud i vandet..."

Niels Teglsbo (13-06-2002)
Kommentar
Fra : Niels Teglsbo


Dato : 13-06-02 01:34

"J. Martin Petersen" <jmp@spam.alvorlig.dk> wrote:

> Det gør den ikke. Den første funktion er jo ikke færdigudført før
> funktion2 returnerer.

Men hvis det nu havde været ML, kunne oversætteren eller afvikleren så
ikke godt finde på det?

I stedet for at skrive en funktion som:

fun fak(0) = 1
| fak(n) = n*fak(n-1);

Mener jeg det er bedre at skrive den som:

fun fakit(0, p) = p
| fakit(n, p) = fakit(n-1, n*p);

(der skal kaldes med fakit(n, 1), men det kan jo pakkes pænt ind).

Fordelen ved fakit mener jeg er, at oversætteren/afvikleren netop kan
glemme de gamle funktionskald, hvorimod den med fak bliver nødt til at
huske dem for på den måde at få en lang række faktorer, der bliver ganget
sammen når det sidste funktionskald returnerer. Fakit kan returnere det
den sidste funktion returnerer, så snart den sidste funktion returnerer.

Selvom funktionelle og iterative sprog er ret forskellige kunne man da
sikkert i nogle tilfælde lave samme optimering i C.

--
Niels, The Offspring Mailinglist www.image.dk/~teglsbo

PS: Beklager det blev fakultetsfunktionen, nogen gange kunne man tro, at
Fakultetsfunktionen <=> Funktionelle sprog

Rasmus Kaae (13-06-2002)
Kommentar
Fra : Rasmus Kaae


Dato : 13-06-02 07:40

"Niels Teglsbo" <Niels@fabel.dk> wrote in message
news:bpnfgusc4e5d7iltq2s56kuj6dm7f87i4u@news.image.dk...
> "J. Martin Petersen" <jmp@spam.alvorlig.dk> wrote:
>
> > Det gør den ikke. Den første funktion er jo ikke færdigudført før
> > funktion2 returnerer.
>
> Men hvis det nu havde været ML, kunne oversætteren eller afvikleren så
> ikke godt finde på det?
>
> I stedet for at skrive en funktion som:
>
> fun fak(0) = 1
> | fak(n) = n*fak(n-1);
>
> Mener jeg det er bedre at skrive den som:
>
> fun fakit(0, p) = p
> | fakit(n, p) = fakit(n-1, n*p);
>
> (der skal kaldes med fakit(n, 1), men det kan jo pakkes pænt ind).
>
> Fordelen ved fakit mener jeg er, at oversætteren/afvikleren netop kan
> glemme de gamle funktionskald, hvorimod den med fak bliver nødt til at
> huske dem for på den måde at få en lang række faktorer, der bliver ganget
> sammen når det sidste funktionskald returnerer. Fakit kan returnere det
> den sidste funktion returnerer, så snart den sidste funktion returnerer.

Forkert, der vil blive opbygget en rekursions-stak i ovenstående tilfælde,
eneste forskel på et almindeligt C program og dit ML program er, at man kan
lave seje switch/case-sætninger i ML. Hvis du vil opnå det du skriver
ovenfor, så skal du bruge exceptions, da dette får ML-fortolkeren til at
stoppe den rekursive-frame og springe tilbage indtil exceptionen bliver
håndteret.

> Selvom funktionelle og iterative sprog er ret forskellige kunne man da
> sikkert i nogle tilfælde lave samme optimering i C.


Hvad mener du? Det er vel ikke super meget forskelligt fra:

int fakit(int n, p)
{
if (n==0) return p;
fakit(n-1, n*p);
}

Det er ikke specielt i fakultets- og andre simple rekursive funktioner, at
ML og andre funktionellesprog har deres styrker, her skal du nok nærmere
kigge efter lazy-strukturer m.v. der kun udregner det aktuelle svar når det
skal benyttes.



Jonas Meyer Rasmusse~ (13-06-2002)
Kommentar
Fra : Jonas Meyer Rasmusse~


Dato : 13-06-02 08:18

"Rasmus Kaae" <macaw@WHATEVERMAKESYOUHAPPYhotmail.com> wrote in message
news:ae9enf$9gg$1@news.net.uni-c.dk...
> "Niels Teglsbo" <Niels@fabel.dk> wrote in message
> news:bpnfgusc4e5d7iltq2s56kuj6dm7f87i4u@news.image.dk...
> > "J. Martin Petersen" <jmp@spam.alvorlig.dk> wrote:
> >
> > > Det gør den ikke. Den første funktion er jo ikke færdigudført før
> > > funktion2 returnerer.
> >
> > Men hvis det nu havde været ML, kunne oversætteren eller afvikleren så
> > ikke godt finde på det?
> >
> > I stedet for at skrive en funktion som:
> >
> > fun fak(0) = 1
> > | fak(n) = n*fak(n-1);
> >
> > Mener jeg det er bedre at skrive den som:
> >
> > fun fakit(0, p) = p
> > | fakit(n, p) = fakit(n-1, n*p);
> >
> > (der skal kaldes med fakit(n, 1), men det kan jo pakkes pænt ind).
> >
> > Fordelen ved fakit mener jeg er, at oversætteren/afvikleren netop kan
> > glemme de gamle funktionskald, hvorimod den med fak bliver nødt til at
> > huske dem for på den måde at få en lang række faktorer, der bliver
ganget
> > sammen når det sidste funktionskald returnerer. Fakit kan returnere det
> > den sidste funktion returnerer, så snart den sidste funktion returnerer.
>
> Forkert, der vil blive opbygget en rekursions-stak i ovenstående tilfælde,
> eneste forskel på et almindeligt C program og dit ML program er, at man
kan
> lave seje switch/case-sætninger i ML. Hvis du vil opnå det du skriver
> ovenfor, så skal du bruge exceptions, da dette får ML-fortolkeren til at
> stoppe den rekursive-frame og springe tilbage indtil exceptionen bliver
> håndteret.

Nej da...

Niels har da ret.
Funktionen han præsenterer er halerekursiv, og oversætteren kan derfor
skrive den om
til en iteration.

Den optimering er desuden så normal at mange C++ oversættere også laver den.

Jonas



J. Martin Petersen (13-06-2002)
Kommentar
Fra : J. Martin Petersen


Dato : 13-06-02 07:56

Niels@fabel.dk (Niels Teglsbo) writes:

> "J. Martin Petersen" <jmp@spam.alvorlig.dk> wrote:
>
> > Det gør den ikke. Den første funktion er jo ikke færdigudført før
> > funktion2 returnerer.
>
> Men hvis det nu havde været ML, kunne oversætteren eller afvikleren så
> ikke godt finde på det?

The ML-oversætter works in misterious ways.

> I stedet for at skrive en funktion som:
>
> fun fak(0) = 1
> | fak(n) = n*fak(n-1);
>
> Mener jeg det er bedre at skrive den som:
>
> fun fakit(0, p) = p
> | fakit(n, p) = fakit(n-1, n*p);
>
> (der skal kaldes med fakit(n, 1), men det kan jo pakkes pænt ind).
>
> Fordelen ved fakit mener jeg er, at oversætteren/afvikleren netop kan
> glemme de gamle funktionskald, hvorimod den med fak bliver nødt til at
> huske dem for på den måde at få en lang række faktorer, der bliver ganget
> sammen når det sidste funktionskald returnerer. Fakit kan returnere det
> den sidste funktion returnerer, så snart den sidste funktion
> returnerer.

Men det kan man vel ikke i C, i hvert fald ikke uden optimeringer. Man
kann vel ikke returnerer til den oprindelige kaldende funktion fra det
inderste funktionskald - man har jo kun returadressen til
funktionskaldet et niveau højere oppe.

Det er en optimering, der kan foretages af oversætteren, hvis det
altså kan gøres forsvarligt. Såfremt den kaldte funktion ikke tager
'automatic' variable som parametre, vil man vel godt kunne destruere
funktionen inden kaldet af underfuktionen, og lade returadressen for
den kaldte funktion være den adresse, som den kaldende funktion skulle
returnere til.

> Selvom funktionelle og iterative sprog er ret forskellige kunne man da
> sikkert i nogle tilfælde lave samme optimering i C.

I stedet kan man selvfølgelig implementere den iterative
fakultetsfunktion vha. en løkke (jeg ved godt, vi efterhånden er lidt
langt fra det oprindelige spørgsmål):

int fakit(int n) {
int p = 1;
while (n > 1)
p *= n--;
return p;
}

--
J. Martin Petersen "Atter springer gnuerne ud i vandet..."

J. Martin Petersen (13-06-2002)
Kommentar
Fra : J. Martin Petersen


Dato : 13-06-02 08:06

Niels@fabel.dk (Niels Teglsbo) writes:

> "J. Martin Petersen" <jmp@spam.alvorlig.dk> wrote:
>
> > Det gør den ikke. Den første funktion er jo ikke færdigudført før
> > funktion2 returnerer.
>
> Men hvis det nu havde været ML, kunne oversætteren eller afvikleren så
> ikke godt finde på det?
>
> I stedet for at skrive en funktion som:
>
> fun fak(0) = 1
> | fak(n) = n*fak(n-1);
>
> Mener jeg det er bedre at skrive den som:
>
> fun fakit(0, p) = p
> | fakit(n, p) = fakit(n-1, n*p);
>
> (der skal kaldes med fakit(n, 1), men det kan jo pakkes pænt ind).
>
> Fordelen ved fakit mener jeg er, at oversætteren/afvikleren netop kan
> glemme de gamle funktionskald, hvorimod den med fak bliver nødt til at
> huske dem for på den måde at få en lang række faktorer, der bliver ganget
> sammen når det sidste funktionskald returnerer. Fakit kan returnere det
> den sidste funktion returnerer, så snart den sidste funktion
> returnerer.

Det kan man vel ikke i C, i hvert fald ikke uden optimeringer. Man kan
ikke returnerer til den oprindelige kaldende funktion fra det inderste
funktionskald - man har jo kun returadressen til funktionskaldet et
niveau højere oppe.

Det er en optimering, der kan foretages af oversætteren, hvis det
altså kan gøres forsvarligt. Såfremt den kaldte funktion ikke tager
'automatic' variable som parametre, vil man vel godt kunne destruere
funktionen inden kaldet af underfuktionen, og lade returadressen for
den kaldte funktion være den adresse, som den kaldende funktion skulle
returnere til.

I nogle tilfælde vil det vel sagtens kunne klares med ren
hop-til-hop-elimineringer, men hvis parametre og især returværdier
placeres på stakken i stedet for registre, så er man nødt til at
flytte rundt på dem.

> Selvom funktionelle og iterative sprog er ret forskellige kunne man da
> sikkert i nogle tilfælde lave samme optimering i C.

I stedet kan man selvfølgelig implementere den iterative
fakultetsfunktion vha. en løkke (jeg ved godt, vi efterhånden er lidt
langt fra det oprindelige spørgsmål):

int fakit(int n) {
int p = 1;
while (n > 1)
p *= n--;
return p;
}

--
J. Martin Petersen "Atter springer gnuerne ud i vandet..."

Jonas Meyer Rasmusse~ (13-06-2002)
Kommentar
Fra : Jonas Meyer Rasmusse~


Dato : 13-06-02 09:34

"Niels Teglsbo" <Niels@fabel.dk> wrote in message
news:bpnfgusc4e5d7iltq2s56kuj6dm7f87i4u@news.image.dk...
> "J. Martin Petersen" <jmp@spam.alvorlig.dk> wrote:
>
> > Det gør den ikke. Den første funktion er jo ikke færdigudført før
> > funktion2 returnerer.
>
> Men hvis det nu havde været ML, kunne oversætteren eller afvikleren så
> ikke godt finde på det?

Jo, men det er jo specialtilfælde, som det du præsentere.. halerekursive
funktioner.
Men den gør det jo netop kun fordi den ved, at funktionen vil gøre præcis
det samme..
Derfor er det vel meget optimalt, som nybegynder, at tænke på det som om at
den kaldende funktion ikke returnerer før den kaldte er færdig.

Jonas



Bo Lorentsen (12-06-2002)
Kommentar
Fra : Bo Lorentsen


Dato : 12-06-02 16:39

In <ksnegu45fblmehofrgr12f3ssg1pek54ck@4ax.com>, Henrik Koksby Hansen
wrote:

> Vi kom til at diskutere, i vores studiegruppe, om følgende kan følgende
> give problemer (MS Visual C++) :
>
>
> void funktion1() {
>
>    bla bla, en masse kode med lokale variable;
>
>    funktion2(a,b,c); // hvor a,b og c er lokale variable
>
> }
>
> void funktion2(int *d, int *e, int *f) {
>
>    behandling_af d,e og f;
> }
>
>
> Spørgsmålet går på, om funktion1() fortsætter udførslen af koden (evt.
> afslutter), før funktion2() er færdig. Jeg mener ikke selv, at dette er
> tilfældet ?
Det ville være interessant !, da det er en parallel udvikling af koden, og
eftersom en funktion per. defination retunerer et eller andet, ville det
heller ikke virke fornuftigt. (Ok, en tråd starter også med en funktion,
men det er princippet i det

Så svaret er at funktion1 "stopper" indtil funktion2 er færdig, og venter
derved på en retur værdi, også hvis den er "void".

> Det ville kunne give nogle problemer, eftersom de lokale variable a,b og
> c (af funktion 1) vil blive destrueret.
Helt rigtig, og bla. derfor er det ikke sådan

> - Er der nogle tilfælde, hvor dette vil kunne ske?
Parallel udviking, via tråde, dvs. du vil starte funktion2 i en tråd, og
så er det helt rigtig at så er det MEGET dumt at overfører pointere til
lokale værdier til tråden da du ikke ved hvornår de destruerers, ud over
en mængte andre problemer med fældes resourcer. Man vil heller ikke vente
på en retur værdi fra en tråd på samme måde da ideen med en tråd så ryger
i vasken

/BL

Henrik Koksby Hansen (12-06-2002)
Kommentar
Fra : Henrik Koksby Hansen


Dato : 12-06-02 17:15

>Så svaret er at funktion1 "stopper" indtil funktion2 er færdig, og venter
>derved på en retur værdi, også hvis den er "void".
[...]

Takker - jeg skulle bare lige have det bekræftet. Alt andet ville jo
også være ulogisk. :)


/Henrik

Byrial Jensen (12-06-2002)
Kommentar
Fra : Byrial Jensen


Dato : 12-06-02 17:27

Henrik Koksby Hansen <henrik@koksby.dk> skrev:
>
> - Er der nogle tilfælde, hvor dette vil kunne ske?

Ja, f.eks. ved

void funktion1 (void)
{
int *p = funktion2 ();

/* Gør noget med p */
}

int *funktion2 (void)
{
int autovar = 47;
return &autovar; /* Fejl, returværdien må ikke bruges. */
}

I det øjeblik funktion2 returnerer, forsvinder autovar, og
pointeren som den returnerer, peger ikke længere på nogen gyldig
værdi. Det betyder at funktion1 under ingen omstændigheder ikke må
bruge p.

Problemet kan f.eks. løses med:

/* En bedre udgave af funktion2 */
int *funktion2 (void)
{
int *p = malloc (sizeof *p);
if (p)
{
*p = 47;
}
return p;
}

Rasmus Kaae (13-06-2002)
Kommentar
Fra : Rasmus Kaae


Dato : 13-06-02 07:43

"Byrial Jensen" <bjensen@nospam.dk> wrote in message
news:slrnagetnt.2rl.bjensen@ask.ask...
> Henrik Koksby Hansen <henrik@koksby.dk> skrev:
> >
> > - Er der nogle tilfælde, hvor dette vil kunne ske?
>
> Ja, f.eks. ved
>
> void funktion1 (void)
> {
> int *p = funktion2 ();
>
> /* Gør noget med p */
> }
>
> int *funktion2 (void)
> {
> int autovar = 47;
> return &autovar; /* Fejl, returværdien må ikke bruges. */
> }

Det er jo ikke compilerensskyld, det er fordi programmørern ikke kender til
C-sproget (i fald man skriver ovenstående kode).
Et andet eksempel kunne være:


void funktion_a()
{
throw 'a';
}


void funktion_b()
{
funktion_a();
throw 'b';
}


int main(int argc, char **argv)
{
try
{
funktion_b();
}
catch (char funktions_bogstav)
{
}
return 0;
}

---
Rasmus Christian Kaae




Igor V. Rafienko (13-06-2002)
Kommentar
Fra : Igor V. Rafienko


Dato : 13-06-02 12:18

[ Rasmus Kaae ]

[ snip ]

> Et andet eksempel kunne være:

[ snip ]


Jeg må innrømme at jeg ikke forstår hva eksempelet ditt skulle
illustrere. Kunne du utdype det?





ivr
--
C++: "an octopus made by nailing extra legs onto a dog"
            -- Steve Taylor, 1998

Rasmus Kaae (13-06-2002)
Kommentar
Fra : Rasmus Kaae


Dato : 13-06-02 13:30

> Jeg må innrømme at jeg ikke forstår hva eksempelet ditt skulle
> illustrere. Kunne du utdype det?

Ja, det Byrial Jensen gjorde i sit eksempel var, at generere en runtime-fejl
der får det kørende program til at crashe, dette gjorde han for at
illustrere en situation hvor en kaldende funktion ikke afsluttes på grund af
en fejl.
Mit eksempel var istedet baseret på C++ hvor man har mulighed for at springe
ud af en funktion (til første try/catch-statement der behandler
tilfældet) -- hvilke gøre, at kalende funktion ikke bliver udført til
vej-ende.






Søg
Reklame
Statistik
Spørgsmål : 177558
Tips : 31968
Nyheder : 719565
Indlæg : 6408925
Brugere : 218888

Månedens bedste
Årets bedste
Sidste års bedste