[C] Waarom werkt dit WEL ?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ok, voor de "verandering" eens een bizarre vraag.

Als achtergrond: mijn collega is programmatuur lessen aan het volgen en moet dus opdrachtjes maken en blabla, 1 van die opdracht compileert netjes en doet zelfs wat er van verwacht wordt. MAAR volgens mij zou het het helemaal niet mogen compileren (en volgens zijn prof trouwens ook niet).

De vraag is dus: iemand die een idee heeft wat er hier gebeurt want ik word er knetter van :)

We hebben een struct voor een student, er staat meer in maar ik haal enkel wat er nodig is uit.
code:
1
2
3
4
5
6
struct student
{
   char nom [21];
   char prenom [21];
}
typedef struct student ETUDIANT


We roepen via qsort een compare functie op voor een lijst van studentjes
code:
1
qsort(tab,nrbetudiants,sizeof(ETUDIANT),comparenom);


En we hebben tenslotte een compare functie, die als doel heeft de studenten te ordenenen op alfabetische volgorde voor de familienaam en indien er zijn met dezelfde familienaam op tegen-alfabetische(?) volgorde op de voornaam.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
int comparenom (const void* a, const void* b)
{
   ETUDIANT *ia = (ETUDIANT*)a;
   ETUDIANT *ib = (ETUDIANT*)b;

   if (strcmp (ia->nom, ib->nom) == 0)
   {
       if (strcmp(ia->prenom,ib->prenom) != 0)
       {
           return strcmp(ib->prenom,ia->prenom);
       }
   }
}


Mijn probleem met die code is:
- niet elk pad heeft een return value
- als we de middelste if blok weghalen wordt er nog steeds correct geranschikt op voornaam.


extra info: hij werkt met het programme "Code Blocks" als IDE.

Acties:
  • 0 Henk 'm!

  • PaulZ
  • Registratie: Augustus 2004
  • Laatst online: 21-05-2024
(algemeen zonder kennis van [C]): Als het syntactisch correct is, zal het altijd compileren. Dat je denkwijze niet correct is gaat die compiler je niet vertellen...

Vlinders moet je volgen, niet vangen...


Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

http://stackoverflow.com/...-without-return-statement

Het is undefined behaviour, dus alles zou kunnen gebeuren.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Dit is een piste waar ik ook aan dacht: het if-statement houdt zijn resultaat ergens bij en aangezien dit het laatste is wat uitgevoerd werd wordt dit resultaat (om de een of andere reden) als return value gebruikt ?

Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Verwijderd schreef op vrijdag 27 april 2012 @ 12:30:
Dit is een piste waar ik ook aan dacht: het if-statement houdt zijn resultaat ergens bij en aangezien dit het laatste is wat uitgevoerd werd wordt dit resultaat (om de een of andere reden) als return value gebruikt ?
Waarschijnlijk. Maar in theorie zou er van alles kunnen/mogen gebeuren, inclusief een segfault of program termination. Het is dus niet aan te raden.

Waarom het wel compileert is waarschijnlijk omdat een compiler niet alle dynamische paden kan checken (niet omdat het moeilijk is, maar omdat het gewoon niet kan). Als ik opschrijf "if (i > 0) return 1; if (i <= 0) return 0;" dan return ik altijd een value omdat ik weet dat een van de ifs altijd uitgevoerd wordt. Niettemin raadt ik aan om zelfs dan altijd een dummy return value te gebruiken.

Acties:
  • 0 Henk 'm!

  • SaphuA
  • Registratie: September 2005
  • Laatst online: 10-09 22:00
.

[ Voor 124% gewijzigd door SaphuA op 31-01-2022 15:27 ]


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Nu online
Het is niet zozeer het resultaat van de expressie die geretourneert wordt, maar het resultaat van de laatste function call. Wat er praktisch gebeurt, is dat een functie die een int returnt op bijna elke architectuur de return value in een register laat staan. Dat doet strcmp() dus en comparenom() ook. Als je een strcmp() uitvoert en vervolgens niets meer doet staat het resultaat van die strcmp() dus nog in het register waarin comparenom() z'n resultaat zou moeten teruggeven.

Maar zoals gezegd mag je er absoluut niet vanuit gaan dat het zo werkt! Sowieso zal de compiler hier waarschijnlijk een warning bij produceren. Die moet je natuurlijk niet negeren.

Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

In C of C++ hoeft je compiler dit niet af te vangen, dus dit is gewoon een programmeer fout :)

Dat dit werkt is waarschijnlijk omdat vrijwel alle C calling conventions altijd hetzelfde register gebruiken voor returns, en omdat in het no-return pad de laatste statement de aanroep op strcmp was is dat register wel geinitialiseerd met het verwachtte resultaat, maar dat neemt niet weg dat dit gewoon 100% fout is.

De C# compiler weigert compilatie als ie niet kan garanderen dat je altijd returned (of een exception gooit), dat is zeg maar de omgekeerde wereld. Daar kan het voorkomen dat een correcte functie niet compiled, omdat de compiler niet kan verifieren dat je altijd returned.

In principe is het in zowel C, C++ en C# verstandig om elke functie te laten eindigen met een return of throw statement :)

-niks-


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ok, dus samengevat:

1) Hij moet nog veel leren over correct programmeren ;)
2) De 'flow' is waarschijnlijk als volgt
- strcmp schrijft iets weg in het return-register
- dit wordt opgevangen door onze compare functie
- onze compare functie schrijft NIETS weg in het return-register
- de qsort functie verwacht een resultaat in het return-register, maar daar staat nog steeds het resultaat in van de compare functie !

Dat dit het juiste resultaat geeft is dan logisch omdat het resultaat van de compare functie toch gelijk is aan het resultaat van de strcmp functie.

Dat alle (meeste) functies hetzelfde register gebruiken voor de return value was nieuw voor me, maar als je erover nadenkt eigenlijk best wel logisch.

Acties:
  • 0 Henk 'm!

  • Vaan Banaan
  • Registratie: Februari 2001
  • Niet online

Vaan Banaan

Heeft ook Apache ontdekt

Er zal zeker een waarschuwing komen, maar je kan het gedrag van de compiler zelf instellen..
Afbeeldingslocatie: http://www.codeblocks.org/docs/compiler_debugger.png
Als je "-Wall" aanklikt, krijg je in ieder geval de waarschuwing.
Als je dan ook "-Werror" aanklikt, zal hij de waarschuwing als error zien en niet compileren. (Het effect wat SaphuA beschrijft bij de Visual Studio.)
Eventueel kun je ook nog -Wfatal-errors aanvinken, dan stopt de compiler direct na de eerste waarschuwing / fout.

500 "The server made a boo boo"


Acties:
  • 0 Henk 'm!

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Compilen met -Wall is sowieso altijd aan te raden, en -Werror is ook good practice. Ik heb altijd geleerd warning-vrije code te schrijven. (enige vervelende is soms de ongebruikte variabelen die je dan met iets als # define UNUSED(x) (void)x; weg moet werken.

[ Voor 30% gewijzigd door Zoijar op 27-04-2012 16:25 ]

Pagina: 1