FOK!forum / Digital Corner / [C(++)] voor dummies - Deel 3
netolkvrijdag 28 januari 2011 @ 15:11
C+for+Dummies.jpgC%2B%2B+for+Dummies+book+cover.JPG
Nu mét gratis web-support!

Als je vragen hebt over C of C++, dan zit je hier goed met een (hopelijk later grote) kliek guru's.
Beperk je vragen niet tot "hij doet het niet" of "hij geeft een fout" - onze glazen bol is kapot en we willen graag van je weten wát er niet lukt en wélke foutmelding je precies krijgt. ;)

En onthoud: lieve modjes maken dit topic centraal! O+

Vorige delen:
[C(++)] voor dummies - Deel 1
[C(++)] voor dummies - Deel 2

:? FAQ :?

:? Ik wil beginnen met C/C++, wat voor IDE is het beste voor mij?
Dat ligt eraan. Als je alléén voor MS Windows wilt gaan developen, is Visual Studio de beste optie. Deze kun je bovendien als je student bent via Microsoft DreamSpark of MSDN Academic Alliance gratis downloaden. :)
Wil je echter cross-platform (dat wil zeggen: voor b.v. Windows én Linux, of Linux én Mac) gaan developen, dan zijn Dev-C++ en Code::Blocks de beste optie voor C++. Eclipse (ook voor C) en NetBeans zijn ook goede keuzes, alleen zijn deze meer op Java gericht. Een ander IDE, van Nokia's hand, is Qt Creator. Dit IDE maakt gebruik van het Qt-framework, een set van functies, types, variabelen etc. om programmeren makkelijker te maken. Dit framework is cross-platform. :)

:? Hoe gebruik ik x/wat houdt y in?
Stop! Voor vragen hoe je bepaalde ingebouwde functies, types of classes gebruikt kun je de C referentie of de C++ referentie gebruiken. Hier staat alles in wat je nodig hebt. :)

:? Wat is het verschil tussen C en C++?
C++ is, eenvoudig gezegd, een nieuwere versie van C (vandaar ook de naam, C++ wil zeggen: verhoog de waarde van C met 1). Het biedt onder andere betere klasse-ondersteuning en verschillende nieuwe types, zoals vectors en maps, om er maar een paar te noemen.
Als je wilt beginnen met leren, is C++ beter, want C wordt eigenlijk niet vaak meer gebruikt.

:? Wat is het Windows SDK?
Het Windows SDK is een set van functies, gemaakt door Microsoft, om het programmeren voor Windows te vereenvoudigen.
Als je ervoor kiest het Windows SDK te gebruiken, houd er dan rekening mee dat je applicatie Windows-only wordt!
Je kunt de laatste versie hier vinden ter download. :)

Handige links:

Referenties en tutorials:
Leer C en/of C++ (engels)
Leer programmeren met het Windows SDK (engels)
Info over het Windows SDK (engels)

Deze OP vind je hier.
Trollface.vrijdag 28 januari 2011 @ 15:32
1
2
3
4
5
6
#include <cstdio>

int main() {
    printf("%c%c%c\n", 'T', 'V', 'P');
    return 0;
}
thabitvrijdag 28 januari 2011 @ 16:06
Tvp* tvp = new Tvp();
netolkvrijdag 28 januari 2011 @ 18:10
zou iemand kunnen uitleggen waarom het volgende niet werkt?

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
#include <iostream>
#include <vector>
class Master{
    protected:
        unsigned short i;
    public:
        Master():i(5){}
        virtual unsigned short get(){return 9;}
};
class Sub:public Master{
    public:
        Sub(){i=8;}
        unsigned short get(){return i;}
};

int main(){
    Master *M_ptr;
    
    Sub mySub;
    
    M_ptr = &mySub;
    
    Sub *S_ptr = dynamic_cast<Sub*>(M_ptr);
    if(S_ptr) // hier werkt het
        std::cout << "Works\n";
    else
        std::cerr << "FAIL\n";
    
    std::vector<Master> myVec;
    myVec.push_back(Sub());
    Master *vec_ptr = &myVec[0];
    Sub *S_ptr2 = dynamic_cast<Sub*>(vec_ptr);
    if(S_ptr2) // hier faalt het
        std::cout << "Works\n";
    else
        std::cout << "FAIL\n";
    
    return 0;
}

waarom werkt dynamic_cast niet als er een pointer naar een vecor wijst?
thabitvrijdag 28 januari 2011 @ 20:17
Een van de problemen is dat een object van base class niet per se dezelfde geheugenruimte inneemt als een object van een derived class. Een dynamic cast werkt in principe alleen met pointers en references. Je definieert een vector van Masters, daar kun je niet zo een twee drie een Sub in stoppen want daar wordt dan gebruik gemaakt van slicing ipv polymorfisme: de Sub is niet echt een Sub maar wordt geconverteerd naar een Master. Met een vector<Master*> of een vector<Master&> gok ik dat je meer succes hebt.

Moraal van het verhaal: value-typed class objecten zijn gewoon zwaar kut. Een van de vele designfoutenblunders in C++ om zoiets toe te laten.
thabitzaterdag 29 januari 2011 @ 00:15
Nog een probleem met je code is dat je de base class niet polymorf hebt gemaakt. Er moet tenminste 1 virtual methode in zitten; het is sowieso raadzaam om de destructor virtual te maken. Dat classes niet automatisch polymorf zijn is overigens ook een designflater.
netolkzaterdag 29 januari 2011 @ 12:18
quote:
1s.gif Op zaterdag 29 januari 2011 00:15 schreef thabit het volgende:
Nog een probleem met je code is dat je de base class niet polymorf hebt gemaakt. Er moet tenminste 1 virtual methode in zitten; het is sowieso raadzaam om de destructor virtual te maken. Dat classes niet automatisch polymorf zijn is overigens ook een designflater.
um, die destructor klopt idd maar er is toch een virtual methode?

virtual unsigned short get(){return 9;}
thabitzaterdag 29 januari 2011 @ 12:26
quote:
1s.gif Op zaterdag 29 januari 2011 12:18 schreef netolk het volgende:

[..]

um, die destructor klopt idd maar er is toch een virtual methode?

