Toon posts:

[c/c++] van Borland naar MS

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik werk persoonlijk al een tijdje met Borland CBuilder 3 en ik ben er redelijk tevreden over. Maar ik ging vanavond een kijken of ik MS-Visual C++ wat vond.
Dus ik pakte een projectje waar ik mee bezig ben die zich zonder problemen (geen errors, geen warnings) laat compileren in Borland. In de MS omgeving kreeg ik echter meer dan 100 errors voor mijn kiezen. (Het zijn bijna allemaal dezelfde)
Ik vroeg me af of jullie me konder vertellen waarom er op deze declaratie:
code:
1
  err mem_alloc (void *&var, dword size);

zo door de compiler wordt gereageerd:
code:
1
e:\dev\cpp\shell_msvc\src\alloc\alloc.h(18) : error C2143: syntax error : missing ')' before '&'

Zoals ik al zei, in de Borland omgeving is er niets aan de hand. De enige files (op mijn eigen rotzooi na) die ik include zijn:
code:
1
2
#include <stdlib.h>
#include <stdio.h>

Het lijkt mij dat het daar niet aan kan liggen, moeten beide bruikbaar zijn in beide omgevingen.

  • stylee
  • Registratie: December 2000
  • Laatst online: 04-09-2021

stylee

blah zeg ik je

code:
1
err mem_alloc   (void *&var, dword size);

Uhm best vage code dit, je hebt hier dus een void-pointer naar een reference genaamd var :?

Achja waarschijnlijk gewoon geschreven door iemand die de Tao beheerst :P

Verwijderd

Topicstarter
net zoiets als **var
zodat je de pointer zelf kan veranderen. (iets wat een alloc-functie moet kunnen)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

Op maandag 03 juni 2002 23:58 schreef stylee het volgende:

Achja waarschijnlijk gewoon geschreven door iemand die de Tao beheerst :P
niet door mij iig :+

komt denk ik omdat ie het type err niet kent... en het is toch wel c++ he? (dus .cpp extensie)

.edit: hmm bij mij geeft ie deze error:
d:\...\profiler.cpp(19) : error C2146: syntax error : missing ';' before identifier 'mem_alloc'
d:\...\profiler.cpp(19) : error C2501: 'err' : missing storage-class or type specifiers
maar dat is dus idd omdat ie het type err niet kent :)

.edit2: als ik err en dword definieer (als int ofzo) dan compilet het gewoon...

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
aahhh... als vanzelf sprekend heb ik alle typen die ie gebruikt gewoon gedefineerd, dat is het probleem niet.
Maar wat jij zegt, dat ik 'm wel .cpp moet noemen ipv .c zodat ie ook daadwerkelijk C++ gebruikt, zou heel erg goed het probleem kunnen zijn. tnx voor het testen.

Verwijderd

Topicstarter
(het .c ipv .cpp was het probleem)

Nu kom ik toch nog een verschil tegen tussen Borland en MS.

Uitgaande van deze functie:
code:
1
2
3
4
5
err mem_alloc(void *&var, dword size)
{
  var = ZO_MAAR_IETS;
  return 1;
}

Dit gaat in borland goed:
code:
1
2
3
int *bla;
if (!mem_alloc((void*)bla, sizeof(int)))
  mislukt();

In MS visual C++ moet het echter zo:
code:
1
2
3
int *bla;
if (!mem_alloc((void*&)bla, sizeof(int)))
  mislukt();

dus (void*&) ipv (void*)...
iemand die me kan uitleggen hoe dat nou precies zit, en wat de 'officiele' manier is...

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

misschien een doorn in het oog, maar de MS manier is in dit geval de goede ;)

een (void*) is namelijk wat anders dan een (void*&)
je kunt een (void*&) naar (void*) casten, maar niet andersom

Je moet het zo zien: een (void*) is gewoon een waarde, en een (void*&) is een referentie naar een variabele van het type (void*)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Ik snap nog steeds niet waarom je 'void *&' gebruikt. Gebruikelijk is het om als je een pointer aan een functie meegeeft

err mem_alloc(void *var, dword size)

te gebruiken, en als je C++ gebruikt heeft een reference de voorkeur, hoewel dat alleen werkt als je vooraf 't type al weet (er zijn geen void references).
code:
1
2
3
4
5
6
7
8
err mem_alloc(void *var, dword size)
{
  var = ZO_MAAR_IETS;
  return 1;
}

int *bla;
if (!mem_alloc(bla, sizeof(int))) mislukt();

of eventueel als ie daar over gaat zeuren
code:
1
if (!mem_alloc((void *)bla, sizeof(int))) mislukt();

Je moet echter (volgens mij) die rare 'void *&' veranderen in een gewone void *... dat is de gangbare manier om pointers door te geven aan een functie.

Verwijderd

Topicstarter
reactie op .oisyn
ik heb die referenties nooit echt gesnapt, maar ik vind het altijd wel makkelijk dat als je een reference parameters hebt, je de waarde kan veranderen zonder met ** te gaan werken...

