Toon posts:

[C++] Sizeof Classproperty == 4?

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik ben net begonnen met classes in C++. Ik wil het aantal bytes weten van een property uit mijn class. Deze wil ik later toevoegen aan een nieuwe (char | string | tchar?!) met precies genoeg bytes.

Ik werk met de windows header maar ik heb even een klein voorbeeldje nagebootst met de iostream én windows header.

C++:
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
#include <windows.h>
#include <iostream>
using std::cout;

class cMyClass
{
    public:
        char *message;
        void doSomething();
};

void cMyClass::doSomething()
{
    int size = sizeof(this->message);

    cout << size; // Output: 4
}

int main()
{
    cMyClass Object;

    Object.message = "Hello World!";
    Object.doSomething();

    return 0;
}


Raar genoeg blijft `this->message` altijd 4 bytes (waarschijnlijk de grote van de verwijzing oid). Hoe kan ik toch de juiste grote opvragen?

Dan heb ik nog een ander vraagje over character sets. Ik weet dat `unicode` breder ondersteunt wordt maar ik weet niet echt goed hoe ik het moet toepassen en waar ik op moet letten. Mijn code werkt in `Multibyte` (ANSI?) maar in `Unicode` heb ik vaak last van foutmeldingen waarvan ik de oorzaak niet snap.

:|

  • Reptile209
  • Registratie: Juni 2001
  • Laatst online: 13:14

Reptile209

- gers -

Het sizeof() verhaal staat hier volgens mij wel aardig uitgelegd. Zoals je het nu doet, krijg je inderdaad de grootte van de pointer (4 bytes) terug en niet de lengte van de array die je zoekt. Ga maar eens aan de slag met het voorbeeld dat gegeven wordt en probeer, als oefening, je eigen strlen() te maken. Is prima voor je begrip van het geheel. :)
En don't shoot me als ik er nu (ook) naast zit, C is een tijd terug en C++ al helemaal ;)

Zo scherp als een voetbal!


Verwijderd

Topicstarter
Reptile209 schreef op dinsdag 03 oktober 2006 @ 21:47:
Het sizeof() verhaal staat hier volgens mij wel aardig uitgelegd. Zoals je het nu doet, krijg je inderdaad de grootte van de pointer (4 bytes) terug en niet de lengte van de array die je zoekt. Ga maar eens aan de slag met het voorbeeld dat gegeven wordt en probeer, als oefening, je eigen strlen() te maken. Is prima voor je begrip van het geheel. :)
En don't shoot me als ik er nu (ook) naast zit, C is een tijd terug en C++ al helemaal ;)
Bedankt Reptile209 :*) !

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 09:03
Je kunt op die manier geen strings toewijzen, tenminste niet hoe jij het hier wilt doen. Lees nog een de basis over pointers etc en dan vooral het stukje over char pointers.

Als je dat onder de knie hebt gebruik je gewoon std::string zodat je de lente op kunt vragen met std::string.length()

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


Verwijderd

Topicstarter
farlane schreef op dinsdag 03 oktober 2006 @ 22:05:
Je kunt op die manier geen strings toewijzen, tenminste niet hoe jij het hier wilt doen. Lees nog een de basis over pointers etc en dan vooral het stukje over char pointers.

Als je dat onder de knie hebt gebruik je gewoon std::string zodat je de lente op kunt vragen met std::string.length()
Strings werken volgens mij echt super. Alleen het probleem is dat ik die niet (rechtstreeks) kan gebruiken om bijvoorbeeld CreateService in te vullen. Want ik moet een long pointer constant string gebruiken (ik moet echt uitzoeken wat ze hier precies mee bedoelen).

Ik zal de basis doornemen over pointers. Bedankt voor je reactie iig.

  • truegrit
  • Registratie: Augustus 2004
  • Laatst online: 10-02 15:26
of je gebruikt de c_str() functie van de std::string class, die je een const char* terug geeft, die je wel kan casten (als dat al nodig is) naar een long iets

