🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA ByRef vs ByVal in Excel — Warum sich deine Variable nach einem Aufruf geändert hat

|

VBA ByRef vs ByVal in Excel — Warum sich deine Variable nach einem Aufruf geändert hat

Getestet in: Excel 365 v2509 · Excel 2021 · Excel 2019 · zuletzt geprüft am 07.06.2026

Kurz gesagtByRef übergibt die Originalvariable, eine Prozedur kann sie also ändern. ByVal übergibt eine Kopie, das Original bleibt sicher. VBA nutzt standardmäßig ByRef — deshalb kann sich eine Variable nach einem Aufruf unter deinen Händen verändern:

Sub Demo()
    Dim n As Long: n = 10
    PlusEins n
    MsgBox n            ' 11 — n hat sich wirklich geändert, weil ByRef der Standard ist
End Sub

Sub PlusEins(ByRef x As Long)   ' ByRef: x IST n — Schreiben in x schreibt in n
    x = x + 1
End Sub
' Ändere oben „ByRef" zu „ByVal", und MsgBox zeigt 10 — das Original bleibt unberührt.

Dieser Standard — ByRef, wenn du nichts anderes sagst — ist die Quelle fast jedes „Warum hat sich meine Variable geändert?"-Fehlers in VBA. So lässt du dich davon nie wieder überraschen.

Das Denkmodell: Original gegen Fotokopie