Trouwens redelijk vaag want als je een functie hebt:
code:
1
2
3
4
void tel_op (int a, int b, int &c)
{
  c = a + b;
}

dan is versie 1 toch correct, of moet je dan ook versie 2 gebruiken:
code:
1
2
3
4
5
6
7
// versie 1
int r;
tel_op(10, 20, r);

//versie 2
int r;
tel_op(10, 20, (int&)r);

(misschien moet ik het toch maar bij ansi-C houden :+)

----------------------------------------------------------
reactie op Qlone
met een gewone void * kan je er toch niet voor zorgen dan de waarde veranderd. Dan maakt ie een copy van de pointer als je die veranderd is de originele pointer (die je meegaf) nog het zelfde...

Verwijderd

Beide versies zijn correct volgens mij, alleen bij de tweede variant vertel je de compiler iets wat hij al weet, namelijk dat je als 3e parameter graag een reference naar die int wil.

Je hebt in C++ 2 manieren om parameters door te geven aan een functie: Pass by value, en pass by reference. Pass by value kopieert de variabele op de stack en gaat er dan mee aan het werk. Pass by reference gebruikt gewoon de variabele 'as is' zonder er een kopie van te maken.
code:
1
2
3
4
5
6
void drie(int c)
{
  c = 3;
}

int c = 2; drie(c); // Wat is C nu?

Bovenstaande code maakt dus eerst een kopie van 'c' en geeft deze door aan de functie. Als de functie is afgelopen heeft 'c' nog steeds de waarde 2.
code:
1
2
3
4
5
6
void drie(int &c)
{
  c = 3;
}

int c = 2; drie(c); // Wat is C nu?

Bij deze code wordt er geen kopie gemaakt van C, en zal C na de functie dus de nieuwe waarde (3) hebben gekregen. In ANSI C doe je hetzelfde zonder reference op de volgende manier:
code:
1
2
3
4
5
6
void drie(int *c)
{
  *c = 3;
}

int c; c = 2; drie(&c); // Wat is C nu?

Call by reference is dus handig in 2 gevallen:
- Je wilt de waarde van een parameter veranderen in de functie.
- Je wilt geen kopie maken van een parameter (bijvoorbeeld omdat het ook een ingewikkelde class kan zijn die veel geheugen gebruikt en waarvoor kopieren niet handig is).

Als je nou de 2e situatie hebt heeft de compiler nog een ingebouwde beveiliging om te voorkomen dat je alsnog de waarde van die parameter aantast: de const reference.
code:
1
2
3
4
5
6
void drie(const int &c)
{
  c = 3;
}

int c = 2; drie(); // Wat is C nu?

Deze code kan je niet compilen; de compiler genereert een error, omdat C 'const' is en de waarde dus niet mag worden veranderd.

Verwijderd

met een gewone void * kan je er toch niet voor zorgen dan de waarde veranderd. Dan maakt ie een copy van de pointer als je die veranderd is de originele pointer (die je meegaf) nog het zelfde...
Ehm... ja, daar heb je helemaal gelijk in. Had ik even overheen gelezen. In dat geval is een reference naar een pointer inderdaad een optie. Zelf vind ik het leesbarder om dan gewoon een pointer naar een pointer te gebruiken...
code:
1
2
3
4
5
6
7
err mem_alloc(void **var, dword size)
{
  *var = ZO_MAAR_IETS;
  return 1;
}
int *bla;
if (!mem_alloc(&bla, sizeof(int))) mislukt();

Ofzo...

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

Qlone: Wat unteraarsch wil bereiken is dat de variabele veranderd kan worden door de aangeroepen functie.

Vergelijk dit:
code:
1
2
3
4
void functie (int & i)
{
    i = 5;
}

met dit:
code:
1
2
3
4
void functie (void *& v)
{
    v = malloc (5);
}

het is dus ook helemaal niet het doel om een pointer door te geven, maar om er een terug te krijgen. En de returnwaarde is al bezet door een errorcode (en voordat iemand begint te roepen: "ja maar dat kan toch ook anders"; ja natuurlijk kan ook anders, maar er is nou eenmaal voor deze manier gekozen)

unteraarsch: beide versies zijn correct :)
r is namelijk een (int &), dus die hoef je niet alsnog te casten :)
Heb je echter bijvoorbeeld een unsigned int die je wilt meegeven, dan moet je m dus wel casten naar (int &)


.edit: te laat :D
dan maar een 2e reactie op Qlone: :)
Op dinsdag 04 juni 2002 01:41 schreef Qlone het volgende:

Ehm... ja, daar heb je helemaal gelijk in. Had ik even overheen gelezen. In dat geval is een reference naar een pointer inderdaad een optie. Zelf vind ik het leesbarder om dan gewoon een pointer naar een pointer te gebruiken...
code:
1
2
3
4
5
6
7
err mem_alloc(void **var, dword size)
{
  *var = ZO_MAAR_IETS;
  return 1;
}
int *bla;
if (!mem_alloc(&bla, sizeof(int))) mislukt();