hallo


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:38
De verwarring komt waarschijnlijk omdat je zowel de Windows API (wat primair een C API is, en ontworpen voor oude versies van C) als C++ gebruikt. Windows heeft zowel ANSI-functies als UNICODE-functies; de eerste accepteren karakters en strings die één byte lang zijn (gewoon 'char' dus in C/C++) en geïnterpreteerd worden in de lokale code page, de tweede accepteren strings van twee bytes (toevallig komt dat overeen met wchar_t karakters voor alle Windows compilers die ik ken).

Als je de UNICODE functies wil gebruiken, zullen je strings dus uit wchar_t-karakters moeten staan. Je kunt daarbij ook C++ klassen als std::wstring gebruiken.

Wide string literals kun je declareren met een L ervoor. Dan kun je ze ook gebruiken zoals jij doet:
C:
1
wchar_t *str = L"Hello world!";


Over far pointers hoef je je geen zorgen te maken; alles wat in de Windows API als far pointer gedefinieerd is (met LP ervoor) is onder Win32 een gewone pointer. Daar hoeft dus niets geconverteerd te worden. (Echte far pointers met een segment en een 32-bits offset kun je ook wel maken, maar gebruik je niet in het flat memory model.)

[ Voor 18% gewijzigd door Soultaker op 03-10-2006 23:04 ]


Verwijderd

Topicstarter
Ik heb deze artikels doorgenomen over pointers en dynamic memory:

http://www.cplusplus.com/doc/tutorial/pointers.html
http://www.cplusplus.com/doc/tutorial/dynamic.html

Mijn eigen probeersel werkt in ieder geval zonder errors.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using std::cout;
using std::endl;

int main()
{
    char * string01 = "Hello ";
    char * string02 = "World!";

    char * name = new char;

    strcpy_s(name, strlen(string01) + 1, string01);
    strcat_s(name, strlen(name) + strlen(string02) + 1, string02);

    cout << name << endl;

    return 0;
}


Als ik dit wil gebruiken in mijn project. Dan krijg ik een error tijdens het uitvoeren van `char * name = new char`.

Unhandled exception at 0x7c81eb33 in pps.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x0012fb6c..


Heeft iemand enig idee wat ik hier fout doe?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:29

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ja, wellicht moet je die tutorials nog eens doornemen. Je alloceert nu namelijk 1 char, een string bestaat overduidelijk uit meerdere karakters. Je moet dus, voor je de string alloceert, eerst uitrekenen hoe lang hij moet zijn (niet vergeten de trailing '\0' mee te tellen), en dan een array van chars alloceren met die lengte.

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


  • MisterData
  • Registratie: September 2001
  • Laatst online: 11-02 08:33
Als je gewoon std::string (of std::wstring bij Unicode) gebruikt kun je op alle plaatsen waar een LPCSTR wordt gevraagd gewoon string.c_str() gebruiken:

C++:
1
2
3
std::string title = "titel!";
...
CreateWindow(...., title.c_str(), ...);


Zie je een LPSTR staan (niet-const dus), dan wordt er meestal geschreven naar de string die je als parameter opgeeft. Zit er een W in (LPCWSTR, LPWSTR) dan is het een 'wide' (=unicode) string en moet je wstring gebruiken :)

  • B-Man
  • Registratie: Februari 2000
  • Niet online
Het is voor mij ook al even geleden, maar ik zie een paar dingen:
- een enkele char hoef je niet met 'new' te creeeren
- je definieert een char *name, oftewel een pointer naar een array (*char == char[]), en je probeert er een enkele char aan toe te wijzen
- je hebt sowieso een char[] nodig als je "Hello " en "World!" aan elkaar wil plakken:

C:
1
2
3
4
5
6
7
8
9
10
11
char *s1 = "Hello ";
char *s2 = "World!";

// Als je nu al weet wat de lengte moet zijn:
char combined[13];