virtual unsigned short get(){return 9;}
O ja, overheen gelezen. Maar dan nog moet je geen polymorfisme toepassen op value-typed objecten.
netolkzaterdag 29 januari 2011 @ 17:41
hmm... ik krijg behoorlijk wat compilatie fouten bij het declareren van std::vector<Master&> iets van
1mingw/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/ext/new_allocator.h:52: error: forming pointer to reference type `Master&'

en nog veel meer...

maar std::vector<Master*> werkt wel :)
thabitzaterdag 29 januari 2011 @ 17:52
Pas wel een beetje op dat je geen pointers naar ongedefinieerde stukken geheugen laat wijzen.
netolkzaterdag 29 januari 2011 @ 18:01
quote:
1s.gif Op zaterdag 29 januari 2011 17:52 schreef thabit het volgende:
Pas wel een beetje op dat je geen pointers naar ongedefinieerde stukken geheugen laat wijzen.
Ja, ik heb het zo bedacht:
[code]
Master *M_ptr = new Sub();
myVec.push_back(M_ptr);

en dan de destructor v.e class waar Master in zit:
~Class{
for(int i = 0; i < myVec.size(); i++){
delete myVec[i];
}
myVec.clear();
}

nog een vraagje, roept een vector bij destruction ook de destructor van het type aan? dus zegmaar std::vector<int> roept die dan ook ~int() aan?
thabitzaterdag 29 januari 2011 @ 18:25
De destructor van de vector roept de destructors van de objecten aan die ruimte innemen in het stuk heap dat de vector zelf gealloceerd heeft. Dus niet als het pointers zijn. Dingen die je zelf met new aanmaakt moet je ook zelf deleten.

Een int heeft trouwens niet echt een destructor je kunt (denk ik) wel ~int() aanroepen, maar dat is puur om de syntax consistent de houden, de instructie doet helemaal niets.
GS42zaterdag 29 januari 2011 @ 19:14
quote:
1s.gif Op zaterdag 29 januari 2011 18:01 schreef netolk het volgende:

nog een vraagje, roept een vector bij destruction ook de destructor van het type aan? dus zegmaar std::vector<int> roept die dan ook ~int() aan?
Ja, als er een destructor bestaat zal deze aangeroepen worden. Dit geldt echter alleen als je classes (of base-types) in de vector opslaat. Als je std::vector<X*> gebruikt, zal de X::~X() destructor niet automatisch aangeroepen worden. Daarom wordt het ook als niet netjes gezien om pointers in containers op te slaan.

Edit: Oh, ik had het bovenstaande antwoord gemist.
thabitzaterdag 29 januari 2011 @ 19:19
Niks mis met pointers in containers, mits je duidelijk aan elke new een delete koppelt.
GS42zaterdag 29 januari 2011 @ 19:25
quote:
1s.gif Op zaterdag 29 januari 2011 19:19 schreef thabit het volgende:
Niks mis met pointers in containers, mits je duidelijk aan elke new een delete koppelt.
Gaat tegen het idee van de stl containers in, namelijk dat de container de eigenaar van de data is. Netter zou zijn de pointer in een class te wikkelen. Dit is echter erg afhankelijk van smaak en stijl, en iedereen weet dat daarover prima te twisten valt. :)
thabitzaterdag 29 januari 2011 @ 19:35
Als je dat soort design patterns al moet gaan toepassen, dan kun je beter op een programmeertaal overstappen waar ze helemaal niet nodig zijn. :).
DemonRagezaterdag 29 januari 2011 @ 19:54
1
2
long long troll[2]={7308604865845225588LL, 0};
printf("%s\n", (char *)troll);

*O*
ralfiezaterdag 29 januari 2011 @ 20:38
quote:
1s.gif Op zaterdag 29 januari 2011 19:25 schreef GS42 het volgende:

[..]

Gaat tegen het idee van de stl containers in, namelijk dat de container de eigenaar van de data is. Netter zou zijn de pointer in een class te wikkelen. Dit is echter erg afhankelijk van smaak en stijl, en iedereen weet dat daarover prima te twisten valt. :)
Mensen kiezen vaak voor c++ vanwege de snelheid, niet omdat de taal zo lekker netjes weg te tikken is... Daarvoor zijn veel geschiktere talen (met garbage collector etc)
netolkzaterdag 29 januari 2011 @ 21:05
die ~int() was even een dummie voor de vraag, maar ik heb dus zo'n vector<Player> waar maar 1 player instaat en toch word de destructor 2x aangeroepen...
quote:
1s.gif Op zaterdag 29 januari 2011 19:14 schreef GS42 het volgende:

[..]

Ja, als er een destructor bestaat zal deze aangeroepen worden. Dit geldt echter alleen als je classes (of base-types) in de vector opslaat. Als je std::vector<X*> gebruikt, zal de X::~X() destructor niet automatisch aangeroepen worden. Daarom wordt het ook als niet netjes gezien om pointers in containers op te slaan.

Edit: Oh, ik had het bovenstaande antwoord gemist.
tja ik kan het ook in een matrix / array zetten maar dat is weer gekut als je er data aan toe wilt voegen, dan kan dat wel met classes die dan naar het volgende object wijzen maar waarom zou ik dat doen als ik ook gewoon vector<int*> kan gebruiken? en het dan via een destructor kan laten verwijderen
netolkzaterdag 29 januari 2011 @ 21:10
code bij mijn vorige post

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <vector>
class Temp{
    int i;
    public:
        Temp(){}
        ~Temp(){
            std::cout << "Destructor\n";
        }
};
int main(){
    std::vector<Temp> myvec;
    myvec.push_back(Temp());
    
    return 0;
}
output:
1
2
Destructor
Destructor

en als ik de push_back(Temp()) weglaat roept ie de destructor helemaal niet aan, maar waarom word de destructor 2x aangeroepen als er maar 1 object is?
thabitzaterdag 29 januari 2011 @ 21:11


[ Bericht 100% gewijzigd door thabit op 29-01-2011 21:11:28 (was te snel) ]
netolkzaterdag 29 januari 2011 @ 21:11
quote:
1s.gif Op zaterdag 29 januari 2011 21:11 schreef thabit het volgende:

:P

of ik te laat
GS42zaterdag 29 januari 2011 @ 21:13
quote:
1s.gif Op zaterdag 29 januari 2011 21:05 schreef netolk het volgende:
die ~int() was even een dummie voor de vraag, maar ik heb dus zo'n vector<Player> waar maar 1 player instaat en toch word de destructor 2x aangeroepen...
Dat is mogelijk en niets om je zorgen over te maken. Bij het kopieren naar de vector is het mogelijk dat er een kopie gemaakt moet worden en dus voor het oude object een destructor aangeroepen wordt. (Sterker nog, aan de code van je kun je zien dat de compiler dit moet doen.) Ook moet een vector zichzelf vaak in geheugen verplaatsen waarbij het kopieen van objecten moet maken en de destructor kan gebruiken, evenals de copy constructor van de klasse (maar dit zou bij 1 object niet moeten gebeuren).

quote:
tja ik kan het ook in een matrix / array zetten maar dat is weer gekut als je er data aan toe wilt voegen, dan kan dat wel met classes die dan naar het volgende object wijzen maar waarom zou ik dat doen als ik ook gewoon vector<int*> kan gebruiken? en het dan via een destructor kan laten verwijderen
Bijvoorbeeld in het vorige voorbeeld. Als je de pointer in een klasse wikkelt die de geheugenafhandeling doet, hoef je er op dit moment niet meer aan te denken. Anders moet je voor elke klasse die een vector<int*> gebruikt, een destructor, copy constructor en eventueel een operator=() schrijven, terwijl een vector<IntPointer> dit zelf op zou kunnen lossen. Maar opnieuw: dit heeft veel met persoonlijke stijl te maken.
thabitzaterdag 29 januari 2011 @ 21:17
quote:
1s.gif Op zaterdag 29 januari 2011 21:10 schreef netolk het volgende:
code bij mijn vorige post

[ code verwijderd ]

output:

[ code verwijderd ]

en als ik de push_back(Temp()) weglaat roept ie de destructor helemaal niet aan, maar waarom word de destructor 2x aangeroepen als er maar 1 object is?
Omdat er 2 Temp-objecten zijn. ;). Zie je waarom?
netolkzaterdag 29 januari 2011 @ 21:19
quote:
1s.gif Op zaterdag 29 januari 2011 21:17 schreef thabit het volgende:

[..]

Omdat er 2 Temp-objecten zijn. ;). Zie je waarom?
JA, ik zie het nu :) tenminste, omdat ie een copy maakt van de Temp() die ik declareer in de push_back() toch?
thabitzaterdag 29 januari 2011 @ 21:20
Juist. Het zoveelste nadeel van value-typed objecten.
netolkzaterdag 29 januari 2011 @ 21:21
quote:
14s.gif Op zaterdag 29 januari 2011 21:20 schreef thabit het volgende:
Juist. Het zoveelste nadeel van value-typed objecten.
Dit soort dingen zijn niet te voorkomen zeker?
thabitzaterdag 29 januari 2011 @ 21:26
quote:
1s.gif Op zaterdag 29 januari 2011 21:21 schreef netolk het volgende:

[..]

Dit soort dingen zijn niet te voorkomen zeker?
Als je per se wilt dat je vector geen pointers bevat (ik lees net dat references niet mogen), dan vrees ik dat dat lastig gaat worden ja.
GS42zaterdag 29 januari 2011 @ 21:30
quote:
1s.gif Op zaterdag 29 januari 2011 21:21 schreef netolk het volgende:

[..]

Dit soort dingen zijn niet te voorkomen zeker?
Als je een c++0x-compatible compiler gebruikt, dan moet je dit kunnen voorkomen door met std::move() een r-value-reference mee te geven aan de push_back. Dan wordt er geen kopie gemaakt. De std::vector hoort dit te ondersteunen.
netolkzaterdag 29 januari 2011 @ 21:34
hmm, die pointers in een vector zijn ook verre van ideaal want ik heb een class waar zo'n vector<*int> in staat alleen staat die class zelf ook weer in een vector dus word ie gekopieerd wat er voor zorgt dat de destructor word aangeroepen zodat de pointer geen betekenis meer heeft...

dus ik ga het dan nu maar op de "nette" manier doen (GS42 ook weer blij :P)

PS. *int is nog steeds dummie
thabitzaterdag 29 januari 2011 @ 21:39
In de destructor van die class kun je toch gewoon een delete over die vector heen lussen?
GS42zaterdag 29 januari 2011 @ 21:45
quote:
1s.gif Op zaterdag 29 januari 2011 21:34 schreef netolk het volgende:

dus ik ga het dan nu maar op de "nette" manier doen (GS42 ook weer blij :P)

Dan moet je misschien ook even kijken naar de unique- en shared-pointer (c++0x): http://www.icce.rug.nl/documents/cplusplus/cplusplus18.html#l286
Of als je op een oudere compiler zit: http://www.cplusplus.com/reference/std/memory/auto_ptr/
(EDIT: Nu ik de stof nog eens nalees, zie ik dat je de auto_prt niet moet gebruiken in containers (zie eerste link).

Dat kan je weer een klasse schrijven schelen. :)

[ Bericht 6% gewijzigd door GS42 op 29-01-2011 22:18:07 ]
netolkzaterdag 29 januari 2011 @ 21:50
hmm... ik had een simpele struct geschreven

1
2
3
4
5
struct T_sptr{
   Temp *_ptr
   T_sptr(Temp *pointer):_ptr(pointer){}
   ~T_sptr(){delete _ptr; _ptr=0;}
};

alleen hiermee geeft het nog eerder een runtime fout...
thabitzaterdag 29 januari 2011 @ 22:07
quote:
1s.gif Op zaterdag 29 januari 2011 21:50 schreef netolk het volgende:
hmm... ik had een simpele struct geschreven

[ code verwijderd ]

alleen hiermee geeft het nog eerder een runtime fout...
Waar gaat wat dan precies fout?
GS42zaterdag 29 januari 2011 @ 22:08
quote:
1s.gif Op zaterdag 29 januari 2011 21:50 schreef netolk het volgende:
hmm... ik had een simpele struct geschreven

alleen hiermee geeft het nog eerder een runtime fout...
Het is ook wat te kort door de bocht voor een pointer class. Als deze struct gekopierd wordt, wordt de _ptr by value gekopierd. Dan wordt het oude object vernietigd. Oftewel: het nieuwe object verwijst naar iets wat niet meer bestaat.
Als je een eigen pointer class wilt schrijven, moet je denken aan de copy constructor, destructor, operator= en eventueel de operator* en operator->. Daarom zijn de stl-pointers ook erg handig:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <vector>
#include <memory>

int main() {

    std::vector< std::unique_ptr<int> > pvect;
    
    for (size_t idx = 0; idx < 10; ++idx)
        pvect.push_back(std::unique_ptr<int>(new int(42)));
        
    std::cout << "Adding done." << std::endl;

    for (size_t idx = 0; idx < 10; ++idx)
        std::cout << *pvect[idx] << ' ';
}

Let wel dat je compileert met -std=c++0x.
netolkzaterdag 29 januari 2011 @ 22:16
quote:
1s.gif Op zaterdag 29 januari 2011 22:08 schreef GS42 het volgende:

[..]

Het is ook wat te kort door de bocht voor een pointer class. Als deze struct gekopierd wordt, wordt de _ptr by value gekopierd. Dan wordt het oude object vernietigd. Oftewel: het nieuwe object verwijst naar iets wat niet meer bestaat.
Als je een eigen pointer class wilt schrijven, moet je denken aan de copy constructor, destructor, operator= en eventueel de operator* en operator->. Daarom zijn de stl-pointers ook erg handig:

[ code verwijderd ]

Let wel dat je compileert met -std=c++0x.
owja, dan hou ik het zelfde probleem natuurlijk |:(

en als ik nou eens in plaats van een vector een linked list maak?
of is dat moeilijk te realiseren? Ik heb nog nooit zo iets gemaakt namelijk

maar die unique pointer die maakt dan dus een nieuw opject aan als het gekopieerd word?
GS42zaterdag 29 januari 2011 @ 22:16
quote:
1s.gif Op zaterdag 29 januari 2011 22:16 schreef netolk het volgende:

maar die unique pointer die maakt dan dus een nieuw opject aan als het gekopieerd word?
Sowieso wordt een nieuw object gemaakt, de unique_pointer is namelijk een object. Voor hetgene waar de ptr naar wijst hoeft dit echter niet te gelden. Als het mogelijk is, wordt de move constructor gebruikt waardoor dus geen deep copy nodig is. Dat is hier na te lezen.

Ik verwacht niet dat in een vector kopieen worden gemaakt. Het overzetten naar een linked list hoeft niet moeilijk te zijn, je pakt bijvoorbeeld een list<> container. Maar ik denk niet dat het nodig is in dit geval.

(Het lijkt ondertussen wel alsof ik reclame maak voor de C++ Annotations. ;))


[ Bericht 67% gewijzigd door GS42 op 29-01-2011 22:29:15 ]
netolkzaterdag 29 januari 2011 @ 22:37
quote:
1s.gif Op zaterdag 29 januari 2011 22:16 schreef GS42 het volgende:

[..]

Sowieso wordt een nieuw object gemaakt, de unique_pointer is namelijk een object. Voor hetgene waar de ptr naar wijst hoeft dit echter niet te gelden. Als het mogelijk is, wordt de move constructor gebruikt waardoor dus geen deep copy nodig is. Dat is hier na te lezen.

Ik verwacht niet dat in een vector kopieen worden gemaakt. Het overzetten naar een linked list hoeft niet moeilijk te zijn, je pakt bijvoorbeeld een list<> container. Maar ik denk niet dat het nodig is in dit geval.

(Het lijkt ondertussen wel alsof ik reclame maak voor de C++ Annotations. ;))

ik gebruik de C++ compiler van mingw (32-bit) maar ik kan nergens vinden of het dat -std=c++0x ondersteund... of hoe ik het aan de compiler moet mee geven, heeft iemand hier ervaring mee?
GS42zaterdag 29 januari 2011 @ 22:44
quote:
1s.gif Op zaterdag 29 januari 2011 22:37 schreef netolk het volgende:

ik gebruik de C++ compiler van mingw (32-bit) maar ik kan nergens vinden of het dat -std=c++0x ondersteund... of hoe ik het aan de compiler moet mee geven, heeft iemand hier ervaring mee?
Als je een nieuwe versie gebruikt van het MinGW pakket, dan wel. Je compiler-versie vind je zo: g++ -v
En de optie kan je uiteraard op dezelfde manier meegeven. Ik zit op hetzelfde systeem (GCC 4.5.0) en compileer zo: g++ -Wall -std=c++0x -o main -enable-auto-import -O3 main.cc
netolkzondag 30 januari 2011 @ 09:37
quote:
1s.gif Op zaterdag 29 januari 2011 22:44 schreef GS42 het volgende:

[..]

Als je een nieuwe versie gebruikt van het MinGW pakket, dan wel. Je compiler-versie vind je zo: g++ -v
En de optie kan je uiteraard op dezelfde manier meegeven. Ik zit op hetzelfde systeem (GCC 4.5.0) en compileer zo: g++ -Wall -std=c++0x -o main -enable-auto-import -O3 main.cc
waarvoor is -wall en auto-import importeert dat alle files in de map waar main staat?

ow hehe ik moet mn compiler maar eens even gaan updaten XD

zit op versie 3.4.5 :'(

[ Bericht 5% gewijzigd door netolk op 30-01-2011 09:49:11 ]
netolkzondag 30 januari 2011 @ 10:10
kut, nu mis ik libgmp-10.dll ... terwijl die wel gewoon op mn pc staat...
GS42zondag 30 januari 2011 @ 12:31
quote:
1s.gif Op zondag 30 januari 2011 09:37 schreef netolk het volgende:

[..]

waarvoor is -wall en auto-import importeert dat alle files in de map waar main staat?
De -Wall is een redleijk veelvoorkomende optie die alle warnings (Warnings ALL: Wall) aanzet, waardoor je tijdens het compileren melding krijgt van legale maar mogelijk gevaarlijke dingen (zoals statements die niets doen of het vergelijken van signed met unsigned waarden).
De enable-auto-import heb ik eigenlijk alleen voor MinGW hoeven gebruiken (en dus niet onder Linux), maar zorgt ervoor dat een waarschuwing over het importeren van dll's niet in beeld komt. Volgens mij is dit Windows- (en misschien zelfs MinGW-) specifiek.

quote:
kut, nu mis ik libgmp-10.dll ... terwijl die wel gewoon op mn pc staat...
Ja, het installeren van MinGW gaat bij mij ook (schijnbaar) willekeurig goed of fout. Al het oude eerst verwijderen (of verplaatsen, ik heb c:/mingw en c:/mingw_old) en dan proberen de getting started te volgen. Toen het eenmaal goed gelukt was, heb ik de map 'mingw' gekopieerd zodat ik deze bij een nieuwe installatie gewoon op een computer kan plakken, zodat ik niet dat hele installatieproces door hoef te lopen. Als het je niet lukt, kan ik je misschien mijn installatie-map (~250mb) wel doorspelen.
Jeroentkzondag 30 januari 2011 @ 16:14
Goedemiddag,

Twee dagen geleden ben ik begonnen met het leren van C++. Heb verder eigenlijk geen programmeerervaring, maar het leek me wel interessant. Mijn eerste programma heb ik nu gemaakt en het is enigszins gelukt. Het programma vraagt eerst om hoeveel getallen je bij elkaar wilt optellen, vraagt daarna om de getallen, stopt ze in een array en geeft vervolgens het antwoord. Helaas zit er wel een grote, potentiële error in, en dat is dat wanneer je bij het invoeren van de getallen geen getal invoert. Hierdoor crash hij (natuurlijk), maar ik weet niet hoe ik dmv bijv. een if of do..while die eruit kan vissen. Weten jullie hoe dat moet?

Verder heb ik zojuist geprobeerd om de ingevoerde getallen doubles ipv integers te maken. Dat lukte wel, maar steeds geeft hij op het einde een error. Hij heeft dan al wel de laatste functie uitgevoerd. Ik heb hieronder eerst de add.cpp gepost, en daarna de main.cpp.

SPOILER
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
#include "stdafx.h"
#include <iostream>
using namespace std;

void AantalGetallen(int &nAantal)
{
    cout << "Hoeveel getallen wilt u bij elkaar optellen?" << endl;
    cin >> nAantal;
    cout << endl;
}

void Vraag(double *&pnGetallen, int nAantal)
{
    for (int iii = 0; iii < nAantal; iii++)
    {
        cout << "Getal " << iii + 1 << ":\t";
        cin >> (pnGetallen[iii]);

    }
}

void PrintArray(double *pnGetallen, int nAantal)
{
    for (int iii = 0; iii < nAantal; iii++)
        cout << pnGetallen[iii] << " ";
}

void Bereken(double *pnGetallen, int nAantal, double &dSom)
{
    dSom = 0;
    for (int iii = 0; iii < nAantal; iii++)
        dSom += pnGetallen[iii];
}

void GeefResultaat(double *pnGetallen, int nAantal, double dSom)
{
    for (int iii = 0; iii < nAantal; iii++)
    {
        cout << pnGetallen[iii];
        if (iii < nAantal - 1)
            cout << " + ";
    }
    cout << " = " << dSom << endl << endl;
}
SPOILER
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "stdafx.h"
#include <iostream>
#include "add.h"
using namespace std;

int main()
{
    int nAantal;
    AantalGetallen(nAantal);
    
    double *pnGetallen = new double;
    Vraag(pnGetallen, nAantal);

    double dSom; 
    Bereken(pnGetallen, nAantal, dSom);
    GeefResultaat(pnGetallen, nAantal, dSom);

    return 0;
}
Verder heb ik ervoor gekozen om zoveel kleine functies te gebruiken, omdat ik het dan makkelijker kan uitbreiden en het overzichtelijker blijft.
Als iemand tips heeft over hoe ik mijn programma op wat voor gebied dan ook kan verbeteren zou ik het graag horen.
thabitzondag 30 januari 2011 @ 16:33
quote:
1s.gif Op zondag 30 januari 2011 16:14 schreef Jeroentk het volgende:
Goedemiddag,

Twee dagen geleden ben ik begonnen met het leren van C++. Heb verder eigenlijk geen programmeerervaring, maar het leek me wel interessant. Mijn eerste programma heb ik nu gemaakt en het is enigszins gelukt. Het programma vraagt eerst om hoeveel getallen je bij elkaar wilt optellen, vraagt daarna om de getallen, stopt ze in een array en geeft vervolgens het antwoord. Helaas zit er wel een grote, potentiële error in, en dat is dat wanneer je bij het invoeren van de getallen geen getal invoert. Hierdoor crash hij (natuurlijk), maar ik weet niet hoe ik dmv bijv. een if of do..while die eruit kan vissen. Weten jullie hoe dat moet?

Verder heb ik zojuist geprobeerd om de ingevoerde getallen doubles ipv integers te maken. Dat lukte wel, maar steeds geeft hij op het einde een error. Hij heeft dan al wel de laatste functie uitgevoerd. Ik heb hieronder eerst de add.cpp gepost, en daarna de main.cpp.

SPOILER
[ code verwijderd ]

SPOILER
[ code verwijderd ]

Verder heb ik ervoor gekozen om zoveel kleine functies te gebruiken, omdat ik het dan makkelijker kan uitbreiden en het overzichtelijker blijft.
Als iemand tips heeft over hoe ik mijn programma op wat voor gebied dan ook kan verbeteren zou ik het graag horen.
Kun je iets specifieker zijn in de foutmeldingen etc?

Een std::vector kan handig zijn als je met arrays wilt werken van variabele lengte.

Verder kun je in plaats van met references als argumenten te werken, de berekende waarde ook als uitkomst meegeven dus, bijvoorbeeld, int AantalGetallen() ipv void AantalGetallen(int &nAantal).
GS42zondag 30 januari 2011 @ 16:58
quote:
Als iemand tips heeft over hoe ik mijn programma op wat voor gebied dan ook kan verbeteren zou ik het graag horen.
Oeh, een excuus om ongegeneerd te gaan muggenziften. :)

Je gebruikt voor elk getal een int. Opzich niets mis mee, maar een int kan ook negatief zijn. In veel getallen is een negatieve waarde geen valide waarde, bijvoorbeeld als je vraagt hoeveel getallen ingelezen moeten worden of als de index van een for-loop. In dit geval kun je beter het 'type' size_t gebruiken, dat in C(++) gebruikt wordt voor een 'size', oftewel een aantal of grootte dat niet negatief kan zijn. ('Type' staat hier tussen aanhalingstekens omdat het een typedef is voor een unsigned int en geen basistype.)

Je gebruikt een postfix increment in de for-loops: idx++. Wederom opzich niets mis mee, behalve dat idx++ een extra operatie uitvoert vergeleken met ++idx. (Lees het verschil maar eens ergens.) Een nette for-loop is dus als volgt:

1for (size_t idx = 0; idx < 10; ++idx)

Ik weet niet of het een typefout betreft, maar de declaratie

1void Vraag(double *&pnGetallen, int nAantal)

...is raar, omdat je een referentie naar een pointer doorgeeft. Ik kan me niet voorstellen dat dat de bedoeling was.

De main() functie van C++ hoeft geen return-waarde te hebben; als deze er niet is, wordt '0' teruggegeven. Je laatste statement in de main is dus nutteloos.

Iets gevaarlijks wat je doet is het volgende:

1double *pnGetallen = new double;

De operator new() alloceert geheugen buiten de stack en alles wat met new aangemaakt wordt, moet ook met delete verwijderd worden. Als je een pointer naar een double mee wilt geven, gebruik je daarvoor de &-operator:

1
2
double d = 3.14;
double *d_ptr = &d;

Pas als je werkelijk geheugen dynamisch wilt alloceren, gebruik je de operator new.

Ik ken de headerfile "stdafx.h" ook niet: weet je zeker dat je die nodig hebt?

Voor invoercontrole kan je het uitlees-statement evalueren:

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>

int main() {

    size_t input;
    std::cout << "Voer een (positief) getal in: ";
    if (std::cin >> input)
        std::cout << "Uw getal is " << input << '\n';
    else
        std::cout << "Verkeerde invoer.\n";
}

Hopelijk heb ik je niet afgeschrikt. :)

[ Bericht 0% gewijzigd door GS42 op 30-01-2011 17:04:15 ]
netolkzondag 30 januari 2011 @ 16:59
quote:
1s.gif Op zondag 30 januari 2011 12:31 schreef GS42 het volgende:

[..]

De -Wall is een redleijk veelvoorkomende optie die alle warnings (Warnings ALL: Wall) aanzet, waardoor je tijdens het compileren melding krijgt van legale maar mogelijk gevaarlijke dingen (zoals statements die niets doen of het vergelijken van signed met unsigned waarden).
De enable-auto-import heb ik eigenlijk alleen voor MinGW hoeven gebruiken (en dus niet onder Linux), maar zorgt ervoor dat een waarschuwing over het importeren van dll's niet in beeld komt. Volgens mij is dit Windows- (en misschien zelfs MinGW-) specifiek.

[..]

Ja, het installeren van MinGW gaat bij mij ook (schijnbaar) willekeurig goed of fout. Al het oude eerst verwijderen (of verplaatsen, ik heb c:/mingw en c:/mingw_old) en dan proberen de getting started te volgen. Toen het eenmaal goed gelukt was, heb ik de map 'mingw' gekopieerd zodat ik deze bij een nieuwe installatie gewoon op een computer kan plakken, zodat ik niet dat hele installatieproces door hoef te lopen. Als het je niet lukt, kan ik je misschien mijn installatie-map (~250mb) wel doorspelen.
hmm die -wall deed ie hoe dan ook altijd al bij mij, maar krijg die mingw echt niet reďnstalleerd... :( eens even kijken hoe het met manual install gaat
Jeroentkzondag 30 januari 2011 @ 17:05
De error wanneer je geen getal invoert:
SPOILER
errorc2.jpg
De error die ik kreeg nadat ik van enkele ints doubles had gemaakt (zodat ik ook 0.66 + 0.33 kon doen etc.):
SPOILER
errorc3.jpg
Verder leek het me juist handig om voids te gebruiken, zodat ik geen hele functies in functies hoefde in te voeren? (zoals GeefResultaat(Vraag(AantalGetallen(), AantalGetallen(), Bereken(Vraag(AantalGetallen), AantalGetallen(), ... etc.
thabitzondag 30 januari 2011 @ 17:13
De plaatjes doen het niet bij mij.
netolkzondag 30 januari 2011 @ 17:14
quote:
1s.gif Op zondag 30 januari 2011 17:13 schreef thabit het volgende:
Plaatjes doen het niet bij mij.
bij mij ook niet...

@GS42, handmatig installeren is al helemaal niet te doen.. :( zou ik jou mingw mapje mogen hebben?
thabitzondag 30 januari 2011 @ 17:16
quote:
1s.gif Op zondag 30 januari 2011 17:05 schreef Jeroentk het volgende:
De error wanneer je geen getal invoert:
SPOILER
De error die ik kreeg nadat ik van enkele ints doubles had gemaakt (zodat ik ook 0.66 + 0.33 kon doen etc.):
SPOILER
Verder leek het me juist handig om voids te gebruiken, zodat ik geen hele functies in functies hoefde in te voeren? (zoals GeefResultaat(Vraag(AantalGetallen(), AantalGetallen(), Bereken(Vraag(AantalGetallen), AantalGetallen(), ... etc.
Je kan ook iets doen als n = AantalGetallen() ipv Aantalgetallen(n)
Jeroentkzondag 30 januari 2011 @ 17:22
quote:
1s.gif Op zondag 30 januari 2011 16:58 schreef GS42 het volgende:

[..]

Oeh, een excuus om ongegeneerd te gaan muggenziften. :)

Je gebruikt voor elk getal een int. Opzich niets mis mee, maar een int kan ook negatief zijn. In veel getallen is een negatieve waarde geen valide waarde, bijvoorbeeld als je vraagt hoeveel getallen ingelezen moeten worden of als de index van een for-loop. In dit geval kun je beter het 'type' size_t gebruiken, dat in C(++) gebruikt wordt voor een 'size', oftewel een aantal of grootte dat niet negatief kan zijn. ('Type' staat hier tussen aanhalingstekens omdat het een typedef is voor een unsigned int en geen basistype.)
Ah, uiteraard. Zou hier niet bijvoorbeeld ook een simpele unsigned int toepasbaar zijn? Size(_t) ken ik niet, maar zoals u (jij?) het beschrijft lijkt het me dezelfde eigenschappen hebben als een unsigned int.

quote:
1s.gif Op zondag 30 januari 2011 16:58 schreef GS42 het volgende:
e gebruikt een postfix increment in de for-loops: idx++. Wederom opzich niets mis mee, behalve dat idx++ een extra operatie uitvoert vergeleken met ++idx. (Lees het verschil maar eens ergens.) Een nette for-loop is dus als volgt:

[ code verwijderd ]
kan het niet allebei? Dus ofwel dat je doet:
1for (size_t iii = 0; iii < 10; ++iii)
ofwel dit, en dat het dezelfde uitkomst heeft?
1for (size_t iii = 0; iii <= 10; iii++)

Overigens dacht ik dat bij ++iii je nooit iii = 0 krijgt?

quote:
1s.gif Op zondag 30 januari 2011 16:58 schreef GS42 het volgende:
Ik weet niet of het een typefout betreft, maar de declaratie

[ code verwijderd ]

...is raar, omdat je een referentie naar een pointer doorgeeft. Ik kan me niet voorstellen dat dat de bedoeling was.
Ik heb deze *&pnGetallen gedaan, zodat ik de Array pnGetallen kon bewerken in de void? Moet dat anders/doe ik het niet goed?

quote:
1s.gif Op zondag 30 januari 2011 16:58 schreef GS42 het volgende:
De main() functie van C++ hoeft geen return-waarde te hebben; als deze er niet is, wordt '0' teruggegeven. Je laatste statement in de main is dus nutteloos.
Oke, bedankt voor de informatie, dat wist ik niet. :)

quote:
1s.gif Op zondag 30 januari 2011 16:58 schreef GS42 het volgende:
Iets gevaarlijks wat je doet is het volgende:

[ code verwijderd ]

De operator new() alloceert geheugen buiten de stack en alles wat met new aangemaakt wordt, moet ook met delete verwijderd worden. Als je een pointer naar een double mee wilt geven, gebruik je daarvoor de &-operator:

[ code verwijderd ]

Pas als je werkelijk geheugen dynamisch wilt alloceren, gebruik je de operator new.
Ik wil ook dynamisch alloceren, omdat de grootte van de array nog niet bepaald is, toch? Ik moet volgens mij wel sowieso nadat ik met new een array heb gemaakt, even delete[] pnArray doen, toch? Of gaat dat vanzelf wanneer het programma afsluit?

quote:
1s.gif Op zondag 30 januari 2011 16:58 schreef GS42 het volgende:
Ik ken de headerfile "stdafx.h" ook niet: weet je zeker dat je die nodig hebt?
Die is volgens mij nodig voor de compiler die ik gebruik (Microsoft Visual C++ 2010 Express)

quote:
1s.gif Op zondag 30 januari 2011 16:58 schreef GS42 het volgende:
Voor invoercontrole kan je het uitlees-statement evalueren:

[ code verwijderd ]
Oke, hierbij is dus input per definitie bijv. een int, en als de invoer geen int is geeft hij een error/kan je er iets mee doen? Bedankt. :)

quote:
1s.gif Op zondag 30 januari 2011 16:58 schreef GS42 het volgende:
Hopelijk heb ik je niet afgeschrikt. :)
Zeker niet, altijd goed om verbeterpunten te zien. Bedankt. :)
thabitzondag 30 januari 2011 @ 17:27
Het verschil tussen ++i en i++ is als volgt. Beide expressies verhogen i met 1, maar het zijn ook expressies met een waarde. ++i heeft als waarde i na de verhoging, en i++ heeft als waarde i voor de verhoging. Omdat je de expressie alleen maar als statement gebruikt, zal de compiler de waarde volkomen negeren, i++ en ++i zijn in dit geval precies hetzelfde. Maar als i een of ander class-object is waarvoor beide operatoren gedefinieerd zijn, dan zal i++ net iets meer tijd kosten om uit te voeren omdat-ie de oude waarde moet returnen ipv de nieuwe.
netolkzondag 30 januari 2011 @ 17:29
quote:
1s.gif Op zondag 30 januari 2011 17:22 schreef Jeroentk het volgende:

Ah, uiteraard. Zou hier niet bijvoorbeeld ook een simpele unsigned int toepasbaar zijn? Size(_t) ken ik niet, maar zoals u (jij?) het beschrijft lijkt het me dezelfde eigenschappen hebben als een unsigned int.

kan het niet allebei? Dus ofwel dat je doet:
dat klopt idd je kan beide methode gebruiken...
Alleen weetje met size_t zeker dat je getal altijd groot genoeg kan worden

quote:
Overigens dacht ik dat bij ++iii je nooit iii = 0 krijgt?
Dit kan je zelf heel eenvoudig checken hč...
1
2
3
4
#include <iostream>
for(int i = 0; i < 10; ++i){
  std::cout << i << std::endl;
}
quote:
Ik wil ook dynamisch alloceren, omdat de grootte van de array nog niet bepaald is, toch? Ik moet volgens mij wel sowieso nadat ik met new een array heb gemaakt, even delete[] pnArray doen, toch? Of gaat dat vanzelf wanneer het programma afsluit?
Je moet delete altijd aanroepen anders kan je geheugenleaks krijgen

quote:
Die is volgens mij nodig voor de compiler die ik gebruik (Microsoft Visual C++ 2010 Express)

compiled die niet ook gewoon zonder die include?
Jeroentkzondag 30 januari 2011 @ 17:40
quote:
1s.gif Op zondag 30 januari 2011 17:27 schreef thabit het volgende:
Het verschil tussen ++i en i++ is als volgt. Beide expressies verhogen i met 1, maar het zijn ook expressies met een waarde. ++i heeft als waarde i na de verhoging, en i++ heeft als waarde i voor de verhoging. Omdat je de expressie alleen maar als statement gebruikt, zal de compiler de waarde volkomen negeren, i++ en ++i zijn in dit geval precies hetzelfde. Maar als i een of ander class-object is waarvoor beide operatoren gedefinieerd zijn, dan zal i++ net iets meer tijd kosten om uit te voeren omdat-ie de oude waarde moet returnen ipv de nieuwe.
Oke, ik zal dus wanneer ik ze nodig heb in statements ++i gebruiken. Bedankt. :)

quote:
1s.gif Op zondag 30 januari 2011 17:29 schreef netolk het volgende:

[..]

dat klopt idd je kan beide methode gebruiken...
Alleen weetje met size_t zeker dat je getal altijd groot genoeg kan worden
Size_t past zich dan ook aan aan de invoer? Want waarom zou je dan überhaupt nog ooit int gebruiken?

quote:
1s.gif Op zondag 30 januari 2011 17:29 schreef netolk het volgende:

Je moet delete altijd aanroepen anders kan je geheugenleaks krijgen
Oke, bedankt. Gedaan. :)

quote:
1s.gif Op zondag 30 januari 2011 17:29 schreef netolk het volgende:
compiled die niet ook gewoon zonder die include?
Nee, ik heb het geprobeerd, maar ik krijg dan de volgende error:
1>c:\*\add.cpp(1): warning C4627: '#include <iostream>': skipped when looking for precompiled header use

Links naar de afbeeldingen:
http://img412.imageshack.us/f/errorc2.jpg/
Error wanneer ik 'A' invul.
http://img821.imageshack.us/i/errorc3.jpg/
Error nadat ik gewone getallen heb ingevuld..
thabitzondag 30 januari 2011 @ 17:46
Dat zijn bufferoverflows. Je hebt geen geheugenruimte gereserveerd voor de arrays waarin je schrijft.
Jeroentkzondag 30 januari 2011 @ 18:03
Oh, bedankt, dat is een vrij opzichtige fout. Wel erg makkelijk te herstellen.. simpelweg door te schrijven:

1
2
3
4
size_t nAantal;
AantalGetallen(nAantal);
    
double *pnGetallen = new double[nAantal];
netolkzondag 30 januari 2011 @ 18:13
quote:
1s.gif Op zondag 30 januari 2011 18:03 schreef Jeroentk het volgende:
Oh, bedankt, dat is een vrij opzichtige fout. Wel erg makkelijk te herstellen.. simpelweg door te schrijven:

[ code verwijderd ]

ja, idd maar waarom maak je je AantalGetallen functie niet gewoon zo?

1
2
3
4
5
6
7
size_t AantalGetallen(){
    size_t nAantal=0;
    cout << "Hoeveel getallen wilt u bij elkaar optellen?" << endl;
    cin >> nAantal;
    cout << endl;
    return nAantal;
}

dan kan je het gewoon zo schrijven:
1double *pnGetallen = new double[AantalGetallen()];
DemonRagezondag 30 januari 2011 @ 18:15
quote:
1s.gif Op zondag 30 januari 2011 17:27 schreef thabit het volgende:
Het verschil tussen ++i en i++ is als volgt. Beide expressies verhogen i met 1, maar het zijn ook expressies met een waarde. ++i heeft als waarde i na de verhoging, en i++ heeft als waarde i voor de verhoging. Omdat je de expressie alleen maar als statement gebruikt, zal de compiler de waarde volkomen negeren, i++ en ++i zijn in dit geval precies hetzelfde. Maar als i een of ander class-object is waarvoor beide operatoren gedefinieerd zijn, dan zal i++ net iets meer tijd kosten om uit te voeren omdat-ie de oude waarde moet returnen ipv de nieuwe.
Sterker nog:
_asm { inc i }

is sneller dan:
++i;
wat zich vertaalt naar:
mov eax, dword ptr [i]
add eax, 1
move dword ptr [i], eax


Maar het eerste is wel minder platform onafhankelijk en het werkt alleen op primitieve typen. :+
thabitzondag 30 januari 2011 @ 18:19
Het lijkt me toch dat een compiler dat nog wel moet kunnen optimaliseren. :?
DemonRagezondag 30 januari 2011 @ 18:31
quote:
1s.gif Op zondag 30 januari 2011 18:19 schreef thabit het volgende:
Het lijkt me toch dat een compiler dat nog wel moet kunnen optimaliseren. :?
Als je 'm laat optimaliseren voor snelheid dan waarschijnlijk wel. Bij mij wordt add eax, 1 wel veranderd in inc eax. De reden dat-ie nog wel eerst mov eax, dword ptr [i] doet is omdat eax wordt gebruikt als parameter bij het aanroepen van printf. eax wordt dus eerst gepusht op de stack en dan opgeslagen in het geheugen met mov dword ptr [i], eax, voordat de call naar printf plaats vindt.

[ Bericht 1% gewijzigd door DemonRage op 30-01-2011 18:42:45 ]
GS42zondag 30 januari 2011 @ 18:44
quote:
Je moet delete altijd aanroepen anders kan je geheugenleaks krijgen
Wat nette code betreft, klopt dit, maar als antwoord op de vraag: als je programma termineert wordt gealloceerd geheugen wel teruggeven aan het OS, dus je verliest nooit geheugenruimte. (Wel kan het zijn dat destrcutors niet aangeroepen worden waarin je iets belangrijks doet (port sluiten, bestand schrijven), dus altijd delete-en, maar het geheugen zelf wordt teruggegeven.)

quote:
Ik wil ook dynamisch alloceren, omdat de grootte van de array nog niet bepaald is, toch? Ik moet volgens mij wel sowieso nadat ik met new een array heb gemaakt, even delete[] pnArray doen, toch? Of gaat dat vanzelf wanneer het programma afsluit?
Hier ligt waarschijnlijk ook je buffer overflow probleem: je alloceert geen array, je alloceert een (1) double. Arrays alloceer je met operator new[], die ook een lengte verwacht. Als je alleen new gebruikt, alloceer je slechts ruimte voor 1 double. Details zijn bijvoorbeeld hier te vinden.

Edit: Oh, ik zie dat je dat al had gevonden. Naja. :)

[ Bericht 5% gewijzigd door GS42 op 30-01-2011 19:03:54 ]
thabitzondag 30 januari 2011 @ 18:53
quote:
1s.gif Op zondag 30 januari 2011 18:31 schreef DemonRage het volgende:

[..]

Als je 'm laat optimaliseren voor snelheid dan waarschijnlijk wel. Bij mij wordt add eax, 1 wel veranderd in inc eax. De reden dat-ie nog wel eerst mov eax, dword ptr [i] doet is omdat eax wordt gebruikt als parameter bij het aanroepen van printf. eax wordt dus eerst gepusht op de stack en dan opgeslagen in het geheugen met mov dword ptr [i], eax, voordat de call naar printf plaats vindt.
Zal wel komen doordat printf een int als returnwaarde heeft en die worden doorgaans in eax doorgegeven.
DemonRagezondag 30 januari 2011 @ 18:56
quote:
1s.gif Op zondag 30 januari 2011 18:53 schreef thabit het volgende:

[..]

Zal wel komen doordat printf een int als returnwaarde heeft en die worden doorgaans in eax doorgegeven.
Nee, het is sneller om eax meteen te gebruiken dan om de waarde van i na de optelling uit het geheugen te plukken, want in eax zit dan toch al het resultaat van de optelling. :) (het gaat nog steeds om code die vóór de aanroep van printf uitgevoerd wordt)
Jeroentkzondag 30 januari 2011 @ 19:12
quote:
1s.gif Op zondag 30 januari 2011 18:13 schreef netolk het volgende:

[..]

ja, idd maar waarom maak je je AantalGetallen functie niet gewoon zo?

[ code verwijderd ]

dan kan je het gewoon zo schrijven:

[ code verwijderd ]

Zoiets zou ik ook kunnen doen, ja, maar mij lijkt dat minder praktisch. Dit omdat ik meerdere keren AantalGetallen() zou moeten gebruiken en hij hem dus ook meerdere keren activeert. Om dit te voorkomen zou ik er een variabele aan toe kunnen schrijven, maar dan heb je uiteindelijk meer code. Maar misschien zit ik fout, en is die andere manier toch sneller. Wel zou ik dan graag weten hoe ik kan voorkomen dat AantalGetallen() steeds opnieuw uitgevoerd wordt, zonder er een variabele aan toe te schrijven.. Tenzij een variabele eraan toeschrijven uiteindelijk toch nog sneller is dan de manier die ik al heb beschreven. :)
netolkzondag 30 januari 2011 @ 19:36
quote:
1s.gif Op zondag 30 januari 2011 19:12 schreef Jeroentk het volgende:

[..]

Zoiets zou ik ook kunnen doen, ja, maar mij lijkt dat minder praktisch. Dit omdat ik meerdere keren AantalGetallen() zou moeten gebruiken en hij hem dus ook meerdere keren activeert. Om dit te voorkomen zou ik er een variabele aan toe kunnen schrijven, maar dan heb je uiteindelijk meer code. Maar misschien zit ik fout, en is die andere manier toch sneller. Wel zou ik dan graag weten hoe ik kan voorkomen dat AantalGetallen() steeds opnieuw uitgevoerd wordt, zonder er een variabele aan toe te schrijven.. Tenzij een variabele eraan toeschrijven uiteindelijk toch nog sneller is dan de manier die ik al heb beschreven. :)
en wat is het probleem dat je een functie vaker gebruikt?
Alles in een functie word opnieuw "aangemaakt" als je de functie aanroept, dus je variabele word gewoon opnieuw gemaakt.

ik volg even niet helemaal wat je bedoelt met voorkomen dat ie steeds opnieuw uitgevoerd word...
Als je die functie maar 1 x aanroept word ie ook maar 1x uitgevoerd (tenzij je een loop maakt)

maar als je 1x een getal wilt invullen en dan met dat getal allemaal dingen wilt doen kun je beter 1 variabele maken en daar je ingevulde getal in opslaan...

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
int main(){
   size_t getal;
   std::cout << "Vul een getal in.\t"
   std::cin >> getal;
   std::cout << std::endl;
   
   // hier dingen doen met dat getal
  
  return 0;
}
Jeroentkzondag 30 januari 2011 @ 19:44
Ja, dat is inderdaad wat ik wil. Maar ik wil dat niet in de main() doen, dus heb ik 2 opties: of ik voer de functie uit en schrijf iets van:
1size_t AantalGetallen = AantalGetallen()
of ik gebruik degene die ik al heb laten zien, waarin ik eerst een variabele maak, die meegeef aan een void die hem vervolgens verandert. Ik weet niet welke sneller is?
netolkzondag 30 januari 2011 @ 19:49
quote:
1s.gif Op zondag 30 januari 2011 19:44 schreef Jeroentk het volgende:
Ja, dat is inderdaad wat ik wil. Maar ik wil dat niet in de main() doen, dus heb ik 2 opties: of ik voer de functie uit en schrijf iets van:

[ code verwijderd ]

of ik gebruik degene die ik al heb laten zien, waarin ik eerst een variabele maak, die meegeef aan een void die hem vervolgens verandert. Ik weet niet welke sneller is?
qua snelheid maakt het denk ik niet merkbaar wat uit, als je via referenties (&) iets aan een functie door geeft kost dat volgens mij wel minder geheugen (verbeter me als dit niet klopt)

maar waarom wil je dit niet in de main doen dan? want dit is niet zo'n groot programma dus blijft het wel overzichtelijk... (tenzij je dit als oefening doet dan heb ik niks gezegd)
Jeroentkzondag 30 januari 2011 @ 19:52
Jep, ik doe dit allemaal als een oefening. ;) Ik ben nog niet zo lang bezig (2 dagen :') ) en ik had dit programma vooral geschreven om te proberen de pointers en referenties toe te passen met arrays ed. Toch bedankt. :)
netolkzondag 30 januari 2011 @ 21:46
quote:
1s.gif Op zondag 30 januari 2011 19:52 schreef Jeroentk het volgende:
Jep, ik doe dit allemaal als een oefening. ;) Ik ben nog niet zo lang bezig (2 dagen :') ) en ik had dit programma vooral geschreven om te proberen de pointers en referenties toe te passen met arrays ed. Toch bedankt. :)
ahh, ik snap :)

Het zijn hele handige dingen maar je moet zorgen dat je voor elke new ook een delete uitvoert vanwege de geheugen leaks... en dat is soms nog best lastig...
GS42maandag 31 januari 2011 @ 00:05
quote:
Ik heb deze *&pnGetallen gedaan, zodat ik de Array pnGetallen kon bewerken in de void? Moet dat anders/doe ik het niet goed?
In C(++) is een array in principe een (const) pointer. Als je een int[5] aan een functie doorgeeft, kan je die opvangen als int*. Hierbij weet de functie de lengte van de array niet, dus wordt deze vaak als extra argument meegegeven. (De main functie, int main(int argc, char **argv) {} is hier een voorbeeld van.) Je kunt in jouw code de reference (&) dus gewoon weglaten: een reference naar een pointer is nooit nodig - ik kan ten minste geen nut verzinnen.

quote:
Size_t past zich dan ook aan aan de invoer? Want waarom zou je dan überhaupt nog ooit int gebruiken?
In vrijwel elke implementatie is 'size_t' identiek aan 'unsigned int' en heeft dus geen speciale eigenschappen, het is een typedef voor een basistype en past zich niet aan aan de invoer. Je kunt er echter niet vanuit gaan dat size_t gelijk is aan unsigned int, omdat dit niet in de standaard staat. Veel stl-functies geven size_t's terug (std::string::length() en std::string::find(), bijvoorbeeld). Om deze op te vangen is het beter een size_t te gebruiken omdat je dan gegarandeerd het goede type hebt: als je deze immers in een unsigned int opvangt, hoop je maar dat dit hetzelfde is.

Je wordt dus min of meer gedwongen om size_t voor afstandsmaten te gebruiken: zo garandeer je maximale portability van je code. En waarom ook niet? Het is minder typewerk en heeft geen overhead...

En natuurlijk wil je soms wel een int gebruiken, bijvoorbeeld als negatieve waarden ook mogelijk zijn. Je wilt nooit de buitentemperatuur in een size_t zetten, maar een array-index wel. Als negatieve waarden geen (valide) betekenis in je variabele hebben, gebruik je size_t.

quote:
qua snelheid maakt het denk ik niet merkbaar wat uit, als je via referenties (&) iets aan een functie door geeft kost dat volgens mij wel minder geheugen (verbeter me als dit niet klopt)
Ik denk niet dat het in dit geval iets uitmaakt. Een return-by-argument heeft de overhead van het maken en dereferencen van een pointer. Een standaard return moet in principe een kopie maken van het object dat hij teruggeeft. (Dit gebeurt in de praktijk zelden, elke hedendaagse compiler past indien mogelijk copy elision toe, waardoor er geen kopie gemaakt wordt.) Dus ook qua geheugengebruik verwacht ik geen merkbaar verschil.
thabitmaandag 31 januari 2011 @ 00:10
Op 64-bitssystemen is een size_t een 64-bits unsigned integer en een int 32-bits. Voor indexering van arrays e.d. is het altijd het handigst een size_t te gebruiken.
Jeroentkmaandag 31 januari 2011 @ 07:05
quote:
1s.gif Op maandag 31 januari 2011 00:05 schreef GS42 het volgende:

[..]

In C(++) is een array in principe een (const) pointer. Als je een int[5] aan een functie doorgeeft, kan je die opvangen als int*. Hierbij weet de functie de lengte van de array niet, dus wordt deze vaak als extra argument meegegeven. (De main functie, int main(int argc, char **argv) {} is hier een voorbeeld van.) Je kunt in jouw code de reference (&) dus gewoon weglaten: een reference naar een pointer is nooit nodig - ik kan ten minste geen nut verzinnen.

[..]
Oke, ik had hier gelezen dat je ze wel kunt gebruiken om de waarden van pointers te veranderen binnen functies, maar ik heb inderdaad eens geprobeerd om de reference weg te laten en het werkte. Bedankt. :) Wel vraag ik me af of je nu altijd dat kunt weglaten, of dat dat alleen bij een array zo is? Of is het hier zo van array = pointer.

quote:
1s.gif Op maandag 31 januari 2011 00:05 schreef GS42 het volgende:In vrijwel elke implementatie is 'size_t' identiek aan 'unsigned int' en heeft dus geen speciale eigenschappen, het is een typedef voor een basistype en past zich niet aan aan de invoer. Je kunt er echter niet vanuit gaan dat size_t gelijk is aan unsigned int, omdat dit niet in de standaard staat. Veel stl-functies geven size_t's terug (std::string::length() en std::string::find(), bijvoorbeeld). Om deze op te vangen is het beter een size_t te gebruiken omdat je dan gegarandeerd het goede type hebt: als je deze immers in een unsigned int opvangt, hoop je maar dat dit hetzelfde is.

Je wordt dus min of meer gedwongen om size_t voor afstandsmaten te gebruiken: zo garandeer je maximale portability van je code. En waarom ook niet? Het is minder typewerk en heeft geen overhead...
Maar een size_t 'reserveert' dus eigenlijk dubbel zoveel ruimte als een int? Of is dat alleen omdat het niet negatief kan gaan?

Verder had ik nog een vraag: met betreft het eruit filteren van tekst in plaats van getallen heb ik geprobeerd een beroep te doen op de isnan() functie. Ik had gehoord dat die in de <math.h> stond, maar wanneer ik dit heb zegt hij nog steeds dat isnan een undefined identifier is..
1
2
#include <math.h>
if (isnan('test'));
Hoe kan ik hem wel werkende krijgen?
GS42maandag 31 januari 2011 @ 09:05
quote:
Wel vraag ik me af of je nu altijd dat kunt weglaten, of dat dat alleen bij een array zo is? Of is het hier zo van array = pointer.
Bij arrays is een reference niet nodig, bij basic types en classes is deze (of een pointer) wel nodig als je de waarde van de variabele in de functie wilt veranderen. Het geldt niet helemaal dat array == pointer, maar nadat de array opgevangen is door een functie wel (binnen de functie). Het verschil tussen een array en een pointer is dat je een pointer een nieuwe waarde kunt geven en een array-naam niet. Dus:

1
2
3
4
int arr[3] = {1, 2, 3}; // Maak array van 3 elementen
int *ptr = arr; // Maak pointer die naar begin van array wijst
++ptr; // Zet pointer op tweede element van array
++arr; // ILLEGAAL! Waarde van 'arr' ligt vast en kan niet veranderd worden

quote:
Maar een size_t 'reserveert' dus eigenlijk dubbel zoveel ruimte als een int?
Daar is dus niets over te zeggen: dat is implementatieafhankelijk. Natuurlijk kan een unsigned int een hogere waarde bevatten dan een signed int, maar dat is omdat het bereik anders gebruikt wordt.

quote:
Verder had ik nog een vraag: met betreft het eruit filteren van tekst in plaats van getallen heb ik geprobeerd een beroep te doen op de isnan() functie
Niet gebruiken. Dit is een twijfelachtige functie (of soms erger: macro) die niet in de standaard zit. Misschien werkt 'ie wel, misschien werkt 'ie anders dan je verwacht, misschien is 'ie niet aanwezig. Je kan input controleren met de evaluatie waar we het over gehad hebben, en een divide-by-zero (die 'inf' op zou moeten leveren ipv. 'nan') moet je zelf afvangen door te controleren of de noemer nul is.
Dale.maandag 31 januari 2011 @ 19:20
quote:
1s.gif Op maandag 31 januari 2011 07:05 schreef Jeroentk het volgende:

[ code verwijderd ]

Hoe kan ik hem wel werkende krijgen?
Google is je vriend...

http://en.wikipedia.org/wiki/Math.h
Zoals blijkt bestaat de functie 'isnan' helemaal niet... enkel 'nan' bestaat.

Verder zou ik eens kijken naar:
http://en.wikibooks.org/wiki/Subject:C_programming_language

en
http://en.wikibooks.org/wiki/Subject:C%2B%2B_programming_language
netolkmaandag 31 januari 2011 @ 21:17
quote:
1s.gif Op maandag 31 januari 2011 07:05 schreef Jeroentk het volgende:

Verder had ik nog een vraag: met betreft het eruit filteren van tekst in plaats van getallen heb ik geprobeerd een beroep te doen op de isnan() functie. Ik had gehoord dat die in de <math.h> stond, maar wanneer ik dit heb zegt hij nog steeds dat isnan een undefined identifier is..
Je kan beter std::isalpha gebruiken om te kijken of het een teken is deze functie staat gedeclareerd in de <cctype> header
Jeroentkwoensdag 2 februari 2011 @ 17:00
Hoe kan ik ervoor zorgen dat wanneer de gebruiker een verkeerd/geen getal invoert, hij automatisch "Voer een getal tussen x en x in" schrijft en dan opnieuw vraagt om een getal, zonder zichzelf aan te roepen? (bij een functie)
GS42woensdag 2 februari 2011 @ 17:33
Iets als het volgende is mogelijk:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int input;
for (;;) {
    std::cout << "Voer een getal tussen -10 en 10 in: ";
    if ( (std::cin >> input) ) {
        if (input >= -10 && input <= 10)
            break;
    }
    else {
        std::cin.clear(); // clear error state
        char dump[255];
        std::cin.getline(dump, 255); // Discard cin buffer
    }
}
std::cout << "Het getal is " << input << ".\n";

De truc is dat als lezen uit std::cin faalt, er een error flag in het object wordt geset, en je deze dus eerst moet resetten en de tekens (die blijkbaar geen cijfers zijn) uit moet lezen. Met cin.clear() reset je alle error flags en met een cin.getline() (bijvoorbeeld, er zijn andere mogelijkheden) kan je willekeurige tekens uitlezen en weggooien.

Alleen als je de juiste invoer hebt, laat je de gebruiker uit de loop komen.
Jeroentkwoensdag 2 februari 2011 @ 18:48
Oke, bedankt, ik begrijp het. Wel vraag ik me nu af hoe je gewoon een x aantal characters kunt aflezen en weggooien en dat je dus niet afhankelijk bent van of de gebruiker meer of minder dan 255 karakters intypt.. Doe je dit door 'dump' dynamisch te maken?
GS42donderdag 3 februari 2011 @ 10:58
quote:
Wel vraag ik me nu af hoe je gewoon een x aantal characters kunt aflezen en weggooien en dat je dus niet afhankelijk bent van of de gebruiker meer of minder dan 255 karakters intypt.
Op deze manier lees je maximaal 255 characters uit de istream. Als je maximaal x characters wilt, kan je dat doen met char dump[x]. Als je x wilt laten bepalen door de gebruiker, dan kan je inderdaad dynamisch alloceren of x/n keer n chars uitlezen en deze in een string opslaan.

Wat je je echter moet realiseren, is dat je niet weet hoeveel characters er in een istream buffer staan en je dus niet van tevoren dynamisch kunt alloceren op basis daarvan. Daarnaast wordt input alleen naar std::cin gestuurd na een enter, dus je kunt geen individuele characters uitlezen op het moment dat ze getypt worden (normaal gesproken dan; er zijn os-specifieke oplossingen die het wel kunnen, zoals curses).

Voor het negeren van een deel van het buffer bestaat ook nog istream::ignore, misschien dat je daar wat aan hebt. Deze kan je een te negeren lengte meegeven en een stop-byte.
nightsleeperzaterdag 5 februari 2011 @ 19:35
Hoe kan ik het beste omgaan met namespaces? Stel ik heb twee namespaces, en ik wil in de ene namespace iets van de andere namespace pakken, dan kan ik :: voor de naam zetten, het werkt echter ook zonder.

Ik zie eigenlijk nooit code waar bijvoorbeeld dingen uit de std namespace zo benadert worden, met andere namespaces zie ik dat weer wel.
ralfiezaterdag 5 februari 2011 @ 20:22
quote:
5s.gif Op zaterdag 5 februari 2011 19:35 schreef nightsleeper het volgende:
Hoe kan ik het beste omgaan met namespaces? Stel ik heb twee namespaces, en ik wil in de ene namespace iets van de andere namespace pakken, dan kan ik :: voor de naam zetten, het werkt echter ook zonder.

Ik zie eigenlijk nooit code waar bijvoorbeeld dingen uit de std namespace zo benadert worden, met andere namespaces zie ik dat weer wel.
Wat is je vraag precies?
GS42zaterdag 5 februari 2011 @ 21:44
quote:
Hoe kan ik het beste omgaan met namespaces? Stel ik heb twee namespaces, en ik wil in de ene namespace iets van de andere namespace pakken, dan kan ik :: voor de naam zetten, het werkt echter ook zonder.
Je kunt niet zomaar iets uit een namespace pakken zonder óf de scope resolution operator (::) te gebruiken óf een using-directive (using namespace std) te op te geven. Je kunt dus niet zomaar vanuit de ene namespace iets uit een andere gebruiken.

Wél kun je in een namespace dingen gebruiken die in de global scope gedefinieerd zijn:

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <cmath>

namespace X {
    double y = cos(0);
};

int main() {
    std::cout << X::y << '\n';
}

Je ziet hier dat in de namespace X de globale functie cos() aangeroepen kan worden. Dit kan op deze manier, of met ::cos() omdat de lege scope resultion operator verwijst naar de globale namespace. Als je echter een conflicterende functie in je namespace hebt, kan de :: nodig zijn voor de juiste aanroep:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <cmath>

namespace X {
    double cos(double in) { return 42; };

    double y = cos(0);
    double z = ::cos(0);
};

int main() {
    std::cout << X::y << ", " << X::z << '\n';
}

Hier krijg je de uitvoer: 42, 1
Soms gebeurt het dat je in je namespace een conflict hebt met een globale functie, waardoor je de scope resolution nodig hebt. Ik hoop dat dit je vraag beantwoordt; zoniet zal je deze moeten verduidelijken.

[ Bericht 0% gewijzigd door GS42 op 05-02-2011 21:52:56 ]
nightsleeperzondag 6 februari 2011 @ 09:22
quote:
5s.gif Op zaterdag 5 februari 2011 20:22 schreef ralfie het volgende:

[..]

Wat is je vraag precies?
Stel, ik heb namespace a en namespace b. In namespace a wil ik de variabele blabla van namespace b gebruiken, dan kan ik ::b::blabla doen, maar b::blabla werkt ook.

Ik zie mensen vanuit namespaces ook nooit ::std::iets doen, maar bij andere namespaces wordt dat weer wel gedaan.
GS42zondag 6 februari 2011 @ 10:19
quote:
Ik zie mensen vanuit namespaces ook nooit ::std::iets doen, maar bij andere namespaces wordt dat weer wel gedaan.
Gegeven wat ik hierboven schrijf, kan dat - denk ik - twee redenen hebben. Ten eerste is het gebruik van de lege scope resolution operator alleen in geval van ambiguiteit noodzakelijk, en niemand zal zelf een namespace std maken. Daarnaast wordt de lege operator ook wel gebruikt om duidelijk aan te geven dat iets uit de globale namespace komt, dus niet omdat het programmeertechnisch nodig is maar om te verduidelijken waar een object vandaan komt. Dit is niet nodig bij de std-namespace omdat iedereen weet waat deze zich bevindt.
netolkdonderdag 3 maart 2011 @ 16:28
is hier iemand bekent met sockets??? ik snap niet goed hoe ik een server meerdere connecties kan laten hebben. Ik heb deze tut gevonden maar die heeft dus geen meerdere connecties. Iemand enig idee hoe ik dit zou kunnen maken?
thabitdonderdag 3 maart 2011 @ 18:31
Je zou met threads kunnen werken, maar dat is in C++ een crime.
HenryHilldonderdag 3 maart 2011 @ 20:24
quote:
1s.gif Op donderdag 3 maart 2011 18:31 schreef thabit het volgende:
Je zou met threads kunnen werken, maar dat is in C++ een crime.
De taal C(++) biedt zelf geen threading functionaliteit, maar Win32 biedt hier bijvoorbeeld wel een API voor. En inderdaad, vergeleken met bijv. .NET is Win32 threading niet grappig.

Zie bijvoorbeeld hier en hier voor uitleg.
netolkdonderdag 3 maart 2011 @ 22:32
hmm, ja threads... is dat de enige (handige) oplossing?
thabitdonderdag 3 maart 2011 @ 22:36
Interrupts kan ook nog (denk ik).
netolkvrijdag 4 maart 2011 @ 01:11
hmm, oke ik had gehoopt dat het wat makkelijker was...

maar het komt er dus op neer dat een nieuwe aanvraag word doorverwezen naar een nieuwe threat en een andere poort?
GS42vrijdag 4 maart 2011 @ 09:40
quote:
1s.gif Op donderdag 3 maart 2011 16:28 schreef netolk het volgende:
is hier iemand bekent met sockets??? ik snap niet goed hoe ik een server meerdere connecties kan laten hebben. [...] Iemand enig idee hoe ik dit zou kunnen maken?
Het is mogelijk om het niet multi-threaded te doen maar alles gewoon in 1 thread af te handelen. Hiertoe zet je alle sockets op non-blocking en sla je alle connecties op in een std::vector<Client>.

Algemene aanpak: eerst loop je door alle clients heen en lees je alle gestuurde gegevens. En hierna kijk je of er toevallig nieuwe clients zijn die een connectie willen.

Alle clients afhandelen kan het beste door gebruik te maken van een fd_set i.c.m een select() aanroep. Hiermee kan je in 1 keer controleren of er clients zijn die data hebben gestuurd en áls die er zijn, welke clients data hebben gestuurd. Hierdoor hoef je niet elke client met een timeout uit te lezen. Als er data is, loop je alle clients langs en controleer je via de df_set of een client data heeft gestuurd. Als dat zo is, kan je gewoon read()'en.

Nieuwe clients accepteren gaat zoals je gewend bent met accept(); omdat deze op non-blocking staat faalt deze direct (met EAGAIN) als er geen clients zijn, waardoor je direct door kan gaan. Als er wel een client is, accepteer je deze, zet je de verbinding op non-blocking en voeg je de client toe aan je vector.

Als je op fd_set zoekt, vind je vast wel voorbeelden.
Trollface.vrijdag 4 maart 2011 @ 11:11
Ik kan niet wachten op C++0x, dan heeft het eindelijk native threads.

Ik zou trouwens boost::thread gebruiken, veel makkelijker ook.
thabitvrijdag 4 maart 2011 @ 11:18
Tja, je weet hopelijk waar "0x" voor staat?
netolkmaandag 7 maart 2011 @ 21:16
quote:
1s.gif Op vrijdag 4 maart 2011 09:40 schreef GS42 het volgende:

[..]

Het is mogelijk om het niet multi-threaded te doen maar alles gewoon in 1 thread af te handelen. Hiertoe zet je alle sockets op non-blocking en sla je alle connecties op in een std::vector<Client>.

Algemene aanpak: eerst loop je door alle clients heen en lees je alle gestuurde gegevens. En hierna kijk je of er toevallig nieuwe clients zijn die een connectie willen.

Alle clients afhandelen kan het beste door gebruik te maken van een fd_set i.c.m een select() aanroep. Hiermee kan je in 1 keer controleren of er clients zijn die data hebben gestuurd en áls die er zijn, welke clients data hebben gestuurd. Hierdoor hoef je niet elke client met een timeout uit te lezen. Als er data is, loop je alle clients langs en controleer je via de df_set of een client data heeft gestuurd. Als dat zo is, kan je gewoon read()'en.

Nieuwe clients accepteren gaat zoals je gewend bent met accept(); omdat deze op non-blocking staat faalt deze direct (met EAGAIN) als er geen clients zijn, waardoor je direct door kan gaan. Als er wel een client is, accepteer je deze, zet je de verbinding op non-blocking en voeg je de client toe aan je vector.

Als je op fd_set zoekt, vind je vast wel voorbeelden.
kijk dit klinkt beter :)
netolkdinsdag 8 maart 2011 @ 16:58
ik ben nu een beetje aan het klooien met threads, die kunnen zeker niet cross-platform geschreven worden?

ik heb nu dit simpele progje gemaakt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <windows.h>

unsigned long WINAPI Threader(void *Data){
    int i = 0;
    while(true){
        std::cout << "Threader:\t" << i++ << '\n';
        Sleep(500);
    }
}
int main(){
    std::cout << "Start of program\n";
    
    HANDLE Thread = CreateThread(0,0,Threader,0,0,0);
    Sleep(5000);
    std::cout << "Main:\tMiddel in the run\n";
    getchar();
    CloseHandle(Thread);
    return 0;
}

Ik vroeg me af wat WINAPI doet, als ik het weg laat dan kan ie Dword (*)(void*) niet converteren naar Dword (*)(void*)... weet iemand wat het precies doet?
thabitdinsdag 8 maart 2011 @ 18:09
quote:
1s.gif Op dinsdag 8 maart 2011 16:58 schreef netolk het volgende:
ik ben nu een beetje aan het klooien met threads, die kunnen zeker niet cross-platform geschreven worden?

ik heb nu dit simpele progje gemaakt

[ code verwijderd ]

Ik vroeg me af wat WINAPI doet, als ik het weg laat dan kan ie Dword (*)(void*) niet converteren naar Dword (*)(void*)... weet iemand wat het precies doet?
WINAPI vertelt de compiler hoe de functie argumenten krijgt en returnt en hoe de functie gelinkt moet worden en dergelijke, voor systeemfuncties zoals threads is dat anders dan hoe het standaard in C++ functioneert.
HenryHilldinsdag 8 maart 2011 @ 20:07
quote:
1s.gif Op dinsdag 8 maart 2011 16:58 schreef netolk het volgende:
Ik vroeg me af wat WINAPI doet, als ik het weg laat dan kan ie Dword (*)(void*) niet converteren naar Dword (*)(void*)... weet iemand wat het precies doet?
In grote lijnen - wat thabit zegt.

Hier stelt iemand precies dezelfde vraag, en die krijgt het volgende antwoord
"Someone has defined the WINAPI word in WinDef.h file like this: #define WINAPI __stdcall; you can find this file and definition on your computer. Therefore, WINAPI means just __stdcall, and now you have to look for this word in documentation. It provides certain features to your MyThreadFunction function, like: the function will clean the stack of arguments, and the arguments will be passed from right to left."

De verschillende calling conventions worden hier uitgelegd; de twee die in dit geval van belang zijn, zijn "cdecl" (de standaard C(++) conventie), en "stdcall" (de conventie die door de Windows API wordt gehanteerd).
Zoals je kunt lezen wordt bij "cdecl" verwacht dat de stack* opgeruimd wordt door de code die de functie aanroept, terwijl "stdcall" functies zelf de stack opruimen voordat ze retourneren. Je kunt je voorstellen dat je duidelijk moet afspreken welke conventie je aanhoudt, anders wordt de stack twee keer (of juist nooit) opgeruimd en heb je een groot probleem.

* De stack is een stuk geheugen dat zich letterlijk gedraagd als een stapel: je kunt er waardes bovenop stapelen en waardes van de bovenkant afhalen, maar niet ertussenuit. Een stack wordt voornamelijk gebruikt om, vlak voor een functieaanroep het returnadres (=de volgende opdracht na het uitvoeren van die functie) op te zetten, zodat de processor weet waar 'ie verder moet gaan als hij een return statement tegenkomt.
Echter, omdat een processor slechts een beperkt aantal registers (="variabelen") heeft, wordt de stack ook gebruikt om functie parameters op te zetten die dan door de functie zelf weer uitgelezen worden. In wezen worden dus returnadressen en functie parameters door elkaar heen op de stack opgeslagen - en dit werkt alleen zolang iedereen ervoor zorgt dat de stack altijd precies genoeg wordt opgeruimd.

Vandaar dat de compiler je een stdcall functie echt niet laat herdefineren als een cdecl functie. ;)
netolkdinsdag 8 maart 2011 @ 21:01
quote:
1s.gif Op dinsdag 8 maart 2011 20:07 schreef HenryHill het volgende:

[..]

In grote lijnen - wat thabit zegt.

Hier stelt iemand precies dezelfde vraag, en die krijgt het volgende antwoord
"Someone has defined the WINAPI word in WinDef.h file like this: #define WINAPI __stdcall; you can find this file and definition on your computer. Therefore, WINAPI means just __stdcall, and now you have to look for this word in documentation. It provides certain features to your MyThreadFunction function, like: the function will clean the stack of arguments, and the arguments will be passed from right to left."

De verschillende calling conventions worden hier uitgelegd; de twee die in dit geval van belang zijn, zijn "cdecl" (de standaard C(++) conventie), en "stdcall" (de conventie die door de Windows API wordt gehanteerd).
Zoals je kunt lezen wordt bij "cdecl" verwacht dat de stack* opgeruimd wordt door de code die de functie aanroept, terwijl "stdcall" functies zelf de stack opruimen voordat ze retourneren. Je kunt je voorstellen dat je duidelijk moet afspreken welke conventie je aanhoudt, anders wordt de stack twee keer (of juist nooit) opgeruimd en heb je een groot probleem.

* De stack is een stuk geheugen dat zich letterlijk gedraagd als een stapel: je kunt er waardes bovenop stapelen en waardes van de bovenkant afhalen, maar niet ertussenuit. Een stack wordt voornamelijk gebruikt om, vlak voor een functieaanroep het returnadres (=de volgende opdracht na het uitvoeren van die functie) op te zetten, zodat de processor weet waar 'ie verder moet gaan als hij een return statement tegenkomt.
Echter, omdat een processor slechts een beperkt aantal registers (="variabelen") heeft, wordt de stack ook gebruikt om functie parameters op te zetten die dan door de functie zelf weer uitgelezen worden. In wezen worden dus returnadressen en functie parameters door elkaar heen op de stack opgeslagen - en dit werkt alleen zolang iedereen ervoor zorgt dat de stack altijd precies genoeg wordt opgeruimd.

Vandaar dat de compiler je een stdcall functie echt niet laat herdefineren als een cdecl functie. ;)
ahh, ik snap :)
netolkdonderdag 10 maart 2011 @ 16:28
EDIT, al opgelost
netolkdonderdag 10 maart 2011 @ 18:01
vraagje hoe kan je parameters meegeven bij het creëren van treads?

ik heb dit stukje code (ik weet dat het niet werkt)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
unsigned long WINAPI Threader(void *Data){
    std::cout << "Threader\n";
    SOCKET Client = *(SOCKET*)(&Data);
    char Buffer[2] = {'1','2'};
    if((send(Client,Buffer,2,0)) == SOCKET_ERROR)
        throw Error("Socket error while sending!");
    
    if(Client != INVALID_SOCKET)
        closesocket(Client);
}

int main(){
     SOCKET hClient;

     // socket code
     HANDLE Thread = CreateThread(0,0,Threader,0,0,0);
     Sleep(5000);
     CloseHandle(Thread);
}
ik zou hClient nu graag willen mee geven aan de nieuwe thread zodat ik voor elke connectie een nieuwe thread heb...

ow enne de HANDLE moet open blijven tot de thread klaar is toch?
thabitdonderdag 10 maart 2011 @ 18:09
De parameters geef je als pointer door in het vierde argument van CreateThread.
netolkdonderdag 10 maart 2011 @ 19:16
hmm, dan werkt mn code niet zoals ik zou verwachten...

ik heb nu dus
1HANDLE Thread = CreateThread(0,0,Threader,&hClient,0,0);

en
1
2
3
4
5
6
7
8
9
10
11
unsigned long WINAPI Threader(void *Data){
    std::cout << "Threader\n";
    
    SOCKET Client = *(SOCKET*)(&Data);
    char Buffer[2] = {'1','2'};
    if((send(Client,Buffer,2,0)) == SOCKET_ERROR)
        throw Error("Socket error while sending!");
    
    if(Client != INVALID_SOCKET)
        closesocket(Client);
}

ik blijf echter nog steeds een error krijgen bij het versturen van data
thabitdonderdag 10 maart 2011 @ 19:26
Misschien moet je in de main() je SOCKET behalve declareren ook initialiseren.
netolkdonderdag 10 maart 2011 @ 20:01
1
2
3
4
5
6
7
SOCKET hClient = INVALID_SOCKET;
        sockaddr_in ClientSockAddr = {0};
        int ClientSockSize = sizeof(ClientSockAddr);
        hClient = accept(hSocket,reinterpret_cast<sockaddr*>(&ClientSockAddr),&ClientSockSize);
        if(hClient == INVALID_SOCKET)
            throw Error("Accept function failed!");
        HANDLE Thread = CreateThread(0,0,Threader,&hClient,0,0);
dit is wat ik nu heb dus hij word geďnitialiseerd
GS42donderdag 10 maart 2011 @ 22:17
Het volgende is ook een erg rare cast:

1SOCKET Client = *(SOCKET*)(&Data);

Data is al een pointer. &Data levert dus het adres van een pointer. Dit cast je naar een Socket-pointer. En die dereference je. De compiler denkt nu dus dat het een Socket is, terwijl je eigenlijk een Socket-pointer hebt.

Probeer het volgende eens:

1SOCKET Client = *reinterpret_cast<SOCKET *>(Data);

En let op dat de hClient nog steeds op de stack in main() staat: als hij hier uit scope raakt of overschreven wordt, dan ben je je gegevens kwijt en crasht de boel (dus beter advies is dynamisch alloceren).
netolkdonderdag 10 maart 2011 @ 22:27
quote:
1s.gif Op donderdag 10 maart 2011 22:17 schreef GS42 het volgende:
Het volgende is ook een erg rare cast:
[ code verwijderd ]

Data is al een pointer. &Data levert dus het adres van een pointer. Dit cast je naar een Socket-pointer. En die dereference je. De compiler denkt nu dus dat het een Socket is, terwijl je eigenlijk een Socket-pointer hebt.

Probeer het volgende eens:
[ code verwijderd ]

En let op dat de hClient nog steeds op de stack in main() staat: als hij hier uit scope raakt of overschreven wordt, dan ben je je gegevens kwijt en crasht de boel (dus beter advies is dynamisch alloceren).
hmm, wat ik dus probeerde was met die cast er voor zorgen dat de compiler idd denkt dat het een socket is en die vervolgens kopieert naar de socket in the nieuwe thread
GS42donderdag 10 maart 2011 @ 22:36
quote:
hmm, wat ik dus probeerde was met die cast er voor zorgen dat de compiler idd denkt dat het een socket is en die vervolgens kopieert naar de socket in the nieuwe thread
Tsja, maar als de compiler denkt een Socket te hebben terwijl het eigenlijk het adres van een Socket is, kunnen er natuurlijk geen goede dingen gebeuren.

Sowieso is een nieuw kopie maken in Threader() onveilig, omdat er geen garantie is dat het object nog bestaat ten tijde van kopieren (tenzij jij die garantie als programmeur geeft d.m.v mutex locks of iets dergelijks).
netolkdonderdag 10 maart 2011 @ 22:46
quote:
1s.gif Op donderdag 10 maart 2011 22:36 schreef GS42 het volgende:

[..]

Tsja, maar als de compiler denkt een Socket te hebben terwijl het eigenlijk het adres van een Socket is, kunnen er natuurlijk geen goede dingen gebeuren.

Sowieso is een nieuw kopie maken in Threader() onveilig, omdat er geen garantie is dat het object nog bestaat ten tijde van kopieren (tenzij jij die garantie als programmeur geeft d.m.v mutex locks of iets dergelijks).
ja das waar miss is het beter om dan de sockets in een array oid. te stoppen dynamisch geheugen alloceren zodat de treads er gebruik van kunnen maken
netolkvrijdag 11 maart 2011 @ 18:35
1
2
3
4
5
6
7
8
SOCKET *Clients[number];

// code

for(int i = 0; i < number; i++){
   delete [] Clients[i];
   Clients[i]=0;
}

kan bij die delete de brakkets ("[]") weggelaten worden?
GS42zondag 13 maart 2011 @ 09:20
quote:
1s.gif Op vrijdag 11 maart 2011 18:35 schreef netolk het volgende:

kan bij die delete de brakkets ("[]") weggelaten worden?
Het moet zelfs, want je delete geen gealloceerde array van Sockets, maar één enkele. In het algemeen geldt: alleen met delete[] verwijderen als je met new[] gealloceerd hebt.

Je bovenstaande code is gevaarlijk omdat het gedrag ongedefinieerd is: per implementatie kan het resultaat verschillen (en waarschijnlijk segfaulten).
netolkzondag 13 maart 2011 @ 11:44
quote:
1s.gif Op zondag 13 maart 2011 09:20 schreef GS42 het volgende:

[..]

Het moet zelfs, want je delete geen gealloceerde array van Sockets, maar één enkele. In het algemeen geldt: alleen met delete[] verwijderen als je met new[] gealloceerd hebt.

Je bovenstaande code is gevaarlijk omdat het gedrag ongedefinieerd is: per implementatie kan het resultaat verschillen (en waarschijnlijk segfaulten).
oke, ik snap die brakkets nu maar waarom waarom is het gedrag ongedefinieerd dan?
GS42zondag 13 maart 2011 @ 12:14
quote:
1s.gif Op zondag 13 maart 2011 11:44 schreef netolk het volgende:

oke, ik snap die brakkets nu maar waarom waarom is het gedrag ongedefinieerd dan?
TL;DR versie: Omdat C++ niet beschrijft hoe deze situatie afgehandeld moet worden.

Lange versie: De programmeertaal 'C++' wordt ontwikkeld door een groep mensen die precies omschrijft wat C++ moet kunnen en doen. Deze groep maakt echter geen compilers, maar alleen een beschrijving van de taal. Compilerbouwers (zoals Microsoft, GCC, Borland etc.) gebruiken deze beschrijving en moeten deze precies volgen als ze een C++-compiler willen maken.

Niet alles staat echter in beschrijving van de taal (ook wel 'standaard' genoemd). Bijvoorbeeld het onderstaande stukje beschrijft de de memberfunctie sum() van de std::valarray class:

quote:
T sum () const ;
This function may only be instantiated for a type T to which operator+= can be applied. This function returns the sum of all the elements of the array.
If the array has length 0, the behavior is undefined. If the array has length 1, sum() returns the value of element 0. Otherwise, the returned value is calculated by applying operator+= to a copy of an element of the array and all other elements of the array in an unspecied order.
Hierin staat dus precies wat std::valarray::sum() moet doen. Het interessante stuk is dikgedrukt. Omdat niet is gedefinieerd wat de functie moet doen als lengte = 0, kan dit verschillen per compilerbouwer. Ze kunnen er bijvoorbeeld voor kiezen te segfaulten, een exception te gooien of gewoon '0' terug te geven als resultaat. Het punt is: ze kunnen kiezen.

Als je dus goede C++ code wilt schrijven, moet je zorgen dat je nooit sum() gebruikt van een leeg std::valarray object: je weet immers niet wat er gaat gebeuren. Je kunt wel testen wat er met jouw compiler gebeurt, maar je weet dan nog niet (a) of dit met iets andere code ook zo zal zijn, (b) of dit in een andere versie van jouw compiler (ouder/nieuwer) ook zo zal zijn en al helemaal niet of (c) dit met een andere compiler ook werkt.

Het resultaat van delete[] op een gewone pointer is ook zoiets: het effect van die operatie staat niet in de standaard, dus moet je er niet vanuit gaan dat het werkt. Dat wordt bedoeld met 'ongedefinieerd gedrag': het resultaat van een operatie die niet in de standaard staat en dus per implementatie kan verschillen.

[ Bericht 0% gewijzigd door GS42 op 13-03-2011 12:21:25 ]
netolkzondag 13 maart 2011 @ 19:42
oke, dus dat was het ongedefinieerde deel :P, dus zonder [] is het wel correcte taal dus :)
Me_Wesleymaandag 14 maart 2011 @ 22:45
Niet specifiek C++ deze vraag, maar is het mogelijk de handle van een control te krijgen (bv een textbox) in flash?

Aangezien ze voor zover ik kan zien geen eigen hWnd hebben.
netolkdinsdag 15 maart 2011 @ 16:11
het moet mogelijk zijn aangezien Windows ook het een en ander moet weten over de textbox oid.
zoals grootte, locatie ect.

ik zou het alleen niet weten hoe je dit kan vinden er zijn denk ik wel tooltjes voor die dat voor je kunnen vinden
Dale.woensdag 16 maart 2011 @ 00:04
Ok weet niet of iemand me kan helpen maar ik waag maar de gok :P

Ik wil graag libHaru, een opensource pdf library, compilen naar een dll. Op de wiki documentatie zeggen ze dat je het volgende moet doen voor windows:

- unzip libharu-X.X.X.zip
- cd libharu-X.X.X
- Microsoft VC++ Compiler: nmake -f script/Makefile.msvc_dll demo

Nu heb ik dat gedaan alleen krijg ik steeds een error:

quote:
Microsoft (R) Program Maintenance Utility Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.

cl -Fosrc\hpdf_streams.obj /MD -nologo -O2 -Iinclude -Iwin32\include -
I"../../libpng"\include -I"../../zlib"\include -DHPDF_DLL_MAKE -c src\hpdf_strea
ms.c
hpdf_streams.c
src\hpdf_streams.c(28) : fatal error C1083: Cannot open include file: 'zlib.h':
No such file or directory
NMAKE : fatal error U1077: '"C:\Program Files\Microsoft Visual Studio 10.0\VC\BI
N\cl.EXE"' : return code '0x2'
Stop.
Blijkbaar kan hij een header zlib niet vinden. Ik geloof dat deze bij de zlib hoort, http://zlib.net/. Alleen lees ik nergens in de documentatie dat je die ook moet hebben. Ook lijkt het als of je http://www.libpng.org/pub/png/ nodig hebt... ook hier lees ik niets van in de documentatie...

Iemand enig idee hoe ik dit oplos? Ben niet echt bekend met het compilen van dll's en makefiles.

De code is hier te downloaden, niet van http://libharu.org/ zelf want dan mis je een aantal dirs.

De makefile
SPOILER
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# makefile for Haru Free PDFLibrary II (Libharu)
# Copyright (C) 1999-2006 Takeshi Kanno
# For conditions of distribution and use, see copyright notice in hpdf.h
#
# To compile, type:
#   .\configure; make
# If you wish to build zlib as a shared library, use: ./configure -s
# To install /usr/local/lib/libhpdf.* and /usr/local/include/hpdf.h, type:
#    make install
# To install in $HOME instead of /usr/local, use:
#    make install prefix=$HOME

!IFNDEF PNG_PREFIX
PNG_PREFIX   = ../../libpng
!ENDIF

!IFNDEF ZLIB_PREFIX
ZLIB_PREFIX   = ../../zlib
!ENDIF

RC=rc
CC=cl
PREFIX=/usr/local

LIBNAME=libhpdf.lib
SONAME=libhpdf.dll
SOVER1=.1
SOVER2=.0.0
LIBTARGET=libhpdf.dll
CFLAGS=/MD -nologo -O2 -Iinclude -Iwin32\include   -I"$(PNG_PREFIX)"\include -I"$(ZLIB_PREFIX)"\include -DHPDF_DLL_MAKE
CFLAGS_DEMO=/MD -nologo -O2 -Iinclude -Iwin32\include -D__WIN32__ -DHPDF_DLL
CFLAGS_EXE=-Fe
LDFLAGS= /LIBPATH:$(PNG_PREFIX)\lib /LIBPATH:$(ZLIB_PREFIX)\lib /LIBPATH:win32\msvc libpng13.lib zlib.lib
LDFLAGS_DEMO1=
LDFLAGS_DEMO2=/link /LIBPATH:. /LIBPATH:win32\msvc libhpdf.lib
DEFNAME=win32/msvc/libhpdf.def
RESNAME=win32/msvc/libhpdf.res

OBJS = \
    src\hpdf_utils.obj \
    src\hpdf_error.obj \
    src\hpdf_mmgr.obj \
    src\hpdf_list.obj \
    src\hpdf_streams.obj \
    src\hpdf_objects.obj \
    src\hpdf_null.obj \
    src\hpdf_boolean.obj \
    src\hpdf_number.obj \
    src\hpdf_real.obj \
    src\hpdf_name.obj \
    src\hpdf_array.obj \
    src\hpdf_dict.obj \
    src\hpdf_xref.obj \
    src\hpdf_encoder.obj \
    src\hpdf_string.obj \
    src\hpdf_binary.obj \
    src\hpdf_encrypt.obj \
    src\hpdf_encryptdict.obj \
    src\hpdf_fontdef.obj \
    src\hpdf_fontdef_tt.obj \
    src\hpdf_fontdef_type1.obj \
    src\hpdf_fontdef_base14.obj \
    src\hpdf_fontdef_cid.obj \
    src\hpdf_font.obj \
    src\hpdf_font_type1.obj \
    src\hpdf_font_tt.obj \
    src\hpdf_font_cid.obj \
    src\hpdf_doc.obj \
    src\hpdf_info.obj \
    src\hpdf_catalog.obj \
    src\hpdf_page_label.obj\
    src\hpdf_gstate.obj \
    src\hpdf_pages.obj \
    src\hpdf_page_operator.obj \
    src\hpdf_destination.obj \
    src\hpdf_annotation.obj \
    src\hpdf_outline.obj \
    src\hpdf_image.obj \
    src\hpdf_encoder_jp.obj \
    src\hpdf_encoder_kr.obj \
    src\hpdf_encoder_cns.obj \
    src\hpdf_encoder_cnt.obj \
    src\hpdf_fontdef_jp.obj \
    src\hpdf_fontdef_kr.obj \
    src\hpdf_fontdef_cns.obj \
    src\hpdf_fontdef_cnt.obj \
    src\hpdf_image_png.obj \
    src\hpdf_image_ccitt.obj \
    src\hpdf_doc_png.obj \
    src\hpdf_ext_gstate.obj \
    src\hpdf_namedict.obj \
    src\hpdf_3dmeasure.obj \
    src\hpdf_exdata.obj \
    src\hpdf_u3d.obj

PROGRAMS = \
    demo\encoding_list.exe \
    demo\font_demo.exe \
    demo\text_demo.exe \
    demo\text_demo2.exe \
    demo\image_demo.exe \
    demo\jpeg_demo.exe \
    demo\jpfont_demo.exe \
    demo\line_demo.exe \
    demo\link_annotation.exe \
    demo\outline_demo.exe \
    demo\png_demo.exe \
    demo\text_annotation.exe \
    demo\ttfont_demo.exe \
    demo\character_map.exe \
    demo\grid_sheet.exe \
    demo\arc_demo.exe \
    demo\raw_image_demo.exe \
    demo\encryption.exe \
    demo\permission.exe \
    demo\slide_show_demo.exe \
    demo\ext_gstate_demo.exe \

.SUFFIXES:  .c .obj

all: $(LIBTARGET)

libhpdf.res: win32\msvc\libhpdf.rc
    $(RC) /FO win32\msvc\libhpdf.res win32\msvc\libhpdf.rc

$(LIBNAME): $(OBJS)
    if exist *.lib del *.lib
    lib -out:$@ $(OBJS)

$(SONAME): $(OBJS) libhpdf.res
    -@if exist $(SONAME) del $(SONAME)
    -@if exist $(LIBAME) del $(LIBNAME)
    link /DLL /OUT:$(SONAME) $(OBJS) $(RESNAME) $(LDFLAGS) /DEF:$(DEFNAME)
    rename libhpdf.lib $(LIBNAME)
    copy $(SONAME) demo

demo: $(LIBTARGET) $(PROGRAMS)

clean:
    if exist src\*.obj del src\*.obj
    if exist src\*.o del src\*.o
    if exist *.lib del *.lib
    if exist *.dll del *.dll
    if exist demo\*.exe del demo\*.exe
    if exist demo\*.tds del demo\*.tds
    if exist *.obj del *.obj
    if exist win32\msvc\*.res del win32\msvc\*.res

install: all installfiles

installfiles:
    echo target "install" is not supported on windows platforms.

.c.obj:
    $(CC) -Fo$@ $(CFLAGS) -c $*.c

demo\encoding_list.exe : demo\encoding_list.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\encoding_list.c  $(LDFLAGS_DEMO2)
    cd demo
    .\encoding_list.exe
    cd ..

demo\font_demo.exe : demo\font_demo.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\font_demo.c $(LDFLAGS_DEMO2)
    cd demo
    .\font_demo.exe
    cd ..

demo\text_demo.exe : demo\text_demo.c demo\grid_sheet.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\text_demo.c demo\grid_sheet.c $(LDFLAGS_DEMO2)
    cd demo
    .\text_demo.exe
    cd ..

demo\text_demo2.exe : demo\text_demo2.c demo\grid_sheet.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\text_demo2.c demo\grid_sheet.c $(LDFLAGS_DEMO2)
    cd demo
    .\text_demo2.exe
    cd ..

demo\image_demo.exe : demo\image_demo.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\image_demo.c $(LDFLAGS_DEMO2)
    cd demo
    .\image_demo.exe
    cd ..

demo\jpeg_demo.exe : demo\jpeg_demo.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\jpeg_demo.c $(LDFLAGS_DEMO2)
    cd demo
    .\jpeg_demo.exe
    cd ..

demo\jpfont_demo.exe : demo\jpfont_demo.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\jpfont_demo.c $(LDFLAGS_DEMO2)
    cd demo
    .\jpfont_demo.exe
    cd ..

demo\line_demo.exe : demo\line_demo.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\line_demo.c $(LDFLAGS_DEMO2)
    cd demo
    .\line_demo.exe
    cd ..

demo\link_annotation.exe : demo\link_annotation.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\link_annotation.c $(LDFLAGS_DEMO2)
    cd demo
    .\link_annotation.exe
    cd ..

demo\outline_demo.exe : demo\outline_demo.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\outline_demo.c $(LDFLAGS_DEMO2)
    cd demo
    .\outline_demo.exe
    cd ..

demo\png_demo.exe : demo\png_demo.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\png_demo.c $(LDFLAGS_DEMO2)
    cd demo
    .\png_demo.exe
    cd ..

demo\text_annotation.exe : demo\text_annotation.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\text_annotation.c $(LDFLAGS_DEMO2)
    cd demo
    .\text_annotation.exe
    cd ..

demo\encryption.exe : demo\encryption.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\encryption.c $(LDFLAGS_DEMO2)
    cd demo
    .\encryption.exe
    cd ..

demo\permission.exe : demo\permission.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\permission.c $(LDFLAGS_DEMO2)
    cd demo
    .\permission.exe
    cd ..

demo\ttfont_demo.exe : demo\ttfont_demo.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\ttfont_demo.c $(LDFLAGS_DEMO2)
    cd demo
    .\ttfont_demo.exe ttfont\PenguinAttack.ttf -E
    cd ..

demo\character_map.exe : demo\character_map.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\character_map.c $(LDFLAGS_DEMO2)

demo\raw_image_demo.exe : demo\raw_image_demo.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\grid_sheet.c demo\raw_image_demo.c $(LDFLAGS_DEMO2)
    cd demo
    .\raw_image_demo.exe
    cd ..

demo\arc_demo.exe : demo\arc_demo.c demo\grid_sheet.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\grid_sheet.c demo\arc_demo.c $(LDFLAGS_DEMO2)
    cd demo
    .\arc_demo.exe
    cd ..

demo\grid_sheet.exe : demo\grid_sheet.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) -DSTAND_ALONE $(LDFLAGS_DEMO1) demo\grid_sheet.c $(LDFLAGS_DEMO2)
    cd demo
    .\grid_sheet.exe
    cd ..

demo\slide_show_demo.exe : demo\slide_show_demo.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\slide_show_demo.c $(LDFLAGS_DEMO2)
    cd demo
    .\slide_show_demo.exe
    cd ..

demo\ext_gstate_demo.exe : demo\ext_gstate_demo.c $(LIBTARGET)
    $(CC) $(CFLAGS_EXE)$@ $(CFLAGS_DEMO) $(LDFLAGS_DEMO1) demo\ext_gstate_demo.c $(LDFLAGS_DEMO2)
    cd demo
    .\ext_gstate_demo.exe
    cd ..
GS42woensdag 16 maart 2011 @ 00:19
Dale, heb je geprobeerd de preprocess-flag LIBHPDF_HAVE_NOZLIB te definieren? Als ik de code in /src/hpdf_streams.c doorblader, krijg ik het idee dat er dan gecompileerd wordt zonder zlib-functionaliteit (wat dat ook in moge houden...).

Zoniet, dan lijkt het erop dat je inderdaad de zlib library nodig hebt op je systeem.
netolkdonderdag 17 maart 2011 @ 17:31
hey, ik ben bezig met een linked list dinges te maken....

ik heb de volgende code:
SPOILER
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    class Piece{
        Piece *_NEXT;
        int _DATA;
        
        public:
            Piece():_NEXT(0),_DATA(0){}
            Piece(Piece *next,int data):_NEXT(next),_DATA(data){}
            friend class LList;
    };
    
    class LList{
        Piece *_START;
        
        public:
            LList():_START(0){}
            LList(Piece start):_START(&start){}
            LList(Piece *start):_START(start){}
            ~LList();
            
            unsigned length();
            bool loop();
    
    };
en dan heb ik hier de niet gedefinieerde functies gedefinieerd:
SPOILER
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
LList::~LList(){
    Piece *temp1,*temp2;
    if(_START != 0){
        temp1 = _START;
        while(temp1 !=0){
            temp2 = temp1;
            temp1 = temp1->_NEXT;
            delete temp2;
        }
        
    }
}

unsigned LList::length(){
    unsigned i = 0;
    if(_START != 0){
         i++; // start is 1e object
         Piece *temp = _START;
        while(temp->_NEXT != 0 && temp->_NEXT != _START){
            temp = temp->_NEXT;
            i++;
        }
        temp = 0;
    }
    return i;
}
bool LList::loop(){
    if(_START !=0){
        Piece *temp = _START;
        while(temp->_NEXT != 0){
            temp = temp->_NEXT;
            if(temp == _START)
                return true;
        }
    }
    return false;
}
nu is het zo dat ik dit doe
1
2
3
4
LList myLList(mypiece);
std::cout << "List length: " << myLList.lenght() << '\n';

std::cout << "List loop?: " << myLList.loop() << '\n';

dit is mijn output:
1list lenght: 5

dan krijg ik een error dat het programma niet meer werkt...
dit duid er dus op dat m'n length() functie niet goed opgeruimd word of zo, iemand een idee wat ik niet goed doe?
thabitdonderdag 17 maart 2011 @ 18:10
Je lijkt dingen te deleten die niet met new worden aangemaakt. Dat kan natuurlijk niet goed gaan.
GS42donderdag 17 maart 2011 @ 18:33
quote:
4s.gif Op donderdag 17 maart 2011 18:10 schreef thabit het volgende:
Je lijkt dingen te deleten die niet met new worden aangemaakt. Dat kan natuurlijk niet goed gaan.
Dat is inderdaad een probleem, maar zijn fout wordt veroorzaakt door iets anders: bekijk je LList constructor LList(Piece start):_START(&start) eens goed. Wat klopt hier niet? (Hint: waar wordt 'Piece start' geinitialiseerd en wanneer wordt deze vernietigd?)
netolkdonderdag 17 maart 2011 @ 18:55
quote:
1s.gif Op donderdag 17 maart 2011 18:33 schreef GS42 het volgende:

[..]

Dat is inderdaad een probleem, maar zijn fout wordt veroorzaakt door iets anders: bekijk je LList constructor LList(Piece start):_START(&start) eens goed. Wat klopt hier niet? (Hint: waar wordt 'Piece start' geinitialiseerd en wanneer wordt deze vernietigd?)
umm, hij word geďnitialiseerd bij de constructie, en weer vernietigd tijdens de destructie van LList

Ik neem aan de de _START pas vernietigd word nadat de rest van de destructor is uitgevoerd...
quote:
4s.gif Op donderdag 17 maart 2011 18:10 schreef thabit het volgende:
Je lijkt dingen te deleten die niet met new worden aangemaakt. Dat kan natuurlijk niet goed gaan.
ja, dat dacht ik dus ook al maar als ik gewoon in de main dit schrijf:
1
2
3
4
Pice myPiece;
Piece *ptr;
ptr = &myPiece;
delete ptr;
is er niks aan de hand, kan zelfs myPiece gewoon nog gebruiken, maar dit zal wel zo'n ongedefinieerd gebeuren zijn
thabitdonderdag 17 maart 2011 @ 18:58
quote:
1s.gif Op donderdag 17 maart 2011 18:55 schreef netolk het volgende:

[..]

umm, hij word geďnitialiseerd bij de constructie, en weer vernietigd tijdens de destructie van LList
Je past daar pass-by-value toe. Dat ding wordt dus meteen al vernietigd bij het verlaten van de constructor.
netolkdonderdag 17 maart 2011 @ 19:01
ow lol Xd, dat verklaard een hoop :P ik heb ze nu idd maar weer via new gemaakt en heb de error nu ook niet meer :)

ow kut die Piece start word natuurlijk weer vernietigd... lekker dom weer |:(

ik was al bang dat mn length() functie een fout bevatte die ik niet snapte

bedankt in ieder geval
netolkzaterdag 2 april 2011 @ 15:32
Hey heeft iemand een idee waarom dit niet werkt??

1
2
3
4
5
6
int ifstr_loc = read.tellg();
while(b_temp){
    read.seekg(ifstr_loc);
    std::cout << read.tellg( << '\n';
    Handle_Function(read);
}

als bool b_temp = true; dan zou dit toch een oneindige loop moeten vormen die steeds read op ifstr_loc zet en dan iets gaat doen??

ik krijg nu dat Handle_Function 1x word uitgevoerd en daarna is read.tellg() -1 nadat seekg(44) is aangeroepen, kan iemand mij misschien vertellen waarom read.tellg() -1 word?
GS42zaterdag 2 april 2011 @ 18:52
quote:
1s.gif Op zaterdag 2 april 2011 15:32 schreef netolk het volgende:
Hey heeft iemand een idee waarom dit niet werkt??
[ code verwijderd ]

als bool b_temp = true; dan zou dit toch een oneindige loop moeten vormen die steeds read op ifstr_loc zet en dan iets gaat doen??
Ja, tenzij b_temp in Handle_Function aangepast wordt. Dan hoeft de loop niet oneindig te zijn.

quote:
ik krijg nu dat Handle_Function 1x word uitgevoerd en daarna is read.tellg() -1 nadat seekg(44) is aangeroepen, kan iemand mij misschien vertellen waarom read.tellg() -1 word?
Aannemende dat 'read' een of andere istream is, dan geeft tellg() -1 terug als deze faalt. Dit betekent hoogstwaarschijnlijk dat 'read' geen vailde status meer heeft, dus dat een of andere operatie in Handle_Function gefaald is. In het algemeen lees je nooit van een istream zonder te controleren of de istream wel leesklaar is. Probeer maar eens de statusbits van de istream af te drukken (eof, fail en bad), dan zal je zien dat dat de stream zich in een foutstaat bevindt.

[ Bericht 1% gewijzigd door GS42 op 03-04-2011 15:15:35 ]
netolkzaterdag 2 april 2011 @ 20:07
quote:
1s.gif Op zaterdag 2 april 2011 18:52 schreef GS42 het volgende:

[..]

Aannemende dat 'read' een of andere istream is, dan geeft tellg() -1 terug als deze faalt. Dit betekent hoogstwaarschijnlijk dat 'read' geen vailde status meer heeft, dus dat een of andere operatie in Handle_Function gefaald is. In het algemeen lees je nooit van een istream zonder te controleren of de istream wel leesklaar is. Probeer maar eens de statusbits van de istream af te drukken (eof, fail en bad), dan zal je zien dat dat de stream zich in een foutstaat bevindt.
Het klopt dat ik de check of ie valide is idd er niet in gedaan heb nee

maar ik zet eerst de read pointer terug naar 44 en dan blijft tellg() toch -1 geven voordat de Handle_Function(read); word aangeroepen

PS. read is std::ifstream
ralfiezaterdag 2 april 2011 @ 20:21
tellg gaf al -1? Je moet de errorbits wel resetten. Weet zo uit mn hoofd niet hoe, maar is makkelijk te googlen.
netolkzaterdag 2 april 2011 @ 22:07
quote:
1s.gif Op zaterdag 2 april 2011 20:21 schreef ralfie het volgende:
tellg gaf al -1? Je moet de errorbits wel resetten. Weet zo uit mn hoofd niet hoe, maar is makkelijk te googlen.
ahh, kijk dat verklaard een hoop

EDIT:

klopt geen ene flikker van m'n code zal dat eerst eens even fixen...

bedankt in ieder geval

[ Bericht 11% gewijzigd door netolk op 02-04-2011 22:26:54 ]
netolkmaandag 4 april 2011 @ 16:19
ik weet al wat m'n probleem was, vergat te checken of de loop nog wel valide was... maar dat is nu dus gefixed en het werkt gewoon :)
netolkmaandag 4 april 2011 @ 22:48
goeden avond fokkers,

ik vraag me af of dit tot geheugen leaks lijd:

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
class Piece{
        Piece *_NEXT;
        
        std::string _TYPE;
        std::string _NAME;
        void *_DATA;
};

class LList{
        Piece *_START;
        ~LList();
};

LList::~LList(){
    Piece *temp1,*temp2;
    if(_START != 0){
        temp1 = _START;
        while(temp1 !=0){
            temp2 = temp1;
            temp1 = temp1->_NEXT;
            delete temp2;
        }
        
    }
}

word nu bij het deleten van Piece* de destructor van Piece aan geroepen? of moet ik dit regelen in de destructor van LList?
thabitmaandag 4 april 2011 @ 23:13
Bij het deleten van Piece* wordt inderdaad de destructor van Piece aangeroepen.
netolkmaandag 4 april 2011 @ 23:24
quote:
1s.gif Op maandag 4 april 2011 23:13 schreef thabit het volgende:
Bij het deleten van Piece* wordt inderdaad de destructor van Piece aangeroepen.
oke, dat is mooi...

nog een vraagje stel ik hou een int die de grootte van het object voorstelt waar void *_DATA naar verwijst, hoe kan ik *_DATA dan ombouwen zodat het object uit het geheugen geflikkerd word? of is dit niet mogelijk in C++?
thabitdinsdag 5 april 2011 @ 07:46
Je kan gewoon delete _DATA doen, de delete "weet" hoeveel ruimte het object inneemt als je het met new hebt aangemaakt.
netolkdinsdag 5 april 2011 @ 11:09
quote:
1s.gif Op dinsdag 5 april 2011 07:46 schreef thabit het volgende:
Je kan gewoon delete _DATA doen, de delete "weet" hoeveel ruimte het object inneemt als je het met new hebt aangemaakt.
um _DATA is wel een void, en als ik delete _DATA doe dan is dat dus ongedefinieerd. Ik krijg dit ook als waarschuwing als ik het wel probeer

dus ik dacht ik cast het eerst naar de gebruikte grootte en dan delete ik het op die manier

Ik weet alleen niet hoe ik dat moet doen als het object bijv. 30 byte is
thabitdinsdag 5 april 2011 @ 13:04
Dat het void is zou niks uit moeten maken, new en delete wrappen malloc en free, en die werken ook met void pointers.
thabitdinsdag 5 april 2011 @ 13:09
Maar als je het echt netjes wilt doen kun je ofwel een template maken en void vervangen door een typename binnen die template, of een base class waar je types die _DATA kunnen zijn van afleidt en dan _DATA dus als een pointer naar die base class declareren.

Het enige probleem void pointers is misschien dat er geen destructor wordt aangeroepen, dus alleen gebruiken voor pointers naar "simpele" types waar geen destructor voor nodig is.
netolkdinsdag 5 april 2011 @ 15:37
quote:
1s.gif Op dinsdag 5 april 2011 13:09 schreef thabit het volgende:
Maar als je het echt netjes wilt doen kun je ofwel een template maken en void vervangen door een typename binnen die template, of een base class waar je types die _DATA kunnen zijn van afleidt en dan _DATA dus als een pointer naar die base class declareren.

Het enige probleem void pointers is misschien dat er geen destructor wordt aangeroepen, dus alleen gebruiken voor pointers naar "simpele" types waar geen destructor voor nodig is.
Dat er evt. geen destructor word aangeroepen is geen probleem dat is nog wel op te lossen maar wat het is ik heb bijv.
1int *ptr_int = new int(8);
en dan
1_DATA = ptr_int;
dit is de enige manier hoe het kan omdat ik bezig ben met een parser en dit de variabelen moet bewaren (wat dus ook door de gebruiker gedefinieerde dingen kunnen zijn)
ralfiedinsdag 5 april 2011 @ 16:00
Ja, dat snapt ie niet, delete zal dan simpelweg ptr_int[0] deleten en de rest laten staan.
delete [] zou dat wel goed moeten doen, maar dan moet je het wel bij arrays houden.
thabitdinsdag 5 april 2011 @ 16:14
quote:
1s.gif Op dinsdag 5 april 2011 16:00 schreef ralfie het volgende:
Ja, dat snapt ie niet, delete zal dan simpelweg ptr_int[0] deleten en de rest laten staan.
delete [] zou dat wel goed moeten doen, maar dan moet je het wel bij arrays houden.
Gelukkig wordt er ook maar 1 int aangemaakt door new in zijn voorbeeld.
netolkwoensdag 6 april 2011 @ 17:35
quote:
1s.gif Op dinsdag 5 april 2011 16:14 schreef thabit het volgende:

[..]

Gelukkig wordt er ook maar 1 int aangemaakt door new in zijn voorbeeld.
goed ik zal de warningcode er wel even bij plakken dan:

1
2
LList.cpp: In destructor `Piece::~Piece()':
LList.cpp:3: warning: deleting `void*' is undefined

Het lijkt er op of de void-pointers geen grootte kunnen "onthouden"

[ Bericht 4% gewijzigd door netolk op 06-04-2011 18:00:32 ]
thabitwoensdag 6 april 2011 @ 19:16
De C++ standaard definieert geen delete van void*s, maar dat betekent niet dat de compiler het niet gedefinieerd heeft.

De code werkt op vrijwel elke compiler goed, zolang de void* naar een built-in type verwijst. Als je hem naar classes laat verwijzen, dan kunnen er dingen misgaan, bijvoorbeeld omdat er dan geen destructor wordt aangeroepen.

Het memory management onthoudt de grootte van de blokken geheugen die worden gealloceerd en weet dus hoe groot het blok geheugen is waar de pointer aan verbonden is.
thabitwoensdag 6 april 2011 @ 19:17
De laatste tig posts laten trouwens prima zien waarom gc zoveel beter is.
netolkdonderdag 7 april 2011 @ 12:09
quote:
1s.gif Op woensdag 6 april 2011 19:16 schreef thabit het volgende:
De C++ standaard definieert geen delete van void*s, maar dat betekent niet dat de compiler het niet gedefinieerd heeft.

De code werkt op vrijwel elke compiler goed, zolang de void* naar een built-in type verwijst. Als je hem naar classes laat verwijzen, dan kunnen er dingen misgaan, bijvoorbeeld omdat er dan geen destructor wordt aangeroepen.

Het memory management onthoudt de grootte van de blokken geheugen die worden gealloceerd en weet dus hoe groot het blok geheugen is waar de pointer aan verbonden is.
Ja, maar het is dus nu juist wel de bedoeling om dit oa. ook naar classes ect te laten verwijzen

dus hoe kan het dan goed opgeruimd worden?
thabitdonderdag 7 april 2011 @ 13:20
1
2
3
4
5
6
7
8
9
10
11
12
class Piece{
        Piece *_NEXT;
        
        std::string _TYPE;
        std::string _NAME;
};

template<typename T>
class TypedPiece: public Piece
{
        T *_DATA;
};

Zoiets bijvoorbeeld. Of je maakt van _DATA een base class waar je een templated class van afleidt.
netolkdonderdag 7 april 2011 @ 20:15
Ja, dat moet ik idd hebben txs...

tja de templates heb ik idd nog niet doorgewerkt maar dat zal ik eens even gaan doen dan :)

Wat je nu als voorbeeld hebt gemaakt kan je dat dan toch als onderdeel van Piece aanroepen?

1
2
3
Piece myPiece;

myPiece._DATA = ptr_int;
ralfiedonderdag 7 april 2011 @ 20:16
quote:
1s.gif Op donderdag 7 april 2011 20:15 schreef netolk het volgende:
Ja, dat moet ik idd hebben txs...

tja de templates heb ik idd nog niet doorgewerkt maar dat zal ik eens even gaan doen dan :)

Wat je nu als voorbeeld hebt gemaakt kan je dat dan toch als onderdeel van Piece aanroepen?

[ code verwijderd ]

Ja, das het voordeel van templates.
netolkdonderdag 7 april 2011 @ 20:28
nice, dan ga ik dat hoofdstuk eens even goed doornemen, dat scheelt weer een hoop cast gekut en daarmee waarschijnlijk ook een hoop fouten en geheugen leaks

bedankt voor de hulp Tabit en ralfie
thabitdonderdag 7 april 2011 @ 20:42
quote:
1s.gif Op donderdag 7 april 2011 20:15 schreef netolk het volgende:
Ja, dat moet ik idd hebben txs...

tja de templates heb ik idd nog niet doorgewerkt maar dat zal ik eens even gaan doen dan :)

Wat je nu als voorbeeld hebt gemaakt kan je dat dan toch als onderdeel van Piece aanroepen?

[ code verwijderd ]

Ik zou dit wel met accessormethodes aanpakken, niet direct van buiten de klasse in de data peuren.
netolkdonderdag 7 april 2011 @ 21:45
quote:
1s.gif Op donderdag 7 april 2011 20:42 schreef thabit het volgende:

[..]

Ik zou dit wel met accessormethodes aanpakken, niet direct van buiten de klasse in de data peuren.
Nee, dat is idd ook niet de bedoeling maar Piece is een onderdeel van mijn Linked List class en ik heb het dan zo gemaakt dat het alleen mogelijk is om data te wijzigen via de Linked List class
netolkmaandag 9 mei 2011 @ 18:06
Hey Fokkers

Ik heb een vraagje hoe kan ik aparte pixels op het scherm tekenen of kleine lijntjes??

Ik heb al wat gekeken voor openGL maar dat is niet zo heel handig om een paar lijntjes te tekenen

Iemand suggesties om dit te doen?
ralfiemaandag 9 mei 2011 @ 22:42
quote:
0s.gif Op maandag 9 mei 2011 18:06 schreef netolk het volgende:
Hey Fokkers

Ik heb een vraagje hoe kan ik aparte pixels op het scherm tekenen of kleine lijntjes??

Ik heb al wat gekeken voor openGL maar dat is niet zo heel handig om een paar lijntjes te tekenen

Iemand suggesties om dit te doen?
Je gaat al snel naar directX of openGL... Wat voor lijntjes will je tekenen? Win32 zal er misschien ook wat functies voor hebben, mits je in een formpje zit.
netolkmaandag 9 mei 2011 @ 23:52
Het liefst wil ik niet in Win32 werken... ik heb een paar tuts gevonden met openGL maar die gebruiken allemaal glut ofzo en dat is dan dus weer niet puur openGL
netolkdinsdag 10 mei 2011 @ 23:29
@ ralfie, in mijn vorige post was ik vergeten wat ik voor lijntjes wil tekenen

ik wel horizontale,verticale en diagonale (45 graden) lijnen tekenen van 1 pixel breed en 3 pixels lang. En daar wil ik er heel veel van

Moet openGL in een win32 omgeving of kan het ook draaien in console mode?
Ai_KaRaMBawoensdag 11 mei 2011 @ 10:28
openGL kan zeker niet in een console, aangezien dat text-based is. Ik neem aan dat je wel onder windows werkt? (en niet linux, freebsd, mac, whatever?)

Dan zul je toch met Win32 of Glut aan de slag moeten (glut is een laag tussen win32 en opengl in, die windowing en messaging afhandeld).

Win32 heeft een SetPixel() functie, maar die is niet echt snel. Als het snel(ler) moet, kun je een off-screen buffer alloceren, en die met SetDIBits vrij snel naar het scherm blitten.
netolkwoensdag 11 mei 2011 @ 12:25
quote:
0s.gif Op woensdag 11 mei 2011 10:28 schreef Ai_KaRaMBa het volgende:
openGL kan zeker niet in een console, aangezien dat text-based is. Ik neem aan dat je wel onder windows werkt? (en niet linux, freebsd, mac, whatever?)

Dan zul je toch met Win32 of Glut aan de slag moeten (glut is een laag tussen win32 en opengl in, die windowing en messaging afhandeld).

Win32 heeft een SetPixel() functie, maar die is niet echt snel. Als het snel(ler) moet, kun je een off-screen buffer alloceren, en die met SetDIBits vrij snel naar het scherm blitten.
Hmm... kut k vind die win32 dingen altijd zo'n gedoe om alleen al een window te krijgen...

nouja het moet dan maar en k heb ondertussen de juiste code voor een lijn in openGL gevonden dus dat is opgelost

bedankt
Catbertwoensdag 11 mei 2011 @ 12:45
OpenGL is ook voor 2D werk handig, omdat het gebruik maakt van de hardwareversnelling van je GPU. Het enige nadeel is dat het in eerste instantie wat complexer is.

Je kunt als je perse met OpenGL bezig wil ook prima met C# of Java aan de slag trouwens.
netolkwoensdag 11 mei 2011 @ 16:40
quote:
0s.gif Op woensdag 11 mei 2011 12:45 schreef Catbert het volgende:
OpenGL is ook voor 2D werk handig, omdat het gebruik maakt van de hardwareversnelling van je GPU. Het enige nadeel is dat het in eerste instantie wat complexer is.

Je kunt als je perse met OpenGL bezig wil ook prima met C# of Java aan de slag trouwens.
Ja, en dan de rest van mn programma helemaal ombouwen zeker Xd

Nee, ik maak er wel gewoon een win32 app van en dan gewoon openGL voor het tekenwerk
netolkdinsdag 7 juni 2011 @ 13:51
Hey, ik heb een vraagje is het mogelijk om in een console programma de toets-status te onderscheppen??

ik gebruik nu GetAsyncKeyState(VK_UP) programma registreert het wel maar na het afsluiten kom ik er achter dat cmd het ook nog registreert en dan dus allemaal andere commando's (die daar voor gebruikt zijn) gaat uitvoeren, weet iemand hoe ik dit kan voorkomen in een console programma?
ralfiedinsdag 7 juni 2011 @ 19:28
- knip -

verkeerd gelezen
GS42dinsdag 7 juni 2011 @ 19:59
quote:
0s.gif Op dinsdag 7 juni 2011 13:51 schreef netolk het volgende:
Hey, ik heb een vraagje is het mogelijk om in een console programma de toets-status te onderscheppen??
In principe is dit niet mogelijk met standaard C(++). Het opvangen van toetsen is namelijk os-specifiek (invoer kan immers alleen in C(++) gelezen worden nadat de terminal het naar cin stuurt).

Er zijn wel os-specifieke libraries die omgang met de terminal versoepelen, waarbij curses de grootste is in Unix-omgevingen. Ik heb curses voor iets dergelijks gebruikt, dus ik weet dat het hiermee kan. Ik lees ook net op de wiki-site dat het blijkbaar naar Windows geport is, dus wellicht dat je hier iets mee kan.
netolkwoensdag 8 juni 2011 @ 09:52
Maar, krijg ik dan niet het zelfde als GetKey() ect. wat windows zelf heeft? (en dan dus ook dat de console nog steeds doet alsof de key's voor de console bestemt waren)
Ai_KaRaMBawoensdag 8 juni 2011 @ 12:51
Waarschijnlijk zal je de input buffer moeten flushen. Ik heb echter niet direct een idee hoe je dat doet in een console applicatie...

Iets als:
1
2
while((c = getchar()) != '\n' && c != EOF)
    /* discard */ ;
wellicht?
netolkwoensdag 8 juni 2011 @ 14:01
tja, voor iets als cin oid zal het wel werken ja maar, niet als je key states wil kunnen bekijken zonder dat je programma gaat wachten op een key input
Ai_KaRaMBawoensdag 8 juni 2011 @ 17:52
Nee, ik bedoel dat je voordat je je programma exit, even de input buffer flushed met zo'n loopje
ralfiewoensdag 8 juni 2011 @ 19:39
Voor key inputs kun je gewoon een messagehandler aan je console app toevoegen. Geen idee hoe of wat dat met je "na het afsluiten kom ik er achter dat cmd het ook nog registreert en dan dus allemaal andere commando'"-probleem doet.

http://msdn.microsoft.com/en-us/library/ms686016

(werkt alleen op Ramen)

@hierboven: cin.flush() ? - Nee, wacht, schijnt niet te kunnen. cin.sync() dan of cin.ignore()?
Ai_KaRaMBadonderdag 9 juni 2011 @ 10:26
Die SetConsoleCtrlHandler functie waaraan je refereerd is voor het afvangen van system events (Ctrl-C, Uitloggen, etc), niet voor alle toetsen.

Dit voorbeeld van MSDN doet echter wel precies wat je zou willen:
http://msdn.microsoft.com/en-us/library/ms685035(v=VS.85).aspx. Die laat zien hoe je input events van de console leest (toetsen indrukken, toetsen loslaten, mouse events, etc) en afhandled. Doordat je dus key-presses en key-releases krijgt, kun je dus zelf bijhouden welke toetsen ingedrukt zijn.

Volgens mij is die ReadConsoleInput trouwens wel blocking, dus lijkt het me zinvol om dat in een apparte thread te doen.

Maar als je toch Win32 gebaseerde eventhandlers gaat schrijven, waarom maak je dan nog een console applicatie?
netolkdonderdag 9 juni 2011 @ 12:32
oe, txs Ai_KaRaMBa, dr zit ook een muis dinges bij, dat is wel handig eigenlijk :)
Ik ga daar even mee klooien
netolkzondag 12 juni 2011 @ 00:26
Het is gelukt hoor :) met de link van Ai_KaRaMBa heb ik een thread gemaakt die de key-status bekijkt dus dan heeft mijn programma gewoon draaien en kan ik de key's uitlezen wanneer ik wil
netolkzondag 24 juli 2011 @ 17:20
Ik heb een probleem met class members en 'friend' in een 'friend' functie blijft de compiler zeggen dat de member private is...

1
2
3
4
5
6
7
8
9
10
11
12
class Key{
            void *_HANDLE;
            bool _KEY_PRESSED[256];
            public:
                Key();
                ~Key() throw();
                
                // operators ed moeten nog
                bool operator[](const unsigned char &n);
                
                friend unsigned long WINAPI Threader_Key(void *Data);
        };
en de functie:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
unsigned long WINAPI Threader_Key(void *Data){
    Thread::Key *myKey = reinterpret_cast<Thread::Key*>(Data);
    
    // declaraties en error checks hier weggelaten
        
        //dispatch the events to the appropriate handler.
        for(unsigned i=0; i < cNumRead;i++){
            switch(irInBuf[i].EventType){
                case KEY_EVENT:
                    if(irInBuf[i].Event.KeyEvent.bKeyDown)
                        myKey->_KEY_PRESSED[irInBuf[i].Event.KeyEvent.wVirtualKeyCode] = true;
                    else
                        myKey->_KEY_PRESSED[irInBuf[i].Event.KeyEvent.wVirtualKeyCode] = false;
                    break;
            }
        }
    }
}

Het gaat om het deel myKey->_KEY_PRESSED[...] = true/false

Weet iemand waarom dit niet werkt? de functie draait overigens wel in een aparte thread ik weet niet of dat uit maakt, maar als ik _KEY_PRESSED 'public' maak werkt het wel...
Ai_KaRaMBamaandag 25 juli 2011 @ 15:17
lijkt mij dat je _KEY_PRESSED dan ook als 'friend' moet declareren? Zonder aanduiding is het geloof ik standaard "private", en kan dus een friend functie er niet bij
netolkmaandag 25 juli 2011 @ 16:21
quote:
0s.gif Op maandag 25 juli 2011 15:17 schreef Ai_KaRaMBa het volgende:
lijkt mij dat je _KEY_PRESSED dan ook als 'friend' moet declareren? Zonder aanduiding is het geloof ik standaard "private", en kan dus een friend functie er niet bij
als ik hem protected maak werkt het btw nog steeds niet maar een friend functie zou gewoon toegang moeten hebben tot alle members (dus ook de private) van een class toch?

Ja, maar _KEY_PRESSED is een member
1bool _KEY_PRESSED[256];
Ai_KaRaMBadinsdag 26 juli 2011 @ 10:21
Ik heb in het verleden wel eens met Java ( :r ) dergelijke problemen gehad, en daar lag het aan dat de member variabelen private waren, en dat protected fucties daar niet bij konden; ik dacht dat dit probleem iets soortgelijks zou zijn :@

Ik ben niet echt ervaren met C++, maar na wat googlen lijkt het inderdaad dat wel had moeten werken: in het eerste voorbeeld in http://www.cplusplus.com/doc/tutorial/inheritance/ doen ze precies hetzelfde als jij...

Mogelijk dat je namespace roet in 't eten gooit???
netolkdinsdag 26 juli 2011 @ 10:50
quote:
0s.gif Op dinsdag 26 juli 2011 10:21 schreef Ai_KaRaMBa het volgende:
Ik heb in het verleden wel eens met Java ( :r ) dergelijke problemen gehad, en daar lag het aan dat de member variabelen private waren, en dat protected fucties daar niet bij konden; ik dacht dat dit probleem iets soortgelijks zou zijn :@

Ik ben niet echt ervaren met C++, maar na wat googlen lijkt het inderdaad dat wel had moeten werken: in het eerste voorbeeld in http://www.cplusplus.com/doc/tutorial/inheritance/ doen ze precies hetzelfde als jij...

Mogelijk dat je namespace roet in 't eten gooit???
Nee, namespace kan het niet zijn omdat in de class staat welke functie gebruik van de private members mag maken en die functie staat niet in een namespace... Zelf denk ik meer dat het misschien te maken heeft dat de functie in een andere thread draait...
GS42dinsdag 26 juli 2011 @ 12:46
Dat de code in verschillende threads draait, zou voor de compiler geen verschil moeten maken. Ik denk dat je probleem toch door de namespaces komt. Je zei dat Threader_Key in de globale namespace staat? Forceer dat dan eens in je code door de friends declaratie zo te schrijven:

1friend unsigned long WINAPI ::Threader_Key(void *Data);

Hiertoe moet de functie wel eerst gedeclareerd zijn, geen probleem lijkt me. Ik denk dat dit de compiler-melding oplost.

Als het niet werkt, kan je altijd een access functie á la Key::setKeyPressed(unsigned char idx, bool value) inline definieren, dit zou het probleem ook oplossen en misschien zelfs netter zijn.
netolkdinsdag 26 juli 2011 @ 12:55
quote:
0s.gif Op dinsdag 26 juli 2011 12:46 schreef GS42 het volgende:
Dat de code in verschillende threads draait, zou voor de compiler geen verschil moeten maken. Ik denk dat je probleem toch door de namespaces komt. Je zei dat Threader_Key in de globale namespace staat? Forceer dat dan eens in je code door de friends declaratie zo te schrijven:
[ code verwijderd ]

Hiertoe moet de functie wel eerst gedeclareerd zijn, geen probleem lijkt me. Ik denk dat dit de compiler-melding oplost.

Als het niet werkt, kan je altijd een access functie á la Key::setKeyPressed(unsigned char idx, bool value) inline definieren, dit zou het probleem ook oplossen en misschien zelfs netter zijn.
het forceren met :: heb ik geprobeerd maar zegt ie dood leuk dat ik hem in :: moet declareren...
Wat dus niet kan omdat ie in een apart .cpp bestand staat. Maar die oplossing van jou is idd wel netter (had ik nog niet aan gedacht) dus dan pas ik dat gewoon toe en is het probleem ook opgelost.
Bedankt, jij ook Ai_KaRaMBa voor het mee denken
Ai_KaRaMBadinsdag 26 juli 2011 @ 13:21
quote:
0s.gif Op dinsdag 26 juli 2011 12:55 schreef netolk het volgende:

[..]

het forceren met :: heb ik geprobeerd maar zegt ie dood leuk dat ik hem in :: moet declareren...
Wat dus niet kan omdat ie in een apart .cpp bestand staat.
Waarom kun je 'm niet declareren omdat 'ie in een appart bestand staat?

Je kan toch prima:
1unsigned long WINAPI ::Threader_Key(void *Data);
boven de klasse-definitie (of mooier: in een header file, die je include) zetten?

Trouwens: een losse set-functie is niet altijd wenselijk (de waarden zijn niet voor niets private natuurlijk); met 'friend' functies kun je nauwkeuriger controlleren waar/hoe waarden gezet gaan worden.

Nog mooier zou zijn als je bijv. een 'handleEvent' functie ofzo als member functie aanmaakt, die een enkele key-event afhandelt. De Threader_Key functie kan die memberfunctie dan in een loop aanroepen. Zo hou je controle over je private member variable binnen de klasse, zonder de variabele voor 'algemeen gebruik' open te zetten

[ Bericht 21% gewijzigd door Ai_KaRaMBa op 26-07-2011 13:27:29 ]
netolkdinsdag 26 juli 2011 @ 22:38
quote:
0s.gif Op dinsdag 26 juli 2011 13:21 schreef Ai_KaRaMBa het volgende:

[..]

Waarom kun je 'm niet declareren omdat 'ie in een appart bestand staat?

Je kan toch prima:
[ code verwijderd ]

boven de klasse-definitie (of mooier: in een header file, die je include) zetten?

Trouwens: een losse set-functie is niet altijd wenselijk (de waarden zijn niet voor niets private natuurlijk); met 'friend' functies kun je nauwkeuriger controlleren waar/hoe waarden gezet gaan worden.

Nog mooier zou zijn als je bijv. een 'handleEvent' functie ofzo als member functie aanmaakt, die een enkele key-event afhandelt. De Threader_Key functie kan die memberfunctie dan in een loop aanroepen. Zo hou je controle over je private member variable binnen de klasse, zonder de variabele voor 'algemeen gebruik' open te zetten
Ik had nu idd ook al bedacht dat dit niet ging werken nee :( omdat ik de member dan netzo goed public kan maken, ik dacht dus dat ie boven mn class al ergens gedeclareerd stond (snapte de fout-code ook al niet helemaal maar had geen zin om te zoeken) en de oplossing leek heel aardig totdat ik bedacht dat je die dan altijd kan aanroepen...
FastFox91vrijdag 21 oktober 2011 @ 21:51
Wat is het verschil tussen type variable_naam en type variable_naam = new type?
Bv struct hoi; en struct hoi = new struct;
RealBizkit666vrijdag 21 oktober 2011 @ 21:53
Bij de tweede alloceer je meteen geheugen. Bij de eerst niet. :)

Daarnaast kun je niets toekennen aan en opvragen van data in je struct in het eerste geval, en zul je op een later tijdstip alsnog een new moeten doen. :)

Onder C# krijg je dan een 'object reference not set to an instance of an object' exceptie, ik weet niet of die in C ook zo heet...
thabitzaterdag 22 oktober 2011 @ 02:33
quote:
0s.gif Op vrijdag 21 oktober 2011 21:51 schreef FastFox91 het volgende:
Wat is het verschil tussen type variable_naam en type variable_naam = new type?
Bv struct hoi; en struct hoi = new struct;
new returnt een pointer, waarbij er op de heap geheugen wordt aangemaakt. In het eerste geval staat de struct op de stack.
FastFox91zaterdag 22 oktober 2011 @ 18:52
Bedankt voor de antwoorden, hier kan ik mee verder.
GS42zaterdag 22 oktober 2011 @ 23:24
quote:
Bij de tweede alloceer je meteen geheugen. Bij de eerst niet.
Bij beide declaraties wordt geheugen gealloceerd, bij de eerste aanroep gebeurt dit op de stack, bij de tweede aanroep in de common pool, waarbij new dus een pointer teruggeeft naar dit geheugen.

quote:
Daarnaast kun je niets toekennen aan en opvragen van data in je struct in het eerste geval, en zul je op een later tijdstip alsnog een new moeten doen.
Ik snap niet wat hiermee bedoeld wordt, maar uiteraard kan je de struct gewoon gebruiken en is het niet noodzakelijk om later nog een new-aanroep te doen.

quote:
new returnt een pointer, waarbij er op de heap geheugen wordt aangemaakt. In het eerste geval staat de struct op de stack.
Kort, krachig en grotendeels juist. Alleen het gebruik van het woord heap begrijp ik niet: in de common pool is geen sprake van een datastructuur?

Gebruik 'new' alleen als je zeker weet dat je het nodig hebt. Zoniet: weglaten.
RealBizkit666zaterdag 22 oktober 2011 @ 23:35
quote:
In the C++ programming language, as well as in many C++-based languages, new is a language construct that dynamically allocates memory on the heap and initialises the memory using the constructor. Except for a form called the "placement new", new attempts to allocate enough memory on the heap for the new data. If successful, it initialises the memory and returns the address to the newly allocated and initialised memory. However if new cannot allocate memory on the heap it will throw an exception of type std::bad_alloc. This removes the need to explicitly check the result of an allocation. A call to delete, which calls the destructor and returns the memory allocated by new back to the heap, must be made for every call to new to avoid a memory leak.
Catbertzondag 23 oktober 2011 @ 00:35
Goh, iemand heeft Wikipedia gevonden.
RealBizkit666zondag 23 oktober 2011 @ 08:53
quote:
0s.gif Op zondag 23 oktober 2011 00:35 schreef Catbert het volgende:
Goh, iemand heeft Wikipedia gevonden.
Klopt, om duidelijk te maken dat de heap gebruikt wordt. ;)
netolkdonderdag 10 november 2011 @ 00:26
Kan iemand mij uitleggen waarom dit programma een (onbekende) error geeft waardoor windows het programma sluit??

het gaat om dit stukje

1
2
3
4
5
6
struct Data{
 *ptr1;
 *ptr2;
};
Data *myData;
myData = new Data[1000*1000*1000];

Hier loopt het programma vast maar als ik 2 vd 3 1000 naar 100 zet werkt het wel gewoon...
Ik, heb werkgeheugen om de 1,86 GB te bewaren, ik snap niet waarom dit niet werkt

alvast bedankt voor de hulp
thabitdonderdag 10 november 2011 @ 00:40
quote:
0s.gif Op donderdag 10 november 2011 00:26 schreef netolk het volgende:
Kan iemand mij uitleggen waarom dit programma een (onbekende) error geeft waardoor windows het programma sluit??

het gaat om dit stukje
[ code verwijderd ]

Hier loopt het programma vast maar als ik 2 vd 3 1000 naar 100 zet werkt het wel gewoon...
Ik, heb werkgeheugen om de 1,86 GB te bewaren, ik snap niet waarom dit niet werkt

alvast bedankt voor de hulp
Een pointer neemt doorgaans op een 32-bitssystem 4 bytes in en op een 64-bitssysteem 8 bytes. We kunnen dus concluderen dat het veel meer dan 1,86 GB inneemt. Om dit te adresseren heb je meer dan 4 GB en dus een 64-bitssysteem nodig. Dan kom je toch al gauw uit op 16 * 10003 bytes en dat is ongeveer 14,9 GB.
netolkdonderdag 10 november 2011 @ 00:44
quote:
0s.gif Op donderdag 10 november 2011 00:40 schreef thabit het volgende:

[..]

Een pointer neemt doorgaans op een 32-bitssystem 4 bytes in en op een 64-bitssysteem 8 bytes. We kunnen dus concluderen dat het veel meer dan 1,86 GB inneemt. Om dit te adresseren heb je meer dan 4 GB en dus een 64-bitssysteem nodig. Dan kom je toch al gauw uit op 16 * 10003 bytes en dat is ongeveer 14,9 GB.
Ahh, vandaar :) ik snapte het al niet dacht dat pointers 1 byte waren Xd maar nu ik dit zo lees is het idd logisch dat ze 8 bytes zijn 8)7
Dale.woensdag 16 november 2011 @ 02:46
Vraagje

ik heb een variabele b dat een unsigned long array is. Nu heb ik het volgende stukje code:
1
2
3
4
unsigned long *a  = b;
a[1] = iets
...
a += 2

Nu wil ik dit graag veranderen naar

1
2
3
*(b + 1) = iets
...
*(b) += 2

Nu runt dit wel maar echter krijg ik dan een foute berekening, omdat ik geloof de laatste stement *(b) += 2 fout is. Kan iemand me ook vertellen waarom die fout is, ik geloof dat dat "*a" een adres is van b maar wat is "a" dan?
Catbertwoensdag 16 november 2011 @ 10:44
quote:
0s.gif Op donderdag 10 november 2011 00:44 schreef netolk het volgende:
Ahh, vandaar :) ik snapte het al niet dacht dat pointers 1 byte waren Xd maar nu ik dit zo lees is het idd logisch dat ze 8 bytes zijn 8)7
Als een pointer 1 byte was, en dus 256 mogelijke waarden had, dan had je maar 256 bytes kunnen adresseren he...
thabitwoensdag 16 november 2011 @ 11:04
quote:
7s.gif Op woensdag 16 november 2011 02:46 schreef Dale. het volgende:
Vraagje

ik heb een variabele b dat een unsigned long array is. Nu heb ik het volgende stukje code:
[ code verwijderd ]

Nu wil ik dit graag veranderen naar
[ code verwijderd ]

Nu runt dit wel maar echter krijg ik dan een foute berekening, omdat ik geloof de laatste stement *(b) += 2 fout is. Kan iemand me ook vertellen waarom die fout is, ik geloof dat dat "*a" een adres is van b maar wat is "a" dan?
a is een pointer, wordt dus gerepresenteerd door een adres. Het statement a += 2 schuift de pointer dus twee plekken op. *a is datgene waar de pointer naar verwijst, ofwel de inhoud van het adres; idem dito voor *b. a en b verwijzen naar hetzelfde adres in jouw code.

*(b+i) is hetzelfde als b[i]. *b is dus hetzelfde als b[0] en ook hetzelfde als *a, wat niet a is.
Dale.woensdag 16 november 2011 @ 12:07
quote:
0s.gif Op woensdag 16 november 2011 11:04 schreef thabit het volgende:

[..]

a is een pointer, wordt dus gerepresenteerd door een adres. Het statement a += 2 schuift de pointer dus twee plekken op. *a is datgene waar de pointer naar verwijst, ofwel de inhoud van het adres; idem dito voor *b. a en b verwijzen naar hetzelfde adres in jouw code.

*(b+i) is hetzelfde als b[i]. *b is dus hetzelfde als b[0] en ook hetzelfde als *a, wat niet a is.
Ok dus als ik het goed begrijp moet de laatste regel niet

*(b) += 2 worden maar gewoon b += 2?
thabitwoensdag 16 november 2011 @ 13:24
quote:
7s.gif Op woensdag 16 november 2011 12:07 schreef Dale. het volgende:

[..]

Ok dus als ik het goed begrijp moet de laatste regel niet

*(b) += 2 worden maar gewoon b += 2?
Ik geloof niet dat je zoiets zomaar kan doen met arrays (tenzij ze een functie-argument zijn, want dan zijn het gewoon pointers).
netolkwoensdag 16 november 2011 @ 19:55
quote:
0s.gif Op woensdag 16 november 2011 10:44 schreef Catbert het volgende:

[..]

Als een pointer 1 byte was, en dus 256 mogelijke waarden had, dan had je maar 256 bytes kunnen adresseren he...
klopt, dat bedacht ik me dus na de uitleg ook... is gewoon :|W
netolkwoensdag 16 november 2011 @ 19:57
quote:
0s.gif Op woensdag 16 november 2011 13:24 schreef thabit het volgende:

[..]

Ik geloof niet dat je zoiets zomaar kan doen met arrays (tenzij ze een functie-argument zijn, want dan zijn het gewoon pointers).
Array's zijn toch stiekem gewoon altijd pointers???
thabitwoensdag 16 november 2011 @ 20:07
quote:
0s.gif Op woensdag 16 november 2011 19:57 schreef netolk het volgende:

[..]

Array's zijn toch stiekem gewoon altijd pointers???
In principe wel, maar er zijn wat subtiele verschillen.
GS42woensdag 16 november 2011 @ 21:40
quote:
7s.gif Op woensdag 16 november 2011 02:46 schreef Dale. het volgende:
Nu runt dit wel maar echter krijg ik dan een foute berekening, omdat ik geloof de laatste stement *(b) += 2 fout is. Kan iemand me ook vertellen waarom die fout is, ik geloof dat dat "*a" een adres is van b maar wat is "a" dan?
Nee, *a is geen adres van b: a is het adres van b. *a is de eerste waarde uit b.

Wat probeer je te doen? Zoals tha_bit al zei, zijn jouw a[1] = iets en *(b + 1) = iets gelijk aan elkaar, omdat a het adres van de array b bevat en de operator[] onder water hetzelfde doet als jij in je tweede voorbeeld. (Trouwens, een leuk detail dat hieruit volgt is dat b[2] identiek is aan 2[b]; dit mag in C(++) ook zo worden gebruikt. Probeer maar...)

De tweede regels zijn niet gelijk aan elkaar. De code a += 2 schuift de pointer a twee adressen op (afhankelijk van de lengte van de array kan dit dus problemen opleveren). De code *b += 2 verhoogt de waarde van b[0] met 2.

Zoals tha_bit ook al zei, kan je niet b += 2 schrijven, omdat het adres waar b naar wijst niet veranderd mag worden.

Een array kan je zien als een const pointer (technisch is het een geheugenadres: de compiler vervangt de arraynaam direct door een adres en maakt dus geen variabele aan). De waarde van b mag dus niet veranderd worden, maar die van *b wel (want een arraynaam 'is' een constante pointer, geen pointer naar een constante). De uitzondering hierop zijn arrays als functie-argumenten (zoals argv[]): dit zijn altijd pointers. (Dit komt doordat de compiler gedwongen wordt het geheugenadres wel een naam te geven als deze aan een functie wordt doorgegeven.)

quote:
Ok dus als ik het goed begrijp moet de laatste regel niet

*(b) += 2 worden maar gewoon b += 2?
Dit mag dus niet. Nogmaals: wat wil je bereiken? Als je met een pointer over de array wilt itereren, heb je expliciet een pointer nodig omdat je b niet mag wijzigen.
Dale.donderdag 17 november 2011 @ 10:17
Ok thanks :) en ja dat laatste wou ik dus :P

Ander vraagje... is het mogelijk om deze expressie korter op te schrijven?

(x >> 16) & 0xff ?

Is het mogelijk dit om te schrijven naar een expressie met maar 1 actie? Geloof 't niet he?
thabitdonderdag 17 november 2011 @ 10:22
Wat is x?
Dale.donderdag 17 november 2011 @ 10:49
quote:
0s.gif Op donderdag 17 november 2011 10:22 schreef thabit het volgende:
Wat is x?
een integer.
thabitdonderdag 17 november 2011 @ 10:52
Hoeveel bits? Als het er 32 zijn, is de &0xff-stap niet nodig.
Dale.donderdag 17 november 2011 @ 10:54
quote:
12s.gif Op donderdag 17 november 2011 10:52 schreef thabit het volgende:
Hoeveel bits? Als het er 32 zijn, is de &0xff-stap niet nodig.
Ja 32 bits en nice!!! Even proberen!

-edit-
Hmmm nee klopt niet. Wanneer ik de stap weghaal krijg ik een andere output.

Dit is eigenlijk me regel;
t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff]

(s1 >> 16) & 0xff en (s2 >> 8) & 0xff is dus hetgene waar het over gaat en s0, s1, s2, s3 zijn alle unsigned integers.

[ Bericht 29% gewijzigd door Dale. op 17-11-2011 11:01:21 ]
thabitdonderdag 17 november 2011 @ 11:17
Bij 8 kun je de &0xff niet weglaten uiteraard.
Dale.donderdag 17 november 2011 @ 11:23
quote:
0s.gif Op donderdag 17 november 2011 11:17 schreef thabit het volgende:
Bij 8 kun je de &0xff niet weglaten uiteraard.
Ja idd. Maar als ik alleen de & 0xff weghaal bij (s1 >> 16) dan verandert de output.
thabitdonderdag 17 november 2011 @ 11:24
Als je 'netjes' wilt programmeren, moet je dit soort truuks sowieso vermijden. Zeker bij integertypes die je voor indexering gebruikt moet de code gewoon werken onafhankelijk van het aantal bits waaruit deze integers bestaan. Er bestaat een typedef die size_t heet. Die kiest automatisch het juiste integertype voor adressering; dat zal doorgaans een 32-bits integer zijn op een 32-bits syteem en een 64-bits integer op een 64-bits systeem.
Dale.donderdag 17 november 2011 @ 11:30
quote:
0s.gif Op donderdag 17 november 2011 11:24 schreef thabit het volgende:
Als je 'netjes' wilt programmeren, moet je dit soort truuks sowieso vermijden. Zeker bij integertypes die je voor indexering gebruikt moet de code gewoon werken onafhankelijk van het aantal bits waaruit deze integers bestaan. Er bestaat een typedef die size_t heet. Die kiest automatisch het juiste integertype voor adressering; dat zal doorgaans een 32-bits integer zijn op een 32-bits syteem en een 64-bits integer op een 64-bits systeem.
Ja ok, maar het gaat in dit geval niet om netjes maar puur om snelheid en dus zo min mogelijk operaties en zo efficiënt mogelijk gebruik van het geheugen en de beschikbare operaties.

Dit is het gehele algorithme trouwens, rijndael algo.

SPOILER
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
unsigned int hive_rk[RKSIZE]; 
unsigned int hive_key[KEYLENGTH(KEYBITS)];
unsigned char hive_plaintext[16];
unsigned char hive_ciphertext[16];

void rijndaelEncrypt(void) ENTRY
{
    unsigned int s0, s1, s2, s3, t0, t1, t2, t3, *rk = hive_rk;

    /**
     * map byte array block to cipher state
     * and add initial round key:
     */
    s0 = GETU32(hive_plaintext       ) ^ rk[0];
    s1 = GETU32(hive_plaintext +  4) ^ rk[1];
    s2 = GETU32(hive_plaintext +  8) ^ rk[2];
    s3 = GETU32(hive_plaintext + 12) ^ rk[3];

    // round 1:
    t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
    t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
    t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
    t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
    // round 2:
    s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
    s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
    s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
    s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
    // round 3:
    t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
    t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
    t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
    t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
    // round 4:
    s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
    s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
    s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
    s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
    // round 5:
    t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
    t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
    t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
    t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
    // round 6:
    s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
    s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
    s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
    s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
    // round 7:
    t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
    t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
    t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
    t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
    // round 8:
    s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
    s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
    s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
    s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
    // round 9:
    t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
    t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
    t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
    t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];

    rk += 40;

    /**
     * apply last round and
     * map cipher state to byte array block:
     */
    s0 = (Te4[(t0 >> 24)       ] & 0xff000000) 
       ^ (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) 
       ^ (Te4[(t2 >>  8) & 0xff] & 0x0000ff00) 
       ^ (Te4[ t3        & 0xff] & 0x000000ff) 
       ^ rk[0];

    PUTU32(hive_ciphertext, s0);

    s1 = (Te4[(t1 >> 24)       ] & 0xff000000) 
       ^ (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) 
       ^ (Te4[(t3 >>  8) & 0xff] & 0x0000ff00) 
       ^ (Te4[ t0        & 0xff] & 0x000000ff) 
       ^ rk[1];

    PUTU32(hive_ciphertext + 4, s1);

    s2 = (Te4[(t2 >> 24)       ] & 0xff000000) 
       ^ (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) 
       ^ (Te4[(t0 >>  8) & 0xff] & 0x0000ff00) 
       ^ (Te4[t1         & 0xff] & 0x000000ff) 
       ^ rk[2];

    PUTU32(hive_ciphertext + 8, s2);

    s3 = (Te4[(t3 >> 24)       ] & 0xff000000) 
       ^ (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) 
       ^ (Te4[(t1 >>  8) & 0xff] & 0x0000ff00) 
       ^ (Te4[ t2        & 0xff] & 0x000000ff) 
       ^ rk[3];

    PUTU32(hive_ciphertext + 12, s3);

    return;
}


[ Bericht 89% gewijzigd door Dale. op 17-11-2011 11:36:29 ]
thabitdonderdag 17 november 2011 @ 11:37
Ah, ik zie al wat ik fout dacht. 0xff is natuurlijk 8 keer een 1, niet 16 keer.
thabitdonderdag 17 november 2011 @ 11:46
Er bestaat ongetwijfeld implementaties van dit soort algoritmen die tot op de cpu-cycle geoptimaliseerd zijn. Die zijn ook vast op het internet wel ergens te vinden.

In elk geval is het zo dat de performance bottleneck vaak op hele andere plekken ligt dan het zo efficiënt mogelijk uitvoeren van elementaire bitoperaties.
Ai_KaRaMBadonderdag 17 november 2011 @ 14:58
quote:
7s.gif Op donderdag 17 november 2011 10:17 schreef Dale. het volgende:
Ander vraagje... is het mogelijk om deze expressie korter op te schrijven?

(x >> 16) & 0xff ?
kan toch met 1 move?

1((unsigned char*)x)[2]

Maar pas op met portability: endianness van je systeem maakt dan plotseling uit!
thabitdonderdag 17 november 2011 @ 15:13
quote:
0s.gif Op donderdag 17 november 2011 14:58 schreef Ai_KaRaMBa het volgende:

[..]

kan toch met 1 move?
[ code verwijderd ]

Maar pas op met portability: endianness van je systeem maakt dan plotseling uit!
Dit is zeker niet sneller. Om te adresseren zal de compiler het namelijk terug moeten casten naar een 32-bits integer.
Ai_KaRaMBadonderdag 17 november 2011 @ 15:54
Uhm, ik ben nog niet direct overtuigd dus ik heb het even geprobeerd:

1
2
3
4
5
6
7
8
9
10
11
unsigned long tr1[255];

unsigned long t1(unsigned int x)
{
    return tr1[(x>>16) & 0xff];
}

unsigned long t2(unsigned int x)
{
    return tr1[((unsigned char*)&x)[2]];
}

en dit in GCC met -O2 optimalisatie gegooid, en in beide gevallen wordt de functie gecompileerd tot:

1
2
3
4
5
6
    pushl   %ebp
    movl    %esp, %ebp
    movzbl  10(%ebp), %eax
    popl    %ebp
    movl    tr1(,%eax,4), %eax
    ret

oftewel: hij pakt idd maar 1 byte uit x en die wordt geexpand tot long om te kunnen indexen. GCC vindt een move dus ook sneller dan bitshiften + masken!

Maar goed, conclusie: een compiler is slim genoeg om dat ook te bedenken, dus met herschrijven win je niks aan performance (maar je verliest wat leesbaarheid).

Ander idee: je algorimte doet netjes steeds hetzelfde op 4 integers; kun je er geen SIMD variant van bouwen? Al blijft je lookup-table dan waarschijnlijk nog steeds de bottleneck...
thabitdonderdag 17 november 2011 @ 17:09
Hmm, interessant. Je kan het optimaliseren dus beter aan de compiler overlaten dan zelf doen (tenzij het puur algoritmische optimalisaties zijn). Sowieso optimaliseer ik zelf nooit zonder eerst te profilen; alleen dan weet je pas waar de echte traagheden zitten.

Probeer eens of de extra compileroptie -fomit-frame-pointer een nog snellere output geeft. Al dat ge-ebp lijkt me een beetje onnodig hier. :).
Ai_KaRaMBadonderdag 17 november 2011 @ 17:32
Sowieso eerst profilen inderdaad, en als ik een bottleneck hebt gevonden vind ik het altijd wel aardig om te optimaliseren met de gegenereerde assembly code ernaast. Sommige optimalisaties lijken slim, maar de compiler wil daar nog wel eens een ander idee over hebben... (sommige optimalisaties hebben tot gevolg dat de compiler minder goed verder kan optimaliseren)

Zowel met GCC als met Microsoft Visual C(++) kun je trouwens vrij eenvoudig aangeven dat je de assembly listings van de compiler ook wil hebben: GCC met de -S switch, en in MSVC kun je in de eigenschappen van je project, bij de C compiler instellingen aangeven dat je een assembly listing (en wat je daar allemaal in wil hebben) als onderdeel van je "output files" wil hebben.

Ommitten van framepointers en __fastcall achtige dingen zetten meestal geen zoden aan de dijk (en maken debuggen een stukje lastiger). Als er echt een punt is waar dat zinnig zou zijn, kun je die functies inline-en...
netolkdonderdag 17 november 2011 @ 20:16
Waar laat de gcc compiler die assembly code dan??
mijn g++ compiler pakt -s ook maar ik kan de file niet terug vinden :(
Ai_KaRaMBadonderdag 17 november 2011 @ 21:25
Uit m'n hoofd; heb nu geen zin om de man-pages door te spitten:

het is -S met een hoofdletter. Als je een outputfile specificeert wordt de assembly daarin gemikt. Geef je geen outputfile, neemt 'ie de basis-bestandsnaam van je C file, en geeft 'm een ".s" extentie
Toryumaandag 21 november 2011 @ 11:57
Klein vraagje:
Als ik een deel van mijn code wil debuggen doe ik nogal omslachtig. Ik maak een nieuwe project (in Eclipse) kopieer de betreffende files naar de nieuwe map en maak daar een main file om wat tests uit te voeren.
Als het klaar is, kopieer ik de files weer terug naar mijn oorspronkelijke project zodat ik zeker weet dat ik de laatste versie heb.

Kan dat niet makkelijk? Hoe doen jullie dat?
Catbertmaandag 21 november 2011 @ 12:01
Units tests gebruiken? http://en.wikipedia.org/wiki/CppUnit bijvoorbeeld?
Ai_KaRaMBamaandag 21 november 2011 @ 17:01
Is er iets wat je tegenhoud om niet de bestanden te kopieren, maar direct in je project te mikken? Scheelt je in ieder geval je kopieer & synchonisatie problemen...
thabitmaandag 21 november 2011 @ 18:17
quote:
0s.gif Op maandag 21 november 2011 11:57 schreef Toryu het volgende:
Klein vraagje:
Als ik een deel van mijn code wil debuggen doe ik nogal omslachtig. Ik maak een nieuwe project (in Eclipse) kopieer de betreffende files naar de nieuwe map en maak daar een main file om wat tests uit te voeren.
Als het klaar is, kopieer ik de files weer terug naar mijn oorspronkelijke project zodat ik zeker weet dat ik de laatste versie heb.

Kan dat niet makkelijk? Hoe doen jullie dat?
Ik gebruik zelf gewoon een versiebeheersysteem voor zoiets. Je kan dan lekker lopen klooien; met 1 commando is alles toch weer teruggedraaid.

[ Bericht 0% gewijzigd door thabit op 21-11-2011 19:01:35 ]
Toryumaandag 21 november 2011 @ 21:21
Ik zocht eigenlijk wat eenvoudigs, maar CppUnit of een versiebeheersysteem wordt het alleen maar ingewikkelder.
Ik doe het voorlopig wel zo, eerst maar eens de basis van c++ onder de knie krijgen. (ik zit al uren te kloten om een functie uit een andere class aan te roepen :( )
thabitmaandag 21 november 2011 @ 21:42
Ach, drempelvrees, daar moet je even over heen. Als je eenmaal aan zo'n versiebeheersysteem gewend bent, dan wil je niet meer terug.
netolkdinsdag 22 november 2011 @ 15:31
@Toryu

Ik doe het idd meestal op de zelfde manier alleen maak ik een nieuw bestand test.cpp aan die ik dan compileer
Soms debug ik ook terwijl het programma'tje draait maar daar gebruik ik dan cheat engine voor
netolkdonderdag 22 december 2011 @ 14:53
Hey, ik heb een vraag mbt. de socket

ik heb dit stukje code:
1
2
3
4
5
6
7
8
9
SOCKET hSocket = INVALID_SOCKET;
            
            try{
                std::cout << "Creating socket... ";
                if((hSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_ICMP)) == INVALID_SOCKET){
                    std::cout << "Failed!\n";
                    throw Error();
                }
                std::cout << "Done.\n";
Nu is het alleen zo dat bij het maken van de socket er iets fout gaat...
Ik snap alleen niet waarom dat fout gaat, het is uiteindelijk de bedoeling dat het programma ping acties kan uitvoeren (nee het is niet mogelijk om de ping.exe te gebruiken), kan iemand mij helpen?
Ai_KaRaMBavrijdag 23 december 2011 @ 11:19
Heb je http://msdn.microsoft.com/en-us/library/windows/desktop/ms740673(v=vs.85).aspx al eens gelezen? Flink uitleg & voorbeeld code. Heb het toevallig laatst zelf gebruikt en werkt als een trein.

1 van de verschillen tussen de voorbeeldcode uit MSDN en jouw code, is dat zei getaddrinfo() gebruikten om een geldige combinatie van parameters voor socket() te vinden...
netolkdinsdag 27 december 2011 @ 10:56
hmm, heb je dan ook een ICMP protocol gebruikt??
Die zie ik er namelijk niet tussen staan (maar de compiler pakt hem wel)
in ieder geval bedankt voor de link er staat idd best nuttige info tussen
FastFox91woensdag 1 februari 2012 @ 16:03
Ik wil een programma schrijven die iets doet met een ingescande afbeelding. (Ik werk op Ubuntu.) Scanimage is een command die het scannen doet. Hoe laat ik mijn programma goed werken met andere applicaties? Popen is een optie en volgens mij moet dat wel kunnen werken, maar zijn er ook alternatieven? Libraries includen oid? Ik heb hier geen ervaring mee, advies/tips/zoekwoorden zijn welkom!
GS42donderdag 2 februari 2012 @ 19:36
quote:
Popen is een optie en volgens mij moet dat wel kunnen werken, maar zijn er ook alternatieven?
Je bent te onduidelijk in wat je wilt. Als je gerichter advies wilt, dan zul je beter moeten omschrijven wat je wilt bereiken.

Als de broncode van scanimage openbaar is, kan je daarvan gebruik maken. Dit is echter meestal erg complex om aan de praat te krijgen bij programma's van meer dan minimale grootte.

Wat betreft popen: pipes zijn een laatste redmiddel dat je alleen wilt gebruiken als je geen andere mogelijkheden hebt. In veel gevallen kan je beter een extern programma uitvoeren voordat je jouw programma start of met een system-call waarin je de uitvoer naar een bestand laat schrijven.

Alleen als je interactief met een extern programma wilt werken, moet je pipes overwegen. In alle andere gevallen verwacht ik dat er betere oplossingen zijn.

[ Bericht 0% gewijzigd door GS42 op 02-02-2012 20:00:31 ]
FastFox91vrijdag 3 februari 2012 @ 17:42
quote:
0s.gif Op donderdag 2 februari 2012 19:36 schreef GS42 het volgende:

[..]

Je bent te onduidelijk in wat je wilt. Als je gerichter advies wilt, dan zul je beter moeten omschrijven wat je wilt bereiken.

Als de broncode van scanimage openbaar is, kan je daarvan gebruik maken. Dit is echter meestal erg complex om aan de praat te krijgen bij programma's van meer dan minimale grootte.

Wat betreft popen: pipes zijn een laatste redmiddel dat je alleen wilt gebruiken als je geen andere mogelijkheden hebt. In veel gevallen kan je beter een extern programma uitvoeren voordat je jouw programma start of met een system-call waarin je de uitvoer naar een bestand laat schrijven.

Alleen als je interactief met een extern programma wilt werken, moet je pipes overwegen. In alle andere gevallen verwacht ik dat er betere oplossingen zijn.
Ik wil in een programma gebruik maken van scanimage, zodat de gebruiker het niet hoeft te doen. In principe kan de gebruiker dat handmatig doen in command line. Het is enkel instructie opgeven en resultaat afvangen, meer interactie is niet nodig. Ik heb geen idee hoe ik specifieker kan zijn. Een system-call lijkt mij niet handig, want ik wil juist automatiseren. Broncode downloaden en verwerken in mijn programma is wel een nette oplossing, maar misschien te veel moeite voor mijn relatief klein project. Bedankt iig voor je reactie.
thabitvrijdag 3 februari 2012 @ 18:00
quote:
0s.gif Op vrijdag 3 februari 2012 17:42 schreef FastFox91 het volgende:

[..]

Ik wil in een programma gebruik maken van scanimage, zodat de gebruiker het niet hoeft te doen. In principe kan de gebruiker dat handmatig doen in command line. Het is enkel instructie opgeven en resultaat afvangen, meer interactie is niet nodig. Ik heb geen idee hoe ik specifieker kan zijn. Een system-call lijkt mij niet handig, want ik wil juist automatiseren. Broncode downloaden en verwerken in mijn programma is wel een nette oplossing, maar misschien te veel moeite voor mijn relatief klein project. Bedankt iig voor je reactie.
Ik zou geen C++ gebruiken voor zulke simpele handelingen.
FastFox91vrijdag 3 februari 2012 @ 18:02
quote:
0s.gif Op vrijdag 3 februari 2012 18:00 schreef thabit het volgende:

[..]

Ik zou geen C++ gebruiken voor zulke simpele handelingen.
De handelingen die ik met het resultaat wil doen zijn minder simpel.
GS42vrijdag 3 februari 2012 @ 18:55
quote:
Het is enkel instructie opgeven en resultaat afvangen, meer interactie is niet nodig. Ik heb geen idee hoe ik specifieker kan zijn. Een system-call lijkt mij niet handig, want ik wil juist automatiseren
Specifieker hoeft niet, denk ik. ;) Een system call lijkt me in dit geval juist ideaal. Kijk eens naar de system() functie, waarmee je de shell aan kunt roepen vanuit je programma. Zo kun je jouw externe programma automatisch aan laten roepen. Als je de uitvoer van het programma nodig hebt, kan je die doorsturen een een bestandje en deze later uitlezen (denk aan "ls > .temp.txt" ofzo). Als de uitvoer een nieuwe bestand is (zoals ik verwacht van scanimages) hoef je die moeite niet eens te doen.

Denk je dat je dit kunt gebruiken of zie ik iets over het hoofd?
FastFox91zaterdag 4 februari 2012 @ 10:59
quote:
0s.gif Op vrijdag 3 februari 2012 18:55 schreef GS42 het volgende:

[..]

Specifieker hoeft niet, denk ik. ;) Een system call lijkt me in dit geval juist ideaal. Kijk eens naar de system() functie, waarmee je de shell aan kunt roepen vanuit je programma. Zo kun je jouw externe programma automatisch aan laten roepen. Als je de uitvoer van het programma nodig hebt, kan je die doorsturen een een bestandje en deze later uitlezen (denk aan "ls > .temp.txt" ofzo). Als de uitvoer een nieuwe bestand is (zoals ik verwacht van scanimages) hoef je die moeite niet eens te doen.

Denk je dat je dit kunt gebruiken of zie ik iets over het hoofd?
Voor de werking lijkt het erg op pipes (in deze simpele vorm). Bedankt voor het advies, ik ga ermee aan de slag. :)
obsamawoensdag 8 februari 2012 @ 12:36
We zijn net begonnen met java en daarom een hele domme vraag, maar waarom krijg ik een foutmelding dat Student a leeg is ?

Tabel klas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.*;

public class Klas
{
private ArrayList<Student> klas;
public Klas()
{
ArrayList klas = new ArrayList<Student>();
}
public void printoverzicht()
{
for(Student a : klas)
{
System.out.println(a.getNaam());
}
}

}

tabel Student
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Student
{
    public String naam;
    public String woonplaats;
    public Student(String n, String w)
    {
        naam=n;
        woonplaats=w;
    }
    public String getNaam()
    {
        return naam;
    }
    
}
trouwens, krijg het niet voor elkaar om de code in een code tag te zetten ? Ook kan ik mijn post niet previewen.

Bedankt alvast !
thabitwoensdag 8 februari 2012 @ 13:23
quote:
0s.gif Op woensdag 8 februari 2012 12:36 schreef obsama het volgende:
We zijn net begonnen met java en daarom een hele domme vraag, maar waarom krijg ik een foutmelding dat Student a leeg is ?

Tabel klas
[ code verwijderd ]

tabel Student
[ code verwijderd ]

trouwens, krijg het niet voor elkaar om de code in een code tag te zetten ? Ook kan ik mijn post niet previewen.

Bedankt alvast !
Twee opmerkingen over de manier waarop je de code presenteert:

(1) Inspringen, dat bovenste blok is zo niet leesbaar.
(2) Geef een zo kort mogelijk doch volledig programma (dus inclusief main) dat runt en de foutmelding geeft.

Verder is Java natuurlijk geen C++. Het lijkt van de buitenkant erg op elkaar, maar onder de motorkap zijn er nog wel behoorlijke verschillen.
netolkwoensdag 8 februari 2012 @ 19:53
quote:
0s.gif Op woensdag 8 februari 2012 13:23 schreef thabit het volgende:

[..]

Twee opmerkingen over de manier waarop je de code presenteert:

(1) Inspringen, dat bovenste blok is zo niet leesbaar.
(2) Geef een zo kort mogelijk doch volledig programma (dus inclusief main) dat runt en de foutmelding geeft.

Verder is Java natuurlijk geen C++. Het lijkt van de buitenkant erg op elkaar, maar onder de motorkap zijn er nog wel behoorlijke verschillen.
Dit dus, maar aangezien er geen java voor dummy's topic lijkt te bestaan vergeef ik het je ;)

Maar volgens mij komt het gewoon omdat je een lege arraylist copieërt naar de (als het goed is ook lege) arraylist.
1ArrayList klas = new ArrayList<Student>();
Bij mijn weten is dit ook een niet nuttige en dus overbodige actie
Oneironautzaterdag 11 februari 2012 @ 14:38
Net begonnen met een cursusje cpp. Ik strand al bij simpele input dingetjes... ik wil graag weten waarom

#include <iostream>
using namespace std;
int main()
{
char line[100];
cout << "Voer een lijn in" << endl;
cin.getline( line, 100);
cout << line;

system ("PAUSE");
return 0;
}
Oké deze werkt. Maar in de aanwijzing bij de opgave staat dat ik moet inlezen met cin.getline(const char* stg, Int len).

Dat lukt me dus niet. Ik snap wel dat je in deze versie netjes met een pointer werkt. Maar m'n compiler geeft foutmeldingen.
FastFox91zaterdag 11 februari 2012 @ 15:24
"cin.getline(const char* stg, Int len)", betekent niet dat je het letterlijk daarmee moet inlezen. Het geeft aan wat voort datetypen meegegeven moet worden. line is dus een const char* en 100 is een int.
Oneironautzaterdag 11 februari 2012 @ 15:29
Akkoord maar hoe introduceer ik 'm dan? Als const char line[100];
werkt het niet...
FastFox91zaterdag 11 februari 2012 @ 15:38
In het werkende deel gebruik je "char line[100]" (regel 5) en dat werkt. Als je const char line[100] doet, krijg je een array van chars die constant zijn. Dat wil je niet, aangezien je nieuwe chars wil inlezen (en opslaan). De pointer naar de array moet wel constant zijn.

(Ik weet overigs niet of ik het helemaal goed heb, ben relatief gezien ook nog een beginner.)
Oneironautzaterdag 11 februari 2012 @ 15:42
Bedankt voor je uitleg.
Maar je leest de string in op regel 7, via een pointer dus? Hoe mag die wel constanten zijn?
Behh ik snap het niet.

#include <iostream>
using namespace std;
int main()
{
char line[100];
cout << "Voer een lijn in" << endl;
cin.getline(const char *line, 100);
cout << line <<endl;

system ("PAUSE");
return 0;
}
zegt:
expected primary-expression before "const"
FastFox91zaterdag 11 februari 2012 @ 15:52
Waarom pas je een werkend stukje code aan eigenlijk, waardoor die niet meer werkt? Dit werkt toch gewoon?
1
2
3
4
char line[100]; // Hiermee reserveer je 100 karakters
cout << "Voer een lijn in" << endl; // Vraag wat invoer aan de gebruiker
cin.getline(line, 100); // Lees 100 karakters en schrijf deze weg naar line.
cout << line <<endl; // Output line
Oneironautzaterdag 11 februari 2012 @ 15:55
Omdat mijn docent blijkbaar wil dat ik pointers en constanten gebruik? Lijkt me dat er een fundamenteel verschil in zit, en ons daarom er op wijst?
FastFox91zaterdag 11 februari 2012 @ 16:00
Misschien een lesje pointers gebruiken. Het is niet zo als je nu getline( line vervangt door getline( const char* line, dat je dan ineens met pointers werken oid.
Oneironautzaterdag 11 februari 2012 @ 16:05
Bedankt in ieder geval voor je feedback. Ik snap pointers wel aardig dacht ik. Snap alleen niet waarom die op de input line een const char pointer wilt nemen. Ik lees m nu gewoon in en ga met een pointer er doorheen om van elk karakter te kijken of het een kleine letter, hoofdlette, getal of iets anders is. Draait goed. Snapte alleen die restrictie uit mijn eerste post niet.
FastFox91zaterdag 11 februari 2012 @ 16:09
Graag gedaan. Het stukje geheugen waar de chars in staan blijft hetzelfde. Line is een pointer naar dat stukje geheugen en je wil afdwingen dat die pointer niet naar iets anders kan gaan wijzen.
thabitzaterdag 11 februari 2012 @ 19:39
quote:
0s.gif Op zaterdag 11 februari 2012 14:38 schreef Oneironaut het volgende:
Maar in de aanwijzing bij de opgave staat dat ik moet inlezen met cin.getline(const char* stg, Int len).
Ik zou een ander boek pakken. :P. Een const char* is een pointer naar een const char. Dit zou suggereren dat de functie de chars in stg niet verandert, wat-ie natuurlijk wel doet. Die functie heeft dus een gewone char* als input, niet een const char*.
FastFox91zondag 12 februari 2012 @ 09:54
quote:
4s.gif Op zaterdag 11 februari 2012 19:39 schreef thabit het volgende:

[..]

Een const char* is een pointer naar een const char.
Heb ik ook weer wat geleerd. Ik dacht dat een const char* een const pointer was naar een char.
thabitzondag 12 februari 2012 @ 11:49
quote:
0s.gif Op zondag 12 februari 2012 09:54 schreef FastFox91 het volgende:

[..]

Heb ik ook weer wat geleerd. Ik dacht dat een const char* een const pointer was naar een char.
Een const pointer naar een char is char* const.

En dan nu de ultieme test: wat is een char const* ?
FastFox91zondag 12 februari 2012 @ 12:12
quote:
12s.gif Op zondag 12 februari 2012 11:49 schreef thabit het volgende:

[..]

Een const pointer naar een char is char* const.

En dan nu de ultieme test: wat is een char const* ?
In totaal heb je 4 mogelijkheden:
• pointer naar char (char*)
• const pointer naar char (char* const)
• pointer naar const char (const char*)
• const pointer naar const char (char const * const)
Ik denk dat er meerdere schrijfnotaties zijn en dat char const* hetzelfde is als const char* (pointer naar een const char)
thabitzondag 12 februari 2012 @ 14:45
quote:
0s.gif Op zondag 12 februari 2012 12:12 schreef FastFox91 het volgende:

[..]

In totaal heb je 4 mogelijkheden:
• pointer naar char (char*)
• const pointer naar char (char* const)
• pointer naar const char (const char*)
• const pointer naar const char (char const * const)
Ik denk dat er meerdere schrijfnotaties zijn en dat char const* hetzelfde is als const char* (pointer naar een const char)
Juist.
Oneironautzondag 12 februari 2012 @ 16:46
quote:
4s.gif Op zaterdag 11 februari 2012 19:39 schreef thabit het volgende:

[..]

Ik zou een ander boek pakken. :P. Een const char* is een pointer naar een const char. Dit zou suggereren dat de functie de chars in stg niet verandert, wat-ie natuurlijk wel doet. Die functie heeft dus een gewone char* als input, niet een const char*.
Lekker dan.... 't is een dictaat van een docent btw, maar de eerste hoofdstukken mogen toch wel goed zijn anders wordt het pittig.

Btw, kun je "wat-ie natuurlijk wel doet" toelichten?
FastFox91zondag 12 februari 2012 @ 18:02
quote:
14s.gif Op zondag 12 februari 2012 14:45 schreef thabit het volgende:

[..]

Juist.
:D
quote:
0s.gif Op zondag 12 februari 2012 16:46 schreef Oneironaut het volgende:

[..]

Lekker dan.... 't is een dictaat van een docent btw, maar de eerste hoofdstukken mogen toch wel goed zijn anders wordt het pittig.

Btw, kun je "wat-ie natuurlijk wel doet" toelichten?
De chars in stg (en dus line) wil je kunnen aanpassen, anders kan je wel leuk chars gaan intypen maar niet opslaan en gebruiken in je programma.
netolkmaandag 13 februari 2012 @ 16:15
Hey, ik ben (nog steeds) aan het kutten met ICMP maar ik kom niet verder met het SOCKET_RAW gebeuren....
Dit is de 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
int main(){
    WSAData wsaData;
    sockaddr_in dest,local;
    
    std::cout << "Inizializing... ";
    if(WSAStartup(MAKEWORD(2,0),&wsaData) == 0){
        if(LOBYTE(wsaData.wVersion) >= 2){
            std::cout << "Done.\n";
        }
        else
            std::cout << "Failed!\nRequired version not supported.\n";
        
        local.sin_family = AF_INET;
        local.sin_addr.s_addr = inet_addr(IP_SOURCE);
        local.sin_port = 0;
        
        dest.sin_family = AF_INET;
        dest.sin_addr.s_addr = inet_addr(IP_DESTINATION);
        dest.sin_port = 0;
        
        try{
            SOCKET hSocket;
            std::cout << "Creating Socket... ";
            if(hSocket = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP) == INVALID_SOCKET){
                std::cout << "Failed!\n";
                throw Error();
            }
            std::cout << "Done.\n";
            std::cout << "Binding... ";
            if(bind(hSocket,(sockaddr*)&local,sizeof(local)) != 0){
                std::cout << "Failed!\n";
                std::cout << "WSA Last Error: " << WSAGetLastError() << '\n';
                throw Error();
            }
            std::cout << "Done.\n";
            
            ICMPHeader ICMP;
            ICMP._TYPE = 8; // echo-request
            ICMP._CODE = 0;
            ICMP._CHECKSUM = 0;
            
            std::cout << "Sending... ";
            if(sendto(hSocket,(char*)&ICMP,sizeof(ICMP),0,(sockaddr*)&dest,sizeof(dest)) == SOCKET_ERROR){
                std::cout << "Failed!\n";
                throw Error();
            }
            std::cout << "Done.\n";
            
        }
        catch(Error){}
                
        std::cout << "Cleaning up... ";
        if(WSACleanup()!= 0){
            std::cout << "Failed!\n";
            return -1;
        }
        else
            std::cout << "Done.\n";
        
    }
    else
        std::cout << "Failed!\n";
    return 0;
}
Nu is het alleen zo dat ik de socket niet kan binden ik krijg WSA Error 10038 (WSAENOTSOCK)
Maar daarvoor heb ik al gekeken of de socket valid is en dat zou het geval moeten zijn, zou iemand mij kunnen uitleggen waarom dit niet werkt en hoe ik dit zou kunnen oplossen?
GS42dinsdag 14 februari 2012 @ 12:32
@netolk: Leuk voorbeeld van hoe een complex probleem veroorzaakt wordt door een simpele vergissing. Algemene tip: Luister altijd naar de waarschuwingen van je compiler.

Als ik compileer, geeft de compiler een waarschuwing op de regel
1if(hSocket = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP) == INVALID_SOCKET){

Zie je wat daar fout gaat? Deze regel corrigeren lost volgens mij het bind-probleem op.

SPOILER
Het if-statement wordt - omdat == (equals) een hogere prioriteit heeft dan = (assignment) - gelezen als:

1hSocket = ( socket(AF_INET,SOCK_RAW,IPPROTO_ICMP) == INVALID_SOCKET )

Dit betekent dat er eigenlijk staat: hSocket = true/false (afhankelijk van het succes van socket()). Omdat een SOCKET onder water gewoon een int is, wordt dit automatisch omgezet naar 1 of 0 en geeft de toekenning geen compileerproblemen.

Oplossing: gebruik haakjes om toekenningen als je tegelijk de waarde evalueert. De compiler controleert hierop.
PS: Je code was niet gemakkelijk te compileren. Als je sneller antwoord wilt, zorg dan dat je ook de nodige headers in de code zet, erbijzet met welke libraries je linkt en eventueel ontbrekende of overbodige klassen (ICMPHeader?) verduidelijkt.
netolkdinsdag 14 februari 2012 @ 14:13
Um, bij mijn weten probeerd ie eerst de socket te maken en checkt ie daarna of dat gelukt is. Maar dit is dan niet zo? Want deze manier van fout controle heb ik ook ooit eens in een tut voor tcp gezien.
Ow, enne ik Krijg geen waarschuwing van mijn compiler wat zou die waarschuwing moeten zijn?
Ai_KaRaMBadinsdag 14 februari 2012 @ 14:21
De vergelijking "==" heeft een hogere prioriteit dan toewijzing "=". Je assigned dus effectief een boolean waarde aan hSocket. Haakjes lossen dit op:
1if( (hSocket = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)) == INVALID_SOCKET )


[ Bericht 0% gewijzigd door Ai_KaRaMBa op 14-02-2012 14:52:20 ]
netolkdinsdag 14 februari 2012 @ 14:33
Ow, fuck... Die ben ik idd vergeten :-(
dit is best wel heel stom |:(
GS42dinsdag 14 februari 2012 @ 14:41
quote:
0s.gif Op dinsdag 14 februari 2012 14:13 schreef netolk het volgende:
Um, bij mijn weten probeerd ie eerst de socket te maken en checkt ie daarna of dat gelukt is. Maar dit is dan niet zo? Want deze manier van fout controle heb ik ook ooit eens in een tut voor tcp gezien.
Ow, enne ik Krijg geen waarschuwing van mijn compiler wat zou die waarschuwing moeten zijn?
Oh, ik dacht dat de spoiler wel duidelijk genoeg was. Maar je hebt het probleem nu gevonden. :)

De waarschuwing die mijn compiler (g++ 4.5) geeft is
quote:
In function 'int main()':
warning: suggest parentheses around assignment used as truth value
Als je waarschuwingen wilt zien, moet je meestal een flag meegeven (in mijn geval -wall).
Graag gedaan. ;)
netolkdinsdag 14 februari 2012 @ 15:25
quote:
0s.gif Op dinsdag 14 februari 2012 14:41 schreef GS42 het volgende:

[..]

Oh, ik dacht dat de spoiler wel duidelijk genoeg was. Maar je hebt het probleem nu gevonden. :)

De waarschuwing die mijn compiler (g++ 4.5) geeft is

[..]

Als je waarschuwingen wilt zien, moet je meestal een flag meegeven (in mijn geval -wall).
Graag gedaan. ;)
Hehe, had die hele spoiler niet gezien....
ik gebruik G++ moet volgensmij idd -wall maar zonder params krijg je wel gewoon waarschuwingen over data types zoals if(unsigned i < 0 ) dat die altijd waar is ed.
netolkwoensdag 15 februari 2012 @ 19:42
Het werkt nu, maar als ik iets ping (bijv. router), krijg ik een 56 bytes aan data terug, een deel ervan is de IP-Header en een deel is de ICMP-Header (met reply 0), maar dan zit er nog een stuk data achter, wat kan dat zijn? overigens verstuur ik dit alleen (behalve de IP-Header die sendto() maakt):

struct ICMPHeader{
unsigned char _TYPE;
unsigned char _CODE;
unsigned short _CHECKSUM;
};

type = 8 en de rest is 0.

Weet iemand wat dat stuk aan data kan zijn? Overigens duurt het ook vrij lang voordat ik reactie krijg (>30 sec), terwijl ik via ping gemiddeld iets van 1 a 2 ms krijg...

Reicieve Buffer Dump (IP-Header is weggelaten):
SPOILER
EDIT: dumpfile weg gehaald
1e kolom als char, 2e decimaal, 3e hexadecimaal


[ Bericht 60% gewijzigd door netolk op 17-02-2012 18:32:32 ]
netolkvrijdag 17 februari 2012 @ 18:36
oke, kom nu tot de conclusie dat wanneer ik de firewall aan heb staan dat ik errorcode 4 (Source Quench) terug krijg, als ik de firewall uit heb staan krijg ik een errorcode 3:13 (Destination Unreachable: Communication administratively prohibited) terwijl het adres wel bestaat ook krijg ik dezelfde error returns als ik een echo-request naar 127.0.0.1 probeer, snap er helemaal niks van :(
GS42zondag 19 februari 2012 @ 10:58
Netolk, zoals je merkt, krijg je niet veel reacties op je ICMP vragen, omdat het natuurlijk niet direct met C(++) te maken heeft. Zorg inderdaad dat al je firewalls uitstaan, want die zullen zeer waarschijnlijk het antwoord blokkeren.

Daarnaast heb ik het idee dat het pakket dat je verstuurt, niet genoeg data bevat. Lees deze website maar eens goed door, daar staan de specs duidelijk op.

Het lukt mij met het volgende (zelf geschreven) pakket:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct ICMPHeader {
    unsigned int type : 8;
    unsigned int code : 8;
    unsigned int checksum : 16;
};

struct ICMPPing : ICMPHeader {
    unsigned int ident : 16;
    unsigned int sequence : 16;

    unsigned char data[32];
};

ICMPPing ping;
ping.type = 8;
ping.code = 0;
ping.checksum = 0;
ping.ident = 0;
ping.sequence = 0;
memcpy(ping.data, "abcdefghijklmnipqrstuvwxyz012345", 32);

Maar verder ben ik bang dat je het vooral zelf uit moet puzzelen.
netolkzondag 19 februari 2012 @ 14:58
Ja, ik weet dat het niks met C++ te maken heeft, was meer een beetje frustratie lozen...
Ik denk dat ik die site idd maar eens grondig door zal gaan nemen

in iedergeval bedankt voor de hulp
Luchtkokerzondag 19 februari 2012 @ 19:57
Wie kan mij uitleggen wat deze functie parameter structuur inhoudt?

1double my_func(double (*my_arg)(double(*)(double))

Ik snap dat bijv:
1double my_func(double (*my_arg)(double))

een pointer is naar een functie met als returntype double, maar ik snap niet wat die (double) erachter doet. Betekent dat dat de functie double my_arg één double accepteert als argument? En double (*my_arg)(double (*)(double) verwart me al helemaal :').

[ Bericht 6% gewijzigd door Luchtkoker op 19-02-2012 20:05:40 ]
GS42zondag 19 februari 2012 @ 22:33
Luchtkoker,

Ten eerste, je bovenste stukje code is geen valide C++ omdat er een haakje ontbreekt; ik neem aan dat er nog een ')' aan het einde moet staan.

quote:
Ik snap dat bijv:1 [code]double my_func(double (*my_arg)(double))[/code]

een pointer is naar een functie met als returntype double
Dat klopt niet, my_func is hier geen pointer naar een functie. Vervang...
1double (*my_arg)(double)
...eens door iets simpels, bijvoorbeeld...
1double a
...en bekijk wat je dan overhoudt. Zie je dan wat my_func is?

Je eerste voorbeeld is zo gemakkelijker te lezen:

1
2
3
4
5
double my_func(
    double (*my_arg)(
        double(*)(double)
    )
);

Kom je er zo uit?
Luchtkokerzondag 19 februari 2012 @ 22:43
Dat haakje was inderdaad even ontglipt.

Verder snap ik het nog niet helemaal :@ Ik bedoelde ook niet dat my_func een pointer naar een functie was, maar my_arg. Maar goed, ik snap nog steeds niet wat bijv double(*)(double) is.
thabitzondag 19 februari 2012 @ 22:45
double(*)(double) is een pointer naar een functie die een double als input heeft en een double returnt. Het is zeg maar double(*func_name)(double) met func_name weggelaten.
Luchtkokerzondag 19 februari 2012 @ 22:51
Ah, oke. Dus toch wel de argumenten. Dan snap ik 'm. Thanks.
GS42vrijdag 2 maart 2012 @ 14:16
Gebruiken jullie de nieuwe faciliteiten van C++11 (de uiteindelijke naam van C++0x) al een beetje?

Eerder in dit topic zijn al de std::thread en de move semantics van r-value references genoemd, maar er is nog veel meer toegevoegd. Zo zijn er 4 nieuwe fundamentele types (long long int, char16_t, char32_t en std::nullptr_t, waarbij vooral de laatste conceptueel interessant is), nieuwe keywords (zoals constexpr en auto) en zowel uitbreidingen op de core (zoals anonieme functies en de r-value references) als op de STL (zoals std::thread en std::unordered_map).

Ik compileer eigenlijk altijd met -std=c++0x. Een van de simpelste dingen die ik veel gebruik is het nieuwe parsen van >>. In eerdere versies van C++ is het volgende een compileerfout omdat de >> gelezen wordt als een right shift:

1std::vector<std::pair<int, int>> vb;

In de nieuwe C++ versie is dit echter aangepast, zodat er geen spatie meer tussen hoeft. De std::unordered_map gebruik ik ook als ik een hashtable nodig heb. Als een klasse dynamisch geheugen gebruikt, geef ik die ook move-mogelijkheid (maar dit gebeurt niet erg vaak). De lambda's zijn, net als auto een mooie toevoeging die ik ook wel gebruik als het handig is.

Ik stel de vraag omdat ik benieuwd ben of de nieuwe C++ toevoegingen ook al onderwezen en gebruikt worden. In plaats van functiepointers (waar het hierboven over ging en die - zoals jullie zien - vreselijk lelijk zijn) is het bijvoorbeeld mogelijk om de nieuwe (en veel mooiere) std::function te gebruiken voor alles wat op een functie lijkt. Doen jullie dat ook?

Dus: wat gebruiken jullie in de praktijk van C++11?
GS42zondag 4 maart 2012 @ 13:56
... Of, als jullie C++11 niet gebruiken, ben ik daar ook benieuwd naar hoor. ;)

Niet nodig? Te ingewikkeld? Geen compiler-ondersteuning? Nooit van gehoord? ...?
FastFox91zondag 4 maart 2012 @ 16:01
Ik ga maar eerst normaal C++ verder leren, zodat ik het mogelijk nut van C++11 kan inzien.
thabitzondag 4 maart 2012 @ 16:54
quote:
0s.gif Op zondag 4 maart 2012 13:56 schreef GS42 het volgende:
... Of, als jullie C++11 niet gebruiken, ben ik daar ook benieuwd naar hoor. ;)

Niet nodig? Te ingewikkeld? Geen compiler-ondersteuning? Nooit van gehoord? ...?
C/C++ gebruik ik voor low-level spul. Voor het hogere programmeerwerk gebruik ik Python.

Ik vind dat hele C++11 gedoe een beetje mosterd na de maaltijd om eerlijk te zijn. Er wordt gedaan alsof er allemaal nieuwe superfeatures in zitten, terwijl andere programmeertalen dit soort zaken jaren geleden al ondersteunden.
netolkmaandag 5 maart 2012 @ 08:55
quote:
0s.gif Op zondag 4 maart 2012 13:56 schreef GS42 het volgende:
... Of, als jullie C++11 niet gebruiken, ben ik daar ook benieuwd naar hoor. ;)

Niet nodig? Te ingewikkeld? Geen compiler-ondersteuning? Nooit van gehoord? ...?
Ik denk niet dat mijn compiler het ondersteund aangezien ik een best oude gebruik omdat de nieuwe versie dll's mist oid. Maar die std::thread klinkt interessant, dat moet ik nu nog allemaal via windows doen
netolkwoensdag 7 maart 2012 @ 16:02
Hey, zou iemand mij dit kunnen uitleggen want ik snap er niks van...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct b8TOb16{
        char _B0:8;
        char _B1:8;
        
        void set(char B0,char B1){_B0=B0;_B1=B1;}
    };

    std::ofstream Write("Test.lvl",std::ios::binary);
    if(Write.is_open()){
        b8TOb16 myb8TOb16;
        unsigned short _X=5,_Y=5,_Z=1;
        myb8TOb16 = *(b8TOb16*)(&_X);
        Write.put(myb8TOb16._B0);
        Write.put(myb8TOb16._B1);
        
        std::cout << int(myb8TOb16._B0) << '\t' << int(myb8TOb16._B1) << '\n';
        Write.close();
    }
nu blijkt op mijn systeem _B0 = 5 en _B1 = 0
maar als ik later het bestand open en op deze manier uitlees:
1
2
    myb8TOb16.set(read.get(),read.get());
    std::cout << *(unsigned short*)(&myb8TOb16) << '\n';
dan blijkt er ineens 1280 (in dec) uit te komen oftewel de bytes zijn omgedraaid
maar als ik het op deze manier doe:
1
2
3
    char temp1=read.get(),temp2=read.get();
    myb8TOb16.set(temp1,temp2);
    std::cout << *(unsigned short*)(&myb8TOb16) << '\n';
komt er wel gewoon weer 5 uit, ik snap dus niet waarom het op de 1ste manier niet het goed getal uit komt en op de 2de manier wel
GS42woensdag 7 maart 2012 @ 16:14
Je komt wel altijd met leuke voorbeelden. :)

1myb8TOb16.set(read.get(),read.get());
Deze regel is ongedefinieerd, omdat C++ de argumenten van de functie in willekeurige volgorde mag evalueren.

Het klassieke voorbeeld is:
1
2
int i = 0;
functie(i++, i++);

Hierin weet je niet of functie(0, 1) aangeroepen wordt of functie(1, 0) omdat de compiler beide mag doen. In jouw geval worden de argumenten blijkbaar van rechts naar links verwerkt. Oplossing: minimaal 1 temp value gebruiken.

[ Bericht 2% gewijzigd door GS42 op 07-03-2012 18:12:00 ]
netolkwoensdag 7 maart 2012 @ 16:19
quote:
0s.gif Op woensdag 7 maart 2012 16:14 schreef GS42 het volgende:
Je komt wel altijd met leuke voorbeelden. :)
[ code verwijderd ]

Deze regel in ongedefinieerd, omdat C++ de argumenten van de functie in willekeurige volgorde mag evalueren.

Het klassieke voorbeeld is:
[ code verwijderd ]

Hierin weet je niet of functie(0, 1) aangeroepen wordt of functie(1, 0) omdat de compiler beide mag doen. In jouw geval worden de argumenten blijkbaar van rechts naar links verwerkt. Oplossing: minimaal 1 temp value gebruiken.
:|W, oke dat is idd wel stom :@ , bedankt voor de uitleg
GS42woensdag 7 maart 2012 @ 20:35
quote:
Ik ga maar eerst normaal C++ verder leren, zodat ik het mogelijk nut van C++11 kan inzien.
C++11 is gewoon 'normaal C++', he? Het betreft een nieuwe versie, geen alternatief op de standaard ofzo. Natuurlijk is het wel zo dat de veranderingen niet zo belangrijk zijn als je net de taal leert, maar onderscheid tussen 'normaal C++' en C++11 is er niet. ;)

quote:
Ik vind dat hele C++11 gedoe een beetje mosterd na de maaltijd om eerlijk te zijn. Er wordt gedaan alsof er allemaal nieuwe superfeatures in zitten, terwijl andere programmeertalen dit soort zaken jaren geleden al ondersteunden.
Wordt er zo over gehyped? Dat heb ik niet zo meegekregen.

Sommige dingen - auto, lambda's en range-based for loops bijvoorbeeld - zijn inderdaad syntactische suiker (zoals dat zo leuk wordt genoemd), namelijk manieren om iets mooier te schrijven zonder dat het verdere winst oplevert. De code wordt er misschien netter van, maar zeker niet sneller.

De twee dingen die echt de moeite waard zijn, vind ik de r-value references en de std::thread (met alle bijbehorende klasses). De r-value references kunnen bestaande code veel sneller maken en is dus relevant vanuit het oogpunt van efficientie, terwijl de multithread opties gewoon noodzakelijk zijn voor een moderne programmeertaal.
netolkdonderdag 8 maart 2012 @ 18:12
Oke, ik ben best benieuwd naar die std::thread dus ik denk ik update mn compiler....

ik gebruik mingw op windows 7 64-bit

en nu krijg ik dus die geweldige error libgmp-10.dll, nu heb ik op internet gevonden dat ik mingw aan Path (of PATH??) moest toevoegen ofzo, maar ik heb dus geen idee hoe dat moet -O-

Kan iemand mij hier mee helpen?
GS42donderdag 8 maart 2012 @ 18:57
Op deze link staat wel hoe je dingen in Win7 aan je path toe kunt voegen.

Let op dat je er geen dingen uit verwijdert en dat je nieuwe toevoeging achteraan zet. De entries worden gescheiden door punt-komma's. Waarschijnlijk voeg jij dus zoiets toe: ;C:/MinGW/bin/ (afhankelijk van waar je MinGW staat, natuurlijk).

Succes.
netolkdonderdag 8 maart 2012 @ 20:16
oke, na mn computer opnieuw te hebben opgestart bleek het wel te werken :P

nu krijg ik alleen wel een hoop error's die ik met de vorige compiler niet kreeg
waaronder dat class-members private zijn terwijl de functie die ze bewerkt friend is van die class
en dit soort error's:
1error: using temporary as lvalue [-fpermissive]
terwijl dit dus enum's zijn...

moet ik dingen dan anders gaan schrijven dan in C++ gebruikelijk is(/was)?
thabitdonderdag 8 maart 2012 @ 22:11
quote:
0s.gif Op donderdag 8 maart 2012 20:16 schreef netolk het volgende:
oke, na mn computer opnieuw te hebben opgestart bleek het wel te werken :P

nu krijg ik alleen wel een hoop error's die ik met de vorige compiler niet kreeg
waaronder dat class-members private zijn terwijl de functie die ze bewerkt friend is van die class
en dit soort error's:
[ code verwijderd ]

terwijl dit dus enum's zijn...

moet ik dingen dan anders gaan schrijven dan in C++ gebruikelijk is(/was)?
Kun je minimale code posten die dat soort foutmeldingen geeft? Je hebt grote kans dat de code sowieso al niet helemaal jofel was, maar dat de oude compiler het allemaal door de vingers zag.
netolkvrijdag 9 maart 2012 @ 08:13
quote:
0s.gif Op donderdag 8 maart 2012 22:11 schreef thabit het volgende:

[..]

Kun je minimale code posten die dat soort foutmeldingen geeft? Je hebt grote kans dat de code sowieso al niet helemaal jofel was, maar dat de oude compiler het allemaal door de vingers zag.
Ondertussen weet ik al waarom die class-members een error opleveren omdat ik een thread via windows maakte en dat nu oud is en niet meer ondersteund word :P

maar dit stukje code blijft wel een error geven:
1
2
3
4
5
6
7
8
9
10
11
struct Fluid{
        enum Fluid_Type{
            None,
            Fresh_Water,Salt_Water,
            Beer,Rum,
            Unknown
        }_TYPE;

}

_FLUID._TYPE = Fluid::None
dan geeft ie dus de volgende error:
1error: using temporary as lvalue [-fpermissive]
Computerfluisteraarvrijdag 9 maart 2012 @ 08:21
Een vraagje aan de mensen met verstand van C++:

Ik wil leren ontwikkelen in C++. Hoe zijn jullie begonnen? En kan ik C++ applicaties werkende krijgen op Linux én Windows?
netolkvrijdag 9 maart 2012 @ 08:34
quote:
5s.gif Op vrijdag 9 maart 2012 08:21 schreef Computerfluisteraar het volgende:
Een vraagje aan de mensen met verstand van C++:

Ik wil leren ontwikkelen in C++. Hoe zijn jullie begonnen? En kan ik C++ applicaties werkende krijgen op Linux én Windows?
Ik ben ooit begonnen met een tut te volgen om pengo (een spel) te maken. Echter leer je hier niet zo veel van en heb ik toen een boek gekocht

Het is inderdaad mogelijk om programma's voor zowel Linux al Windows te maken maar als je niet moeilijk wilt doen zal dat wel alleen in een console zijn
Computerfluisteraarvrijdag 9 maart 2012 @ 09:43
quote:
0s.gif Op vrijdag 9 maart 2012 08:34 schreef netolk het volgende:

[..]

Ik ben ooit begonnen met een tut te volgen om pengo (een spel) te maken. Echter leer je hier niet zo veel van en heb ik toen een boek gekocht

Het is inderdaad mogelijk om programma's voor zowel Linux al Windows te maken maar als je niet moeilijk wilt doen zal dat wel alleen in een console zijn
Is het onder Windows noodzakelijk Visual Studio te gebruiken? Verschilt de manier waarop je programma's schrijf onder Windows met Linux?

Bestaat er ook een Nederlandse uitgave van C++ voor Dummies?
Computerfluisteraarvrijdag 9 maart 2012 @ 09:49
Ik heb ook gehoord dat het goed is om te programmeren onder Linux, gezien je het systeem dan beter leert kennen. Hoe zit dat nou?
netolkvrijdag 9 maart 2012 @ 10:04
quote:
7s.gif Op vrijdag 9 maart 2012 09:49 schreef Computerfluisteraar het volgende:
Ik heb ook gehoord dat het goed is om te programmeren onder Linux, gezien je het systeem dan beter leert kennen. Hoe zit dat nou?
Ik zou gewoon met iets als minGW compiler werken en iets van notepad++ (als kladblok) en dan gewoon beginnen of idd een IDE gebruiken maar dan zou ik persoonlijk niet voor Visual studio gaan
netolkvrijdag 9 maart 2012 @ 10:05
Klopt het dat std::thread nog niet werkt voor g++ onder windows?
Computerfluisteraarvrijdag 9 maart 2012 @ 10:31
quote:
0s.gif Op vrijdag 9 maart 2012 10:04 schreef netolk het volgende:

[..]

Ik zou gewoon met iets als minGW compiler werken en iets van notepad++ (als kladblok) en dan gewoon beginnen of idd een IDE gebruiken maar dan zou ik persoonlijk niet voor Visual studio gaan
Oke, bedankt
FrankRicardvrijdag 9 maart 2012 @ 10:34
quote:
7s.gif Op vrijdag 9 maart 2012 09:49 schreef Computerfluisteraar het volgende:
Ik heb ook gehoord dat het goed is om te programmeren onder Linux, gezien je het systeem dan beter leert kennen. Hoe zit dat nou?
Heb je al kennis van andere talen? C, Java, Basic?
Windows of Linux maakt vrij weinig uit. Ligt er een beetje aan wat je wilt, code maken die op zowel Windows als Linux draait blijft lastig en zou ik in het begin niet proberen.
Onder Windows sowieso voor Visual Studio gaan. Dat is niet voor niets de standaard in de commerciele softwarebedrijven. Alleen al vanwege de debugger stukken handiger dan een notepad en een losse compiler.
De gratis Express-versie is voor een beginner prima.
Computerfluisteraarvrijdag 9 maart 2012 @ 12:35
quote:
0s.gif Op vrijdag 9 maart 2012 10:34 schreef FrankRicard het volgende:

[..]

Heb je al kennis van andere talen? C, Java, Basic?
Windows of Linux maakt vrij weinig uit. Ligt er een beetje aan wat je wilt, code maken die op zowel Windows als Linux draait blijft lastig en zou ik in het begin niet proberen.
Onder Windows sowieso voor Visual Studio gaan. Dat is niet voor niets de standaard in de commerciele softwarebedrijven. Alleen al vanwege de debugger stukken handiger dan een notepad en een losse compiler.
De gratis Express-versie is voor een beginner prima.
Nee, heb ik helaas niet. Ik denk dat ik standaard voor Linux wil gaan programmeren.
thabitvrijdag 9 maart 2012 @ 13:07
Bruce Eckel heeft wel een aardige online cursus. Nadeel is wel dat het op het "++"-gedeelte focust, en niet op het C-gedeelte.
Ofyles2zaterdag 10 maart 2012 @ 23:53
quote:
5s.gif Op vrijdag 9 maart 2012 08:21 schreef Computerfluisteraar het volgende:
Een vraagje aan de mensen met verstand van C++:

Ik wil leren ontwikkelen in C++. Hoe zijn jullie begonnen? En kan ik C++ applicaties werkende krijgen op Linux én Windows?
Ik zou voor Qt gaan.
netolkmaandag 12 maart 2012 @ 08:57
quote:
0s.gif Op zaterdag 10 maart 2012 23:53 schreef Ofyles2 het volgende:

[..]

Ik zou voor Qt gaan.
Welk deel snap je niet van ik wil ontwikkelen in C++???
FastFox91maandag 12 maart 2012 @ 09:09
quote:
0s.gif Op maandag 12 maart 2012 08:57 schreef netolk het volgende:

[..]

Welk deel snap je niet van ik wil ontwikkelen in C++???
In/Met Qt kan je c++-applicaties ontwikkelen die werken in Linux en Windows?
netolkmaandag 12 maart 2012 @ 13:47
quote:
0s.gif Op maandag 12 maart 2012 09:09 schreef FastFox91 het volgende:

[..]

In/Met Qt kan je c++-applicaties ontwikkelen die werken in Linux en Windows?
sorry :@ mijn fout, dacht dat het een andere taal was

misschien moet ik de volgende keer eerst is kijken voordat ik onzin lul...
FastFox91maandag 12 maart 2012 @ 18:15
Ik gebruik getopt om wat parameters binnen te halen zoals -h voor help en -s voor scan, maar ik heb nou er nog ééntje nodig voor save. De s is al 'bezet', dus ik wil van -s -scan maken. Moet ik per se een andere library gebruiken zoals getoptpp of kan ik wat aanpassen zodat zoiets ook mogelijk is met de standaard lib?
thabitmaandag 12 maart 2012 @ 18:22
quote:
0s.gif Op maandag 12 maart 2012 18:15 schreef FastFox91 het volgende:
Ik gebruik getopt om wat parameters binnen te halen zoals -h voor help en -s voor scan, maar ik heb nou er nog ééntje nodig voor save. De s is al 'bezet', dus ik wil van -s -scan maken. Moet ik per se een andere library gebruiken zoals getoptpp of kan ik wat aanpassen zodat zoiets ook mogelijk is met de standaard lib?
Die parameters worden direct aan main() gevoerd. Ik zie niet waarom je allerlei vage libraries daarvoor nodig zou hebben.
Computerfluisteraarmaandag 12 maart 2012 @ 18:24
quote:
0s.gif Op zaterdag 10 maart 2012 23:53 schreef Ofyles2 het volgende:

[..]

Ik zou voor Qt gaan.
Is dit de beste IDE of zijn er nog meer die geschikt zijn?
FastFox91maandag 12 maart 2012 @ 18:56
quote:
0s.gif Op maandag 12 maart 2012 18:24 schreef Computerfluisteraar het volgende:

[..]

Is dit de beste IDE of zijn er nog meer die geschikt zijn?
Qt is niet alleen een IDE, maar ook een UI cross-platform framework. http://qt.nokia.com/products/
FastFox91maandag 12 maart 2012 @ 18:56
Dicht!
[C(++)] voor dummies - Deel 4

[ Bericht 89% gewijzigd door FastFox91 op 12-03-2012 19:10:53 ]