Die Community zu .NET und Classic VB.
Menü

Zeiger in VB - Seite 3

 von 

Eine Warteschlange
Nächste Seite >>
Einleitung
<< Vorherige Seite

Das Heap-Modul  

Der Code

Es folgt ein allgemeiner Code des Heap-Moduls. %DataType% steht dabei stellvertretend und muß durch den gewünschten Datentyp ersetzt werden.

Option Explicit

Private Type MemSeg
    Flag    As Byte
    Seg     As %DataType%
End Type
'----------------------------------------------------

Public Heap()       As MemSeg
Private m_HeapSize  As Long
Private m_Dynamic   As Boolean
Private m_Steps     As Long
'----------------------------------------------------

'----------------------------------------------------
' SetHeapSize
' definiert die logische Größe des Heaps
' - [IN] Size As Long: Anzahl der Segmente des Heaps
'----------------------------------------------------
Public Sub SetHeapSize(Size As Long)
    m_HeapSize = Size
    ReDim Heap(1 To Size)
End Sub

'----------------------------------------------------
' ReSize
' Ändert die Größe des Heaps -- dabei wird der
' aktuelle Inhalt beibehalten
' - [IN] Size As Long: Neue Anzahl von Segmenten
'----------------------------------------------------
Public Sub ReSize(Size As Long)
    m_HeapSize = Size
    ReDim Preserve Heap(1 To Size)
End Sub

'----------------------------------------------------
' SetDynamic
' legt fest, ob der Heap dynamisch (skalierbar) ist
' - [IN] Enabled As Boolean: Dynamik an/aus
' - [IN] Steps As Long: Vergrößerungsschritt
'----------------------------------------------------
Public Sub SetDynamic(Enabled As Boolean, Steps As Long)
    m_Dynamic = Enabled
    m_Steps = Steps
End Sub

'----------------------------------------------------
' Alloc As Long
' Reserviert Speicher auf dem Heap
' - gibt einen Zeiger auf das reservierte Segment zurück
'----------------------------------------------------
Public Function Alloc() As Long
    For Alloc = 1 To m_HeapSize
        If Heap(Alloc).Flag = 0 Then
            Heap(Alloc).Flag = 1
            Exit Function
        End If
    Next Alloc

    If m_Dynamic Then
        Call ReSize(m_HeapSize + 10)
        Heap(Alloc).Flag = 1
    Else
        Call Err.Raise(vbObjectError, "GC::Alloc", "Heap overflow")
    End If
End Function

'----------------------------------------------------
' Free
' gibt ein Heap-Segment frei
' - [IN] Segment As Long: Adresse des Segments
'----------------------------------------------------
Public Sub Free(Segment As Long)
    Heap(Segment).Flag = 0
End Sub

Listing 3

Etwas fällt ins Auge: die Kürze des Codes. Es wird ja auch nicht viel gemacht: die Funktion Alloc() sucht lediglich nach dem ersten freien Speichersegment im Heap-Feld. Dieses erkennt er dadurch, dass die Eigenschaft Flag null ist. Alloc() setzt sie nun auf eins und gibt den Feldindex zurück: unser "Zeiger". Free() macht noch viel weniger: es setzt lediglich den Flag des angegebenen Feldeintrags auf null.

Dieser Code gibt uns Werkzeuge in die Hand, um einen Heap zu erzeugen (SetHeapSize()), Speicher zu reservieren (Alloc()) und diesen auch wieder zu befreien (Free()).

Einfaches Beispiel

Man kann nun einen C++-Code, der Zeiger verwendet, 1:1 nach VB übersetzen:

int main(void)
{
    int* Int1;
    int* Int2;
    
    Int1 = new int();
    Int2 = Int1;
    
    *Int1 = 5;
    cout << "Int1: " << *Int1 << endl;
    cout << "Int2: " << *Int2 << endl;
    
    delete Int1;
    return 0;
}

Listing 4

Dieser Code ergibt in VB (Voraussetzung: wir haben einen Long-Heap erstellt):

Sub Main()
    Call SetHeapSize(10)

    Dim Lng1 As Long
    Dim Lng2 As Long

    Lng1 = Alloc()
    Lng2 = Lng1

    Heap(Lng1).Seg = 5
    Debug.Print "Lng1: "; Heap(Lng1).Seg
    Debug.Print "Lng2: "; Heap(Lng2).Seg

    Call Free(Lng1)
End Sub

Listing 5