// Als je at runtime pas bepaalt wat de lengte moet zijn
char *combined = new char[ strlen(s1) + strlen(s2) + 1 ];

strcpy( combined, s1 );
strcat( combined, s2 );

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:29

.oisyn

Moderator Devschuur®

Demotivational Speaker

Een char* is geen char[]. Als functieparameter zijn ze equivalent, maar voor de rest is het allesbehalve hetzelfde.

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


  • B-Man
  • Registratie: Februari 2000
  • Niet online
.oisyn schreef op woensdag 04 oktober 2006 @ 13:21:
[...]

Een char* is geen char[]. Als functieparameter zijn ze equivalent, maar voor de rest is het allesbehalve hetzelfde.
Je hebt natuurlijk gelijk. Het helpt de TS mogelijk met het begrijpen van de link tussen arrays en pointers, that's all.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:29

.oisyn

Moderator Devschuur®

Demotivational Speaker

Sure, ik snap je intentie wel, maar doe dat dan niet door te zeggen dat pointers hetzelfde zijn als arrays, want dat introduceert alleen maar verwarring op een later moment :)

Voor de TS:
een variabele is natuurlijk verbonden aan een stukje geheugen waarin de data staat van die variabele.
Een array (char myarray[10]) is een rijtje van aaneengesloten variabelen, en effectief is een array dus een variabele die meerdere subvariabelen in zich heeft. Je kunt toegang verkrijgen tot de elementen dmv array subscription: myarray[3] = 'a'
Een pointer (char * myptr) is een variabele die wijst naar een andere variabele. Hij heeft dus zelf geheugen nodig waar de verwijzing in staat, en je hebt een stukje geheugen nodig waar die pointer naar verwijst (wat weer een bestaande variabele kan zijn, of een nieuw stuk geheugen wat je alloceert middels new). Toegang tot de verwijzing krijg je dmv pointer dereferencing: *myptr = 'a'.

Welnu, het punt waar B-Man het over heeft is het volgende: een array kan impliciet geconverteert worden naar een pointer (myptr = myarray). Je krijgt dan een pointer naar het eerste element in de array. Eveneens kun je de array subscription toepassen op een pointer: de "array" begint dan bij de variabele waar myptr naar verwijst. *myptr is dus hetzelfde als myptr[0], en eveneens is *(myptr + 3) hetzelfde als myptr[3].

Het belangrijke verschil tussen arrays en pointers is dus dat een array zelf geen geheugen nodig heeft voor de verwijzing, en dat je derhalve ook geen nieuwe verwijzing kunt toekennen aan een array. Een pointer heeft op zijn beurt weer een stuk geheugen nodig waarnaar verwezen moet worden, waar je zelf voor moet zorgen. En als je geheugen alloceert, niet vergeten dat geheugen ook weer vrij te geven! :)

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


Verwijderd

Topicstarter
Ik post even een stukje code uit de class waar ik mee bezig ben. Ik wil parameters toevoegen aan de property `filePath` en die opgeven in de createService functie.

C++:
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
void cApache::install()
{
    SC_HANDLE hSCM;
    SC_HANDLE hService;

    hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);

    char * parameters   = " -k runservice";
    char * execute      = new char[strlen(this->filePath) + strlen(parameters) + 1];

    strcpy(execute, this->filePath);
    strcat(execute, parameters);

    if(hSCM)
    {
        hService = CreateService(
            hSCM,
            this->serviceName,
            this->serviceName,
            READ_CONTROL,
            SERVICE_WIN32_OWN_PROCESS,
            SERVICE_DEMAND_START,
            SERVICE_ERROR_IGNORE,
            execute,
            NULL,
            NULL,
            NULL,
            NULL,
            NULL
        );

        CloseServiceHandle(hSCM);
        CloseServiceHandle(hService);
    }
}


