Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

30.08.2013, 14:16

MemGetEntry

Hallo,

kann mir bei dieser Funktion jemand ein bisschen auf die Sprünge helfen? So ganz fit bin ich in Hardcore-Zeigerarithmetik dann wohl doch nicht...

- Wozu der cast von void* nach BYTE* ?
- Warum muss die Zeigergröße abgezogen werden, wenn z.B. die Startadresse der Texturliste in pMemory reinkommt? Wird dann nicht auf irgendwas Unbestimmtes vor den eigentlich Daten gezeigt?
- Hätte man statt der letzten (signifikaten) Zeile nicht auch ppOut = (tbListEntry<tbMemListEntry>**)(pMemory) schreiben können bzw. wäre der cast nicht sogar automatisch passiert?

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
tbResult MemGetEntry(void* pMemory,
                     tbListEntry<tbMemListEntry>** ppOut)
{
    // Parameter prüfen
    if(pMemory == NULL) TB_ERROR_NULL_POINTER("pMemory", TB_ERROR);
    if(ppOut == NULL)   TB_ERROR_NULL_POINTER("ppOut", TB_ERROR);

    
    // Speicherbereich prüfen
    if(!tbMemIsValid(pMemory)) return TB_ERROR;

    // Vom angegebenen Zeiger muss die Größe eines Zeigers auf eine
    // tbMemListEntry-Struktur abgezogen werden.
    pMemory = (BYTE*)(pMemory) - sizeof(tbListEntry<tbMemListEntry>*);

    // pMemory zeigt jetzt auf einen Zeiger auf die zum Speicher
    // gehörige Listenstruktur - dieser wird geliefert.
    *ppOut = *((tbListEntry<tbMemListEntry>**)(pMemory));

    return TB_OK;
}

Tobiking

1x Rätselkönig

  • Private Nachricht senden

2

30.08.2013, 18:06

- Wozu der cast von void* nach BYTE* ?

Einen Zeiger verschiebt man immer um ein Vielfaches des Typs auf den er zeigt. Void hat aber theoretisch keine Größe, weswegen es im Allgemeinen nicht möglich ist void* für Zeigerarithmetik zu verwenden.

- Warum muss die Zeigergröße abgezogen werden, wenn z.B. die Startadresse der Texturliste in pMemory reinkommt? Wird dann nicht auf irgendwas Unbestimmtes vor den eigentlich Daten gezeigt?

Im Prinzip hast du recht. In einem anderen Snippet habe ich aber gesehen, dass pMemory vor dem übergeben an diese Funktion um ebend diesen Wert nach vorne geschoben wurde.

- Hätte man statt der letzten (signifikaten) Zeile nicht auch ppOut = (tbListEntry<tbMemListEntry>**)(pMemory) schreiben können bzw. wäre der cast nicht sogar automatisch passiert?

Dein Code überschreibt ppOut mit einem neuen Doppelzeiger. Da der Parameter ppOut aber "per Value" übergeben wurde, überschreibst du damit nur eine Kopie.
Der originale Code überschreibt den Zeiger auf den ppOut zeigt (mit dem Zeiger der auf pMemory zeigt). Der Zeiger auf den ppOut zeigt ist hier "per Reference" übergeben und wird auf das veränderte pMemory umgesetzt.

3

02.09.2013, 12:24

1) Ich hab das gerade mal ausprobiert und sobald man auf void-Zeigern rumarithmetikt will der Compiler tatsächlich nicht mehr. In dem Ausdruck speziell braucht er die Größe aber doch eigentlich gar nicht, weil er nur die Adresse des void-Zeigers benutzt und da 4 Byte Zeigergröße draufaddiert. Das wäre also doch höchstens bei so was wie pMemory++ von Belang?!

2) Mein Callstack ist:

C-/C++-Quelltext

1
2
3
4
tbResult tbTextureManager::SetListSize(int iNewSize)
tbMemReAlloc(m_pTextureList, iNewSize * sizeof(tbTextureListEntry))
tbMemGetSize(pMemory);
MemGetEntry(pMemory, &pMemoryListEntry)


und ich seh da keine Zeigermanipulation vorher. In SetListSize wird bei existierende Texturliste deren Startadresse an tbMemReAlloc übergeben und dieser Zeiger in allen weiteren Calls nur durchgereicht.

3) Auch das hab ich überprüft und ja, hier:

C-/C++-Quelltext

1
2
3
4
5
6
int five = 5;

void foo(int* x)
{
  x = &five;
}


tritt also der gleiche Effekt auf wie hier:

C-/C++-Quelltext

1
2
3
4
void bar(int x)
{
  x = 5;
}


D.h. also, Adressvariablen sind auch nur Kopien, die nach der Funktion wieder im Nirwana verschwinden? - Interessant, vor allen Dingen wenn man durch Doppelzeiger noch vollends verwirrt wird. :)

patrick246

Treue Seele

Beiträge: 328

Wohnort: nahe Heilbronn/BW

Beruf: TG Profil Informatik-Schüler

  • Private Nachricht senden

4

02.09.2013, 12:57

Zu 3:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
int five = 5;
void foo(int*& x)
{
    x = &five;
}

int main()
{
    int *x = nullptr;
    foo(x);
    std::cout << x << std::endl;
}

würde funktionieren, und zwar ohne Doppelpointer

Tobiking

1x Rätselkönig

  • Private Nachricht senden

5

02.09.2013, 14:05

weil er nur die Adresse des void-Zeigers benutzt und da 4 Byte Zeigergröße draufaddiert

Das sizeof gibt unabhängig von der Bedeutung erstmal nur eine Zahl zurück. Auf einem 32 Bit System steht da im Prinzip "pMemory - 4". Damit wird pMemory um 4 * Größe des Zeigertyps verschoben. Wäre pMemory ein int* (mit sizeof(int) = 4), würde es um 16 Byte verschoben.


2) Mein Callstack ist:

C-/C++-Quelltext

1
2
3
4
tbResult tbTextureManager::SetListSize(int iNewSize)
tbMemReAlloc(m_pTextureList, iNewSize * sizeof(tbTextureListEntry))
tbMemGetSize(pMemory);
MemGetEntry(pMemory, &pMemoryListEntry)


und ich seh da keine Zeigermanipulation vorher. In SetListSize wird bei existierende Texturliste deren Startadresse an tbMemReAlloc übergeben und dieser Zeiger in allen weiteren Calls nur durchgereicht.

Ich habe den Quellcode leider nicht. Ich habe nur per Google das 3. Snippet unter Textur aus Speicher für Font erstellen *edit* gesehen. Dort wird beim new extra mehr Platz reserviert für den Zeiger.


D.h. also, Adressvariablen sind auch nur Kopien, die nach der Funktion wieder im Nirwana verschwinden? - Interessant, vor allen Dingen wenn man durch Doppelzeiger noch vollends verwirrt wird. :)

Genau. Das ist praktisch die Per Value/Reference Semantik stumpf auf den Zeiger als Variable angewendet.

6

02.09.2013, 14:05

Ja, stimmt. Zeigerreferenzen sind mir unter initialen WTFs auch schon über den Weg gelaufen. ;)
Würde dementsprechend dann auch das funktionieren?

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
tbResult MemGetEntry(void* pMemory,
                     tbListEntry<tbMemListEntry>**& ppOut)
{
    //...
    
    ppOut = (tbListEntry<tbMemListEntry>**)(pMemory);

    return TB_OK;
}

Werbeanzeige