Parameter (Informatik)Parameter – (deutsch) auch Übergabewerte genannt – sind in der Informatik Variablen, durch die ein Computerprogramm (oft ein Unterprogramm) auf die Verarbeitung bestimmter Werte „eingestellt“ werden kann. Parameter sind also programmextern gesetzte Einflussfaktoren; sie werden insbesondere beim Aufruf von Unterprogrammen verwendet, um diesen ‚mitzuteilen‘, welche Daten/Werte sie verarbeiten sollen und ggf. wie. Durch Parametrisierung können Programme in ihrer Anwendung flexibilisiert werden, ohne dass das Programm dazu neu erstellt oder geändert werden muss. Welche Sachverhalte eingestellt werden können, muss bei der Erstellung des Programms (als Anforderung) festgelegt werden. Parameter können z. B. bestimmte Grenzwerte/Auswahlbedingungen (für Beträge, ein Datum oder ähnliches) oder zu verwendende Texte sein oder auch das „Was“ und das „Wie“ der Verarbeitung steuern (z. B. Prüfung X vornehmen – ja/nein). Begrifflich wird unterschieden zwischen „formalen Parametern“ (= als Teil der Funktionsdefinition im Programmcode; Bsp.: Wird beim Aufruf des (Unter-)Programms nicht für jeden Parameter ein Argument übergeben, kann dieses eine beim Erstellen des Programms festgelegte Standardannahme verwenden oder (je nach Implementierung) die Verarbeitung wegen fehlender Parameter abbrechen. Zweck von Parametern![]()
Parameter sind aus Sicht des Systembegriffs Inputdaten; sie unterscheiden sich jedoch von normalen Eingabedaten z. B. wie folgt:
Unterschiedliche Parameter-BegriffeParameter werden in unterschiedlichen Funktionen in der Informatik verwendet:
Bei Verwendung mehrerer Parameter ist es wichtig, die einzelnen Parameter identifizieren und unterscheiden zu können. Hierzu gibt es zwei Erkennungsmethoden:
Ob leere Parameter erlaubt sind und wie dies zu behandeln ist, z. B. leere Zeichenkette oder Standardannahme (englisch default argument), ist durch das Programm zu behandeln. Ebenso muss für beide Varianten festgelegt/vereinbart sein, in welchem Format sie anzugeben sind; im Beispiel: „hh:mm“, jeweils 2 Stellen, getrennt durch einen Doppelpunkt. Weiterhin lassen sich Parameter unterscheiden nach:
Beispiele für Parameter
In weitestem Sinn sind auch Computerbefehle (in allen Programmiersprachen und auch in Maschinensprache) Parameter: Sie enthalten einen Funktionscode plus Adressen, Längen und so weiter für die zu verarbeitenden Daten. Die Angaben werden vom Steuerwerk des Computers interpretiert und decodiert und entsprechend ausgeführt. Ein konkretes Beispiel für die Anwendung von Parametern: Als Teil einer Anwendung zur Verwaltung von Rechnungen soll ein Programm entstehen, das für die Benutzer Rechnungen in einer Liste ausgibt. Als fachliche Vorgabe wurde festgelegt, dass in dieser Liste alle Rechnungen ausgewiesen werden, die noch nicht bezahlt sind und die älter als 1 Monat sind, berechnet zum Zeitpunkt des Programmlaufs.
Medien zur Parameterübergabe
Je nach Medium werden Parameter mit unterschiedlichen Verfahren erfasst, externe Parameter häufig mithilfe von Standard- oder individuellen Editoren. Parameter für Dialogprogramme können, wenn dies im Programm vorgesehen ist, vom Benutzer direkt über Bildschirm und Tastatur eingegeben werden. Parameter bei UnterprogrammenEine essentielle Bedeutung haben Parameter in Verbindung mit der Verwendung von Unterprogrammen. Diese verarbeiten Daten und liefern Werte zurück, die meist zu den sie aufrufenden Programmen gehören. Um einem Unterprogramm (das die Daten des rufenden Programms grundsätzlich nicht 'kennt') die Teilmenge an Daten mitzuteilen, die es verarbeiten muss, verwendet man beim Aufruf des Unterprogramms bestimmte Techniken, die in höheren Programmiersprachen durch eine sogenannte formale Parameterliste abgebildet werden. Dieser Ausdruck wurde bereits in den 1960er Jahren für die damals als Lehrbeispiel entstandene Sprache ALGOL benutzt und ist noch heute üblich. Die Begriffe Parameter oder Argument werden in diesem Kontext oft synonym verwendet, wobei sich „Parameter“ genau genommen auf die Funktionsdefinition bezieht, „Argument“ hingegen auf den tatsächlichen Aufruf. Den Unterprogrammen wird beim Aufruf über die tatsächliche Parameterliste (genauer: Argumentliste) bestimmte Werte übergeben, mit denen sie arbeiten können. Die Unterprogramme liefern in der Regel Rückgabewerte zurück. Alle genannten Werte können auch Referenzen, Zeiger oder Adressen auf Speicherbereiche sein. Die genannten Begriffe sind ebenfalls synonym. Im C++-Jargon wird allerdings oft streng zwischen Referenz und Zeiger unterschieden, mit Referenz wird die mit Übergabe der Parameter/ArgumenteAbhängig von der Rechnerarchitektur und der Programmiersprache werden zur Übergabe von Parametern vom aufrufenden an den aufzurufenden Softwareteil unterschiedliche Verfahren und Konventionen benutzt. Zum Beispiel können die Parameter über Register übergeben werden, wobei durch Konventionen festgelegte Register(nummern) auf eine Adressliste zeigen (die die Adressen der Parameter/Argumente enthält), ein Register enthält die Einsprungadresse im Unterprogramm, ein anderes die Rücksprüngadresse. Details siehe Objektmodule bei Großrechnern. Übergabe über den StackIn anderen Systemumgebungen wird dazu einen Stack-Mechanismus verwendet. In diesen Fällen ist zum Verständnis der Funktionsweise von Unterprogrammen folgendes Basiswissen notwendig: Grundsätzlich ist der Speicher von Prozessoren unterteilt in
Jeder Thread hat seinen eigenen Stapelspeicher. In diesem werden gespeichert:
Der Stack wird bei der Programmabarbeitung im Maschinencode über ein spezielles Adressregister adressiert, den Stackpointer oder Stapelzeiger. Dieser adressiert immer das untere Ende des als Stack benutzen Speicherbereiches. Hinzu kommt zumeist ein Basepointer, der eine Basisadresse der Variablen und tatsächlichen Parameter innerhalb des Stacks adressiert. Der Begriff Stack ist im Deutschen als „Stapel“ übersetzbar, auch der Begriff „Kellerspeicher“ wird benutzt. Im Stack werden Informationen gestapelt und nach dem Prinzip Last In – First Out (LIFO) gespeichert und wieder ausgelesen. Allerdings kann der Zugriff auch auf beliebige Adressen innerhalb des Stacks erfolgen. Die Parameterübergabe erfolgt über den Stack. Jeder tatsächliche Parameter wird in der Reihenfolge der Abarbeitung, üblicherweise von links nach rechts (gemäß einer strikt festgelegten Aufrufkonvention), auf den Stack gelegt. Dabei erfolgt, falls notwendig, eine Konvertierung auf das Format, das vom Unterprogramm benötigt wird. Bei Aufruf des Unterprogramms wird dann der sogenannte Basepointer auf die nunmehr erreichte Adresse des Stacks gesetzt. Damit sind die Parameter des Unterprogramms relativ über die Adresse, die im Basepointer gespeichert ist, erreichbar, auch wenn der Stack für weitere Speicherungen benutzt wird. Werte oder Referenzen/Zeiger als ParameterWerden in der tatsächlichen Parameterliste nicht nur elementare Datentypen wie void function(type* data) // Funktionskopf, formale Parameterliste
…
struct { int a, float b } data; // Datendefinition
function(&data); // Funktionsaufruf, tatsächliche Parameterliste
In diesem Fall erfolgt beim Aufruf die explizite Angabe der Adresse der Daten, ausgedrückt mit dem Der Aufruf In C++ kann der Funktionskopf im gleichen Beispiel mit In C oder C++ ist es auch möglich, anstelle der meist sinnvollen und gebräuchlichen Referenzübergabe eine Wertübergabe zu programmieren. Das sieht wie folgt aus: void function(type data) // Funktionskopf, formale Parameterliste
…
struct { int a, float b } data; // Datendefinition
function(data); // Funktionsaufruf, tatsächliche Parameterliste
Beim Aufruf wird der Inhalt der Struktur insgesamt auf den Stack kopiert. Das kann sehr viel sein, wenn die Struktur umfangreich ist. Dadurch kann es zum Absturz des gesamten Ablaufes kommen, wenn die Stackgrenzen überschritten werden und dies in der Laufzeitumgebung nicht erkannt wird. Eine Wertübergabe ist allerdings sinnvoll in folgenden Fällen:
Rückschreiben über referenzierte DatenIn vielen Programmiersprachen ist ein Rückschreiben von Ergebnissen auch über Referenzen, die als Parameter des Unterprogramms übergeben wurden, möglich, beispielsweise in C und C++: void function(Type* data)
{
data->a = data->b * 2; // Wert in data->a wird veraendert.
}
Das gilt gleichermaßen für Java. Das Rückschreiben kann ungewollt sein, weil Nebenwirkungen (Nebeneffekte) verhindert werden sollen. Ein Unterprogramm soll die Werte von bestimmten Datenstrukturen nur lesend verarbeiten und wirkungsfrei darauf sein. In C++ (bzw. in C) ist es möglich, zu formulieren: void function(Type const* data)
{
data->a = data->b * 2; // Hier meldet der Übersetzer einen Syntaxfehler.
}
Die hier verwendete Schreibweise mit dem Schlüsselwort const struct Type { int a, float b } data = { 5, 27.2 };
function(Type* data) { … } // Funktionsdefinition
function(&data); // Aufruf
führt in C++ zu einem Syntaxfehler, weil es nicht gestattet ist, als konstant bezeichnete Daten an eine nicht konstante Referenz zu übergeben. In C werden Zeigertypen nicht so genau getestet, so dass dieses Beispiel – abhängig vom verwendeten Übersetzer – in solchen Fällen möglicherweise lediglich eine Warnung auslösen würde. Allerdings ist es in C und C++ möglich, innerhalb der Funktion den Typ des Zeigers zu wandeln und dann dennoch schreibend auf den Speicherbereich zuzugreifen. Eine solche Programmierung sollte nur in Sonderfällen verwendet werden und sollte nach außen entsprechend dokumentiert werden. In Java gibt es die Möglichkeit der In der objektorientierten Programmierung in Java und C++ wird die Referenz auf die Klassendaten implizit mit dem Umsetzung auf MaschinenebeneDas Konzept des Stack wurde weiter oben im Abschnitt Übergabe über den Stack bereits erläutert. Für Unterprogramme auf Maschinensprachniveau (Assembler) ist es an sich gleichgültig, beziehungsweise liegt es in der Hand des Programmierers, wie er die Parameterübergabe und die Rücksprungadresse verwaltet. Möglich ist auch die Übergabe und Speicherung ausschließlich in Prozessorregistern. Allerdings ist bei der Verwaltung der Rücksprungadresse die Notwendigkeit eines geschachtelten Aufrufs mehrerer (typisch verschiedener) Unterprogramme ineinander zu beachten. Nur bei ganz einfachen Aufgaben ist eine Beschränkung auf wenige oder nur eine Ebene sinnvoll. Es gibt aber tatsächlich bei zugeschnittenen Prozessoren und Aufgabenstellungen auch solche Konzepte.
In Assembler muss man all diese Dinge selbst programmieren. In den Programmiersprachen C++ und C übernimmt das der Übersetzer. In Java erfolgt innerhalb der Speicherbereiche der Virtuellen Maschine das Gleiche, organisiert vom Bytecode (erzeugt vom Java-Übersetzer) und dem Maschinencode in der virtuellen Maschine. Als Illustration sei hier der erzeugte Assembler-Code (80x86-Assembler) der folgenden einfachen Funktion gezeigt: float parabel(float x)
{
return x * x;
}
Als Compiler wurde Microsoft Visual Studio 6 auf einem PC verwendet. Der Assemblercode ist in dieser IDE sichtbar, beispielsweise beim Debuggen in Maschinenebene, aber auch wenn mit entsprechenden Compileroptionen Listingfiles erzeugt werden. Maschinencode für den Aufruf: push 40000000h ; Der Wert 2.0 wird in den Stack gelegt.
call parabel ; Aufruf des Unterprogramms;
; call legt den Instructionpointer in den Stack
add esp, 4 ; Addieren von 4, das ist Byteanzahl des Parameters
fst dword ptr [ebp - 4] ; Abspeichern des Ergebnisses in y
Maschinencode des Unterprogramms: parabel:
push ebp ; Der Basepointer wird im Stack gespeichert.
mov ebp, esp ; Der Basepointer wird mit dem Wert des Stackpointer geladen.
sub esp, 40h ; 64 Byte Stack werden reserviert.
push ebx ; CPU-Register, die hier verwendet = geändert werden,
push esi ; werden im Stack zwischengespeichert.
push edi
fld dword ptr [ebp + 8] ; Der Wert des Parameters x wird relativ zum Basepointer geladen
fmul dword ptr [ebp + 8] ; und in der floating-point-unit mit selbigem multipliziert.
pop edi ; Register werden restauriert.
pop esi
pop ebx
mov esp, ebp ; Der Stackpointer wird genau auf den Stand wie beim Aufruf
; des Unterprogramms gebracht.
pop ebp ; Der Basepointer wird aus dem Stack restauriert.
ret ; Der Instruction pointer wird aus dem Stack restauriert
; und damit wird nach dem call (oben) fortgesetzt.
Folgendes Beispiel zeigt einen handgeschriebenen Assemblercode für den Signalprozessor ADSP-216x von Analog Devices für folgende aus C zu rufende Funktion: float set_floatExtend(_floatExtend* dst, float nVal);
Dabei handelt es sich um eine Funktion, die einen in .GLOBAL _set_floatExtend; ; Sprunglabel global sichtbar
_set_floatExtend: ; Sprunglabel angeben, das ist der Name des Unterprogramms,
; aus C ohne Unterstrich anzugeben.
I4 = R4; ; Im Register R4 wird der erste Parameter _floatExtend* dst übergeben.
; Da es eine Adresse ist, wird diese in das Adressregister I4 umgeladen.
PX = F8; ; Der zweite Parameter float nVal wird aus F8 in das Register PX geladen.
dm(0,I4) = PX1; ; Ein Teil des Inhaltes von PX, in PX1 sichtbar, wird auf
; der Adresse gespeichert, die von I4 gezeigert wird.
dm(1,I4) = PX2; ; Speicherung des zweiten Teils auf der Folgeadresse
! FUNCTION EPILOGUE: ; Standard-Abschluss des Unterprogramms:
i12 = dm(-1,i6); ; Das Adressregister i12 wird aus einer Adresse relativ zum Basepointer
; (hier i6) geladen. Das ist die Rücksprungadresse.
jump (m14,i12) (DB) ; Das ist der Rücksprung unter Nutzung des Registers i12.
F0 = F8; ; nach dem Rücksprung werden die noch im cashe stehenden Befehl verarbeitet,
; hier wird der Wert in F8 nach dem Register R0 geladen, für return.
RFRAME; ; dieser Befehl korrigiert den Basepointer i6 und Stackpointer i7.
Definition und technische Anwendung von Unterprogramm-ParameternFormale ParameterDie formalen Parameter eines Unterprogramms werden bei dessen Deklaration oder Definition normalerweise hinter dem Namen des Unterprogramms angegeben. Mit diesen kann im Unterprogramm beispielsweise gerechnet werden, ohne dass konkrete Werte bekannt sind. Bei einer Deklaration sind oft nur die Datentypen der formalen Parameter anzugeben. Die verwendeten Parameter müssen immer zuweisungskompatibel zu diesen formalen Definitionen sein. Beispiel: Unterprogrammdeklaration in den Programmiersprachen PASCAL und Delphi mit x und y als formalen Parametern: FUNCTION Radius(x, y : REAL) : REAL;
BEGIN
Radius := SQRT((x * x) + (y * y))
END;
Die formalen Parameter, hier Tatsächliche Parameter oder ArgumenteZur Verwendung des Unterprogramms wird dieses mit die Ausführung beeinflussenden tatsächlichen Parametern (Argumenten) aufgerufen; diese definieren für diese Ausführung den anfänglichen konkreten Wert der abstrakten formalen Parameter. Zur besseren Unterscheidung von formalen Parametern wurde für tatsächliche Parameter auch die Bezeichnung Argument etabliert, besonders in Beschreibungen von Programmiersprachen.[1][2] Im Deutschen findet man auch die Bezeichnung aktueller Parameter, durch die falsche Übersetzung des englischen Ausdrucks actual parameter (tatsächlicher Parameter). Die Art der Übergabe ist von Programmiersprache zu Programmiersprache verschieden. Die Sprache Fortran verwendet beim Übersetzen festgelegte Speicheradressen für jedes Unterprogramm. Sprachen wie Pascal oder C verwenden den Stack oder Prozessorregister zur Parameterübergabe. Beispiel: Aufruf des Unterprogramms mit verschiedenen tatsächlichen Parametern: r1 := Radius(x1, y1); -- tatsächliche Parameter x := x1 und y := y1
Durchmesser := 2 * Radius(13, -2); -- tatsächliche Parameter x := 13 und y := -2
Kurz: (formale) Parameter stellen benannten Speicherplatz zur Verfügung, ähnlich algebraischen Variablen, Argumente oder tatsächliche Parameter sind konkrete Werte (oder Datenobjekte), die dort gespeichert und entsprechend verwendet werden. Type-HintingWerden die Datentypen der formalen Parameter vorgegeben, wie im obigen Beispiel, spricht man von Type-Hinting. Type-Hinting ist in vielen Programmiersprachen (C, C++, Java und einige mehr) Pflicht (das Auslassen führt zu einem Syntaxfehler), während Skriptsprachen häufig keine Möglichkeit bieten Type-Hinting zu verwenden. float radius (float x, float y);
function radius($x, $y);
/* Der erste Parameter muss vom Typ der Klasse PDO sein, andernfalls wird ein Fehler erzeugt */
function getData(PDO $db, $y);
Ersetzen der formalen durch tatsächliche ParameterEs gibt unterschiedliche Methoden, wie die formalen Parameter während der Parameterübergabe durch die tatsächlichen Parameter ersetzt werden:
In einem Makro wird der formale Parameter textuell durch den tatsächlichen Parameter ersetzt. Der Unterschied zu Namensparametern besteht darin, dass Namenskonflikte in Kauf genommen werden. Kommt in einem tatsächlichen Parameter eine Variable vor, welche den gleichen Namen wie eine lokale Variable besitzt, so wird bei der Makroexpansion die lokale Variable verwendet.
Moderne, prozedurale Programmiersprachen unterstützen in der Regel Wertparameter und Referenzparameter, manchmal auch Wertergebnisparameter. Beispiel für verschiedene Parameterübergaben proc test(x,y)
{
y = y + 1;
x = 10 * x;
}
a = 5;
b = 4;
test(a, b);
print(a, b);
test(b, b);
print(b);
5 4
4
Erklärung: Es wird durch die Aufrufe von
50 5
60
Erklärung: Beim Aufruf von In der zweiten Abarbeitung von
50 5
6 ''oder'' 50
Erklärung: Beim zweiten Aufruf von BefehlszeilenparameterZudem besteht bei vielen gängigen Programmen für alle gängigen Betriebssysteme die Möglichkeit, Parameter in der Befehlszeile zu übergeben, die dann beim Aufrufen bearbeitet werden. Beispiel: Fiktiver Programmaufruf über die Befehlszeile unter Windows programm.exe -parameter -weiterer -xyz=(a|b) /usw
Hiermit würde programm.exe mit den Parametern „parameter“, „weiterer“, „xyz=(a|b)“ und „usw“ aufgerufen werden. Parameter werden also mit oder ohne Wertangabe verwendet, wobei die Wertangabe dem Namen mit Leerraum, mit Sonderzeichen wie „=“ oder gar nicht abgegrenzt angehängt wird. Je nachdem, welches Programm verwendet wird, stehen verschiedene Parameter zur Verfügung; je nach Programm haben gleich benannte Parameter im Allgemeinen unterschiedliche Auswirkungen. Auch die formalen Regeln zur Angabe sind vom Programm abhängig; dass, wie im Beispiel, mehrere unterschiedliche Trennzeichen verwendet werden, ist zwar unüblich und dient nur der Demonstration, aber viele Programme bieten durchaus flexible Möglichkeiten. Unter Unix-artigen Systemen werden Parameter traditionell mit einzelnen Buchstaben angegeben und mit „-“ eingeleitet, wenn es sich um Optionen oder Schalter handelt, die aus einer für das jeweilige Programm feststehenden Menge ausgewählt werden können; dagegen werden Parameter nicht besonders eingeleitet, wenn es sich um Dateinamen und ähnliche freie Angaben handelt. Die Abgrenzung voneinander geschieht erforderlichenfalls durch Leerraum. Beispiel: „ls -l -t /usr/bin /usr/local/bin“ oder gleichbedeutend „ls -lt /usr/bin /usr/local/bin“. Bei Programmen, die sowohl einbuchstabige als auch mehrbuchstabige Optionen annehmen, sind Letztere mit „--“ einzuleiten. Unter DOS (in Tradition von OpenVMS) wird traditionell „/“ an Stelle des „-“ verwendet und Werte von Parameternamen mit „=“ abgetrennt. Unter Windows sind beide Stile anzutreffen. Allgemein kann man sagen, dass versierte Benutzer bei Verwendung von Befehlszeilenparametern oft schneller zu Ergebnissen kommen als durch andere Bedienmöglichkeiten, wie beispielsweise Dialogfenster in einer GUI. So ist es mit IrfanView zum Beispiel ein Leichtes, mittels dreier Parameter beliebig viele Bilder zu laden, zu konvertieren und in einem anderen Format zu speichern. Siehe auch
Einzelnachweise
|