Als ik de code debug dan krijg ik een error (bij regel met `char * execute`):
Unhandled exception at 0x7c81eb33 in pps.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x0012fb6c..
Ik zie niet wat ik verkeerd doe? Als ik `this->filePath` rechtstreeks bij CreateService invul dan werkt alles verder gewoon normaal (moet ik wel even de char * execute, strcpy en strcat van // voorzien).

Bedankt voor de reacties tot nu toe!

*Edit
.oisyn schreef op woensdag 04 oktober 2006 @ 14:24:En als je geheugen alloceert, niet vergeten dat geheugen ook weer vrij te geven! :)
Goede tip!

[ Voor 7% gewijzigd door Verwijderd op 04-10-2006 14:50 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:29

.oisyn

Moderator Devschuur®

Demotivational Speaker

Blijkbaar is er geen geheugen genoeg, wat ik raar vind. Je zegt dat het werkt zonder de het toevoegen van de parameters, waardoor ik er wel vanuit ga dat filePath naar een correcte string wijst. En zelfs als dat niet zo was dan zou je een access violation moeten krijgen, en zo niet dan nog kan strlen(filePath) niet zo lang zijn aangezien het praktisch onmogelijk is dat ie in het geheugen waar filePath naar wijst in de eerste miljoenen bytes geen 0 kan vinden (want dat is wat strlen() doet).

.edit: tenzij je de functie natuurlijk zo vaak aanroept dat je op een gegeven moment gewoon geen geheugen meer vrij hebt :P

[ Voor 11% gewijzigd door .oisyn op 04-10-2006 15:06 ]

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


Verwijderd

Topicstarter
.oisyn schreef op woensdag 04 oktober 2006 @ 15:06:
Blijkbaar is er geen geheugen genoeg, wat ik raar vind. Je zegt dat het werkt zonder de het toevoegen van de parameters, waardoor ik er wel vanuit ga dat filePath naar een correcte string wijst. En zelfs als dat niet zo was dan zou je een access violation moeten krijgen, en zo niet dan nog kan strlen(filePath) niet zo lang zijn aangezien het praktisch onmogelijk is dat ie in het geheugen waar filePath naar wijst in de eerste miljoenen bytes geen 0 kan vinden (want dat is wat strlen() doet).

.edit: tenzij je de functie natuurlijk zo vaak aanroept dat je op een gegeven moment gewoon geen geheugen meer vrij hebt :P
Als ik filePath gebruik in een messagebox dan krijg ik gewoon de volledige string terug. In debug mode zie ik dat `strlen(this->filePath)` de waarde 45 krijgt (wat volgens mij gewoon moet kloppen). De functie wordt maar één keer aangeroepen.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:29

.oisyn

Moderator Devschuur®

Demotivational Speaker

Heel wazig. Hoeveel mem gebruikt je proces in de task manager?

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


Verwijderd

Topicstarter
.oisyn schreef op woensdag 04 oktober 2006 @ 15:27:
Heel wazig. Hoeveel mem gebruikt je proces in de task manager?
Hoe moet ik dat testen? In debug mode gaat hij niet verder vanwege die error. En zonder debug crasht hij gelijk.

Ik gebruik trouwens Microsoft Visual C++ 2005 Express edition.

[ Voor 17% gewijzigd door Verwijderd op 04-10-2006 15:47 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:29

.oisyn

Moderator Devschuur®

Demotivational Speaker

Gewoon task manager openen en kijken hoeveel mem je proces gebruikt :?

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


Verwijderd

Topicstarter
.oisyn schreef op woensdag 04 oktober 2006 @ 16:12:
Gewoon task manager openen en kijken hoeveel mem je proces gebruikt :?
Ow zo, sorry. Hij gebruikt 2.288 kB, is dat veel?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:29

.oisyn

Moderator Devschuur®

Demotivational Speaker

Nee, dus ik gok dat je heap corrupt raakt. Waarschijnlijk gebruik je ergens een ongeinitialiseerde pointer, een pointer die wijst naar al vrijgegeven memory, schrijf je ergens buiten je buffers of geef je een stuk geheugen meerdere keren vrij.

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


Verwijderd

Topicstarter
.oisyn schreef op woensdag 04 oktober 2006 @ 16:32:
Nee, dus ik gok dat je heap corrupt raakt. Waarschijnlijk gebruik je ergens een ongeinitialiseerde pointer, een pointer die wijst naar al vrijgegeven memory, schrijf je ergens buiten je buffers of geef je een stuk geheugen meerdere keren vrij.
Ja, dat denk ik ook. Ik vond het al zo raar, ik had eerst op zo'n zelfde manier een string gemaakt (in main) en daarna probeerde ik het nog een keer en toen kreeg ik dezelfde error. Nu begrijp ik waarom! Bedankt voor je hulp _/-\o_.

Verwijderd

Topicstarter
Ik heb een klein vraagje over pointers. Ik gebruikt `wchar_t * service` om daar de naam van de service op te slaan en `wchar_t * executable` om het path naar het programma op te slaan. De method `install()` is afhankelijk van deze properties. Nu wil ik dus controleren of deze properties zijn geset.

Ik heb `wcslen()` en `sizeof()` geprobeerd maar met de eerste krijg ik een `Access violation` error :| en sizeof geeft altijd 4 terug en vervolgens ook een `Access violation` error :/.

Ik hoop dat iemand hier een oplossing voor weet :).

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:29

.oisyn

Moderator Devschuur®

Demotivational Speaker

sizeof geeft geen Access violation, je zal wel iets anders doen wat de access violation geeft. En als je wilt controleren of die dingen zijn geset moet je ze intialiseren met 0.

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


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 09:03
Verwijderd schreef op woensdag 11 oktober 2006 @ 12:25:
Ik heb een klein vraagje over pointers. Ik gebruikt `wchar_t * service` om daar de naam van de service op te slaan en `wchar_t * executable` om het path naar het programma op te slaan. De method `install()` is afhankelijk van deze properties. Nu wil ik dus controleren of deze properties zijn geset.

Ik heb `wcslen()` en `sizeof()` geprobeerd maar met de eerste krijg ik een `Access violation` error :| en sizeof geeft altijd 4 terug en vervolgens ook een `Access violation` error :/.

Ik hoop dat iemand hier een oplossing voor weet :).
Klinkt alsof je toch niet begrepen hebt wat nu het verschil is tussen een buffer die je alloceert en een losse pointer.