Ofzo...
dan zit je alleen met het probleem dat var naar NULL kan wijzen... bij een referentie heb je dat niet (ja kan nog wel als je het forceert, maar dus niet als je gewoon een variabele meegeeft)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
ik geloof dat we er uit zijn..
wat .oisyn zegt was dus altijd mijn probleem, een pointer naar een pointer kan NULL zijn dus die moet je controleren en dat levert extra code op die je bij een reference niet hebt.

maar (bedenk ik mij opeens :'() als je deze functie:
code:
1
void functie (int & i) { i = 5; }

zo aan kan roepen
code:
1
int i; functie(i);

waarom kan je deze functie
code:
1
void functie (void *&i) { i = malloc(5); }

dan (in MS-Visual C++ weliswaar) niet zo aan roepen
code:
1
byte *i; functie((void*)i);

blijf ik merkwaardig vinden... :?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

omdat de functie een (void*&) verwacht, en geen (void*) :)

bij (void*) kun je gewoon een waarde opgeven, terwijl het bij (void*&) een l-value (variabele) moet zijn

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
maar waarom is dat met die int niet zo ??
Een void* is toch net zo goed een type als een int

Verwijderd

Een 'void' is een type. Een 'void *' is een pointer naar een 'objectje' van het type void. Op dezelfde manier is een int een type en een 'int *' een pointer naar een int.

Jij probeert in je code de waarde van de pointer te veranderen door een reference naar een pointer naar een void mee te geven. Je kan hem dan niet casten naar een pointer naar een void omdat dat echt iets heel anders is dan een reference naar een pointer naar een void.

Verwijderd

Topicstarter
dat snap ik, maar ik snap het fundamentele verschil nog steeds niet van wat ik twee post geleden uitlegde.

een int een void * een int * een char * een char...
het zijn allemaal datatypen waarnaar je een referentie naar kan leggen... toch ??

waarom dan toch het verschil tussen die int en void *, omdat het een pointer is, lijkt mij niet.

Verwijderd

Voorbeeld 1
code:
1
2
3
4
5
6
7
8
9
10
11
void ptr(void *&c) { }

int main(int argc, char* argv[])
{
    void *d;

    ptr(d);
    ptr((void *)d);

    return 0;
}

Voorbeeld 2
code:
1
2
3
4
5
6
7
8
9
10
11
void ptr(void *&c) { }

int main(int argc, char* argv[])
{
    int *d;
    void *e = d;

    ptr((void *)e);

    return 0;
}

Voorbeeld 3
code:
1
2
3
4
5
6
7
8
9
void ptr(void *&c) { }

int main(int argc, char* argv[])
{
    int *d;
    ptr((void *)d);

    return 0;
}

Ik snap wel wat je probleem is denk ik. Waarom compileren voorbeelden 1 en 2 wel zonder fouten, en voorbeeld 3, waar je in weze hetzelfde doet niet?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

kijk hier even naar
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void func_int (int i);
void func_int_ref (int & i);

func_int (5); // ok
func_int_ref (5); // fout, er is geen reference naar een var

int i = 4;
func_int (i); // ok, pass by value
func_int_ref (i); // ok, pass by reference

unsigned u = 6;
func_int ((int)u); // ok, converteer naar int
func_int_ref ((int)u); // FOUT! hij verwacht een int &
func_int_ref ((int &)u); // prima zo

en dat zelfde rijtje kun je zo ook precies invullen voor void *

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 08:58
Op dinsdag 04 juni 2002 01:21 schreef .oisyn het volgende:
misschien een doorn in het oog, maar de MS manier is in dit geval de goede ;)

een (void*) is namelijk wat anders dan een (void*&)
je kunt een (void*&) naar (void*) casten, maar niet andersom

Je moet het zo zien: een (void*) is gewoon een waarde, en een (void*&) is een referentie naar een variabele van het type (void*)
Je hebt bijna gelijk. Vergeet niet dat het probleem is dat het origineel een int* is. Die kun je wel naar een void* converteren, maar dan krijg je een temporary. Die temporary veranderen geeft natuurlijk niet het gewenste resultaat.
Als je een cast naar een reference-type doet (T&) dan krijg je een type-pun; de assignment naar de void*& schrijft dan blindelings naar de int* alsof het de bytes van een void* zijn. Nu gaat dat goed op Borland en MSVC, ( void* en int*hebben dezelfde structuur) maar dat hoeft dus niet ivm aligment (relevant voor RISC chips cq alles behalve x86).

Kortom: de code is gewoon fout.

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


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03-09 13:30

.oisyn

Moderator Devschuur®

Demotivational Speaker

hmmja daar zat ik idd al over te twijfelen

dus in principe zou je dan dit moeten doen?
code:
1
2
3
4
int * i = bla;
void * temp = i;
functie_die_een_void_ptr_ref_verwacht (temp);
i = (int *)temp;

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
ik heb inmiddels honderden regels (void*) naar (void*&) omgezet ... en het werkt allemaal perfect..
Pagina: 1