Einen grundlegenden Unterschied gibt es zwischen den C++-Zeigern und unseren VB-"Zeigern": Zeiger in C++ sind absolut. Die absolute Adresse einer Variable kann man in VB ebenfalls über einen Umweg ermitteln, die VBA-Bibliothek sieht dafür die undokumentierten Funktionen VarPtr(), StrPtr() und ObjPtr() vor. Allerdings kann VB mit diesen Zeigern nicht umgehen, man braucht APIs, um mit ihnen arbeiten zu können. Wir arbeiten mit Feldindizes. Ein Feldindex ist in Wahrheit nichts anderes als eine relative Speicheradresse, relativ nämlich zum ersten Element des Feldes. Diese Adressen sind selbstverständlich unbenutzbar in APIs, aber für unsere Zwecke reichen sie vollauf, da sie die selben Eigenschaften wie absolute Zeiger besitzen.

Achtung : Wie auch in C++ wird hier per Alloc() zwar Speicherplatz reserviert, nicht aber geleert! Das heißt, dass der reservierte Speicherplatz durchaus bereits einen Wert enthalten kann.

An dem Code fällt auf, dass der Derefenzierungsoperator aus C++, das Asterisk (*) durch Heap(...).Seg ersetzt wird. Das sieht umständlich aus (ist es auch), lässt sich aber leider nicht verhindern. Für Codes wie den obigen wäre die Benutzung des Heaps also recht umständlich. In einigen Gebieten jedoch wird Programmierung durch Benutzung des Heaps vereinfacht.
Oft wird man im Internet zum Beispiel Algorithmen in C++ (oder C) finden, die bestimmte Programmiertechniken umsetzen. Viele dieser Algorithmen verwenden Zeiger, was die Übersetzung der Algorithmen nach VB erschwert. Mithilfe des Heaps ist das hingegen kein Problem.

Ein Beispiel für einen solchen Algorithmus ist eine spezielle Listenklasse, eine so genannte Warteschlange. Hierbei handelt es sich um einen Datenbehälter ("Container"), in den man Daten hineingeben und und aus dem man Daten herausnehmen kann. Das besondere an der Warteschlange ist, dass man grundsätzlich nur hinten Daten anreihen kann und nur vorne Daten wegnehmen: In der selben Reihenfolge, in der man die Daten einfügt, kommen sie auch wieder heraus.

Die Implementierung einer solchen Struktur ist in VB ohne API oder Klassen nicht möglich, da Zeiger benötigt werden. Wenn man Klassen für die einzelnen Elemente der Warteschlange verwendet, hat man jedoch einen ungeheuren Geschwindigkeitsnachteil. Hier schafft unser Heap Abhilfe.

Archivierte Nutzerkommentare 

Klicken Sie diesen Text an, wenn Sie die 4 archivierten Kommentare ansehen möchten.
Diese stammen noch von der Zeit, als es noch keine direkte Forenunterstützung für Fragen und Kommentare zu einzelnen Artikeln gab.
Aus Gründen der Vollständigkeit können Sie sich die ausgeblendeten Kommentare zu diesem Artikel aber gerne weiterhin ansehen.

Kommentar von Cyron am 27.10.2008 um 16:10

Die folgende Zeile ist fehlerhaft:

Call ReSize(m_HeapSize + 10)

sie sollte wohl eher

Call ReSize(m_HeapSize + m_Steps)

lauten.

LG Cyron

Kommentar von Christian am 05.10.2005 um 09:19

Das Tutorial ist wirklich gut, wenn man Zeiger unter VB emulieren will.

Ich frage mich aber, warum Microsoft die Zeiger nicht in VB integriert hat. Das finde ich bei der Programmierung (und gerade bei der dynamischen Speicherverwaltung) das Beste, was es diesbezüglich gibt.

Da sage ich nur:
"Ein Hoch auf C/C++ und die Win32-API!" :-)

Kommentar von Konrad L. M. Rudolph am 17.02.2005 um 16:40

Peter,

auf diese Funktionen weise ich aber auch explizit in dem Tutorial hin!

Kommentar von Peter Hoyer am 23.10.2004 um 14:27

Ganz verzweifelt über ein Pointerproblem, dass ich nicht über die Heap-Lösung behandeln konnte, weil es sich um Adreesen von zwei externen Objekten handelte, die ich vergleichen wollte, habe ich den folgenden interssanten Artikel über undokumentierte VB Funktionen gefunden:

http://www.vb-magazin.de/new/contentid-122.html

Nächste Seite >>
Eine Warteschlange
<< Vorherige Seite
Einleitung