De enige reden die ik kan bedenken waarom sizeof( service ) 4 teruggeeft is dat het in jouw class een pointer is, en geen buffer. Als je die pointer niet naar een geldige buffer laat wijzen dan zal wsclen() waarschijnlijk een access violation genereren omdat dat itt sizeof een functie is.

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


  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

ik had een tijdje geleden een gelijkaardig probleem

C++:
1
2
3
4
5
void SomeFunction(std::string someString)
{
    someString += "blahblah";
    DoeIetsMet(someString);
}

ik kreeg dus een access violation tijdens een operatie met DoeIetsMet()
tijdens debuggen vond ik dat voor uitvoeren van += op de string alles in orde was, maar nadien was de string corrupt wat de access violation tijdens lezen verklaart.

Ik vond dit gedrag vaag aangezien std::string altijd zelf voor zijn geheugen (de/re)allocatie zorgt. Ook het passen by-value zou geen probleem mogen zijn aangezien intern wel de referentie doorgegeven wordt, maar tijdens de append-operatie een copy gemaakt wordt.

Iemand enig idee ?

ASSUME makes an ASS out of U and ME


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 10-12-2025
Pass-by-value maakt echt een kopie.

De AV kan ook komen omdat je voor de += je heap hebt gecorrumpeerd.

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


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14:29

.oisyn

Moderator Devschuur®

Demotivational Speaker

VC6 deed geloof ik nog iets met refcounted buffers.

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

Pagina: 1