Wenn du eine Variable an eine Prozedur übergibst, gibst du ihr Zugriff auf deine Daten. Dafür gibt es zwei Wege:

  • ByRef = du reichst dein echtes Notizbuch weiter. Die Prozedur schreibt auf die echten Seiten. Gibt sie das Buch zurück, stehen deine Änderungen darin. (Ref = Referenz = „ein Verweis auf das Original".)
  • ByVal = du reichst eine Fotokopie einer Seite weiter. Die Prozedur darf die Kopie vollkritzeln; dein Notizbuch bleibt unverändert. (Val = Value/Wert = „eine Momentaufnahme des Inhalts".)

Dieselbe Idee, zwei Folgen. Bei ByRef bleiben Änderungen in der Prozedur. Bei ByVal verschwinden sie, sobald die Prozedur endet. Alles andere ist Detail.

Die eine Regel: Der Standard ist ByRef, und das ist die Falle

Das ist der Fakt, der beißt: Schreibst du nicht ByVal, nutzt VBA ByRef. Diese beiden Deklarationen sind identisch:

Sub Verarbeiten(x As Long)        ' kein Schlüsselwort...
Sub Verarbeiten(ByRef x As Long)  ' ...bedeutet genau das hier

Jeder unmarkierte Parameter, den du je geschrieben hast, ist also still eine Übergabe als Referenz. Meist macht das nichts — aber an dem Tag, an dem ein Helfer still den Zähler hochzählt, den du ihm übergeben hast, hast du einen Fehler, der unmöglich aussieht: Die Variable hat sich geändert, und die Zeile, die sie geändert hat, steht in einer anderen Prozedur. Wer von Python, Java oder C# kommt (wo Primitive als Wert übergeben werden), empfindet das als verkehrt herum — zu Recht: VBA ist hier der Sonderfall.

Die Gewohnheit gegen die ganze Fehlerklasse: Schreibe ByVal ausdrücklich an jeden Parameter und wechsle nur dann zu ByRef, wenn du wirklich „gib einen Wert zurück" meinst. Dein zukünftiges Ich, das um 18 Uhr debuggt, wird es dir danken.

' Standardmäßig sicher — die Variablen der Aufrufer sind geschützt:
Sub LogZeile(ByVal zeilenNr As Long, ByVal text As String)
    Debug.Print zeilenNr & ": " & text
End Sub

ByRef mit Absicht: mehr als eine Antwort

ByRef ist kein zu meidender Fehler — es ist ein Werkzeug. Eine Function gibt genau einen Wert zurück. Wenn du wirklich brauchst, dass eine Prozedur zwei oder mehr Ergebnisse zurückreicht, sind ByRef-Ausgabeparameter der saubere, klassische Weg:

Sub MinMax(daten As Range, ByRef lo As Double, ByRef hi As Double)
    lo = Application.Min(daten)
    hi = Application.Max(daten)
End Sub

Sub Benutze()
    Dim tief As Double, hoch As Double
    MinMax Range("A1:A100"), tief, hoch   ' füllt BEIDE Variablen
    MsgBox "Bereich: " & tief & " bis " & hoch
End Sub

MinMax gibt über seinen Namen nichts zurück, reicht aber zwei Zahlen zurück, indem es in tief und hoch des Aufrufers schreibt. Genau dafür ist ByRef gemacht. Faustregel: ByVal für Eingaben, ByRef für Ausgaben. Markiere sie bewusst, und die Signatur dokumentiert sich selbst.

Der Stolperstein, der ByRef in ByVal kippt: zusätzliche Klammern

Dieser ist wirklich heimtückisch und hängt direkt damit zusammen, wie du ein Sub aufrufst. Ein Argument in zusätzliche Klammern zu setzen, erzwingt, dass es zuerst als Ausdruck ausgewertet wird — VBA übergibt also das Ergebnis, also eine Kopie, und hebelt ByRef aus:

PlusEins n        ' ByRef wie gewollt → n wird 11
PlusEins (n)      ' das (n) wird zuerst ausgewertet → eine KOPIE → n bleibt 10
Call PlusEins(n)  ' hier gehören die Klammern zu Call → wieder ByRef → n wird 11

PlusEins (n) und Call PlusEins(n) sehen fast gleich aus, verhalten sich aber gegensätzlich. Weigert sich ein ByRef-Parameter rätselhaft, die Variable des Aufrufers zu aktualisieren, such nach einem verirrten Klammernpaar ums Argument. Das ist zugleich ein bewusster Trick: Willst du eine Variable schützen, obwohl die Prozedur ByRef ist, ist ( ) darum ein schnelles lokales Übersteuern.

Die Feinheit, die alle falsch verstehen: Objekte ignorieren den Unterschied

ByVal schützt einfache Werte — Zahlen, Zeichenketten, Wahrheitswerte, Datumswerte. Es kopiert kein Objekt tief. Bei einem Range, Worksheet oder Workbook übergibt selbst ByVal eine Kopie des Verweises, und diese Kopie zeigt weiter auf dasselbe lebende Objekt:

Sub Leeren(ByVal rng As Range)  ' ByVal, und doch...
    rng.ClearContents           ' ...leert das wirklich die Zellen des Aufrufers
End Sub

Man greift zu ByVal in der Erwartung, es „schütze" einen Range, und ist verblüfft, dass die Zellen trotzdem geleert werden. Die Wahrheit: ByVal auf einem Objekt hält dich nur davon ab, die Variable in der Prozedur auf ein anderes Objekt umzubiegen — den Inhalt des Objekts schützt es nie. Willst du unberührte Daten, kopier die Werte selbst heraus; das Schlüsselwort tut es nicht für dich.

Häufige ByRef-/ByVal-Fehler (und die Lösung)

Symptom Ursache Lösung
Variable hat sich nach einem Aufruf geändert Standard ByRef ließ die Prozedur sie verändern Parameter ByVal deklarieren oder drinnen nicht mehr ändern
ByRef-Parameter aktualisiert den Aufrufer nicht Argument in Extra-Klammern: MeinSub (x) Klammern entfernen (oder Call MeinSub(x) nutzen)
„ByRef-Argumenttyp unverträglich" Variablentyp des Aufrufers ≠ deklarierter Parametertyp Typen angleichen, oder ByVal übergeben, damit VBA eine Kopie umwandelt
ByVal-Range wurde trotzdem geändert Objekte übergeben auch bei ByVal einen Verweis Werte vor dem Aufruf herauskopieren; das Schlüsselwort schützt den Inhalt nicht
Zwei Rückgaben nötig, Globale benutzt Eine Function gibt nur einen Wert zurück ByRef-Ausgabeparameter — das vorgesehene Werkzeug
Rekursion läuft aus dem Speicher Großer Wert per ByVal wird je Ebene kopiert Große Arrays ByRef übergeben, um das Kopieren je Aufruf zu vermeiden

Wenn das Herumreichen von Daten die Last ist — beschreib das Ergebnis

ByRef/ByVal ist genau die Art Detail, die VBA wie ein Minenfeld wirken lässt: korrekt, aber fummelig, und eine verirrte Klammer von einem Fehler entfernt. Ist das eigentliche Ziel „teile dieses Blatt nach Region und schicke jeder Führungskraft ihren Ausschnitt", solltest du nicht darüber nachdenken, wie Argumente kopiert werden. ExcelMaster Agent nimmt das Ziel in Klartext-Deutsch und liefert das Ergebnis — keine Parameter, keine Übergabekonvention, keine Fußangeln. Kostenlos testen →

Verwandte Anleitungen

FAQ

Was ist der Unterschied zwischen ByRef und ByVal in VBA? ByRef übergibt einen Verweis auf die Originalvariable, Änderungen in der Prozedur bleiben also nach der Rückkehr erhalten. ByVal übergibt eine Kopie, das Original wird nie berührt. Das Schlüsselwort steuert, ob eine Prozedur die Variable des Aufrufers ändern darf.

Ist VBA standardmäßig ByRef oder ByVal? Standardmäßig ByRef. Schreibst du einen Parameter ohne Schlüsselwort — Sub Verarbeiten(x As Long) — behandelt VBA ihn als ByRef, die Prozedur kann die übergebene Variable also ändern. Das ist das Gegenteil der meisten modernen Sprachen und eine häufige Fehlerquelle.

Warum hat sich meine Variable nach dem Aufruf eines Subs geändert? Weil der Parameter ByRef war (der Standard) und die Prozedur ihn geändert hat. Um die Variable zu schützen, deklariere den Parameter ByVal, das eine Kopie übergibt. Alternativ setzt du das Argument an der Aufrufstelle in Extra-Klammern — MeinSub (x) — um eine Kopie zu erzwingen.

Wann sollte ich in VBA ByRef nutzen? Nutze ByRef bewusst, wenn eine Prozedur einen Wert zurück an den Aufrufer geben soll — etwa zwei oder mehr Ergebnisse über Ausgabeparameter. Gute Regel: ByVal für Eingaben, ByRef für Ausgaben.

Schützt ByVal ein Range- oder Worksheet-Objekt? Nein. ByVal kopiert nur den Verweis, nicht das Objekt — die Kopie zeigt weiter auf denselben lebenden Range bzw. dasselbe Worksheet, das Ändern des Inhalts trifft also weiter den Aufrufer. ByVal auf einem Objekt verhindert nur, dass du die Variable in der Prozedur auf ein anderes Objekt umlegst.

Was macht Call MeinSub(x) anders als MeinSub (x)? Mit Call gehören die Klammern zur Call-Syntax, x wird also weiter ByRef übergeben. Ohne Call ist (x) ein Ausdruck, der zuerst ausgewertet wird, es wird also eine Kopie übergeben — und ByRef ausgehebelt. Sie sehen gleich aus, verhalten sich aber gegensätzlich.