Getestet in: Excel 365 v2509 · Excel 2021 · Excel 2019 · zuletzt geprüft am 07.06.2026
Kurz gesagt — ByRef ü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
- VBA Sub in Excel — Prozeduren, Aufruf & warum dein Makro nur ein Sub ist
- VBA Function in Excel — Rückgabewerte & eigene Arbeitsblattfunktionen
- VBA MsgBox in Excel — Ja/Nein, Buttons & die Klammer-Regel
- VBA For-Schleife in Excel — 8 Praxisbeispiele
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.
