2.3.1 Datentypen
Die
Bartels User Language stellt die folgenden elementaren Datentypen zur Verfügung:
char | Zeichen aus dem Zeichensatz der Maschine |
int | ganzzahliger numerischer Wert |
double | doppelt genauer numerischer Gleitkommawert |
string | Zeichenkette (char-Vektor) |
index | Index auf definierte DDB-Struktur des Bartels AutoEngineer |
Daneben ist die Verwendung folgender zusammengesetzter Datentypen möglich:
| Vektor | Zusammenfassung von Elementen gleichen Datentyps |
struct | Zusammenfassung von Elementen unterschiedlichen Datentyps |
Datentyp-Konvertierung
Verschiedene Operatoren können implizite Datentypumwandlungen verursachen. So setzen eine Reihe arithmetischer Operationen definierte Datentypen bzw. Datentyppaare für ihre Operanden voraus. Ebenso wird bei der Zuweisung eines Wertes an eine Variable oder der Übergabe von Funktionsparametern eine entsprechende Datentypkompatibilität verlangt. Sofern an irgendeiner Stelle im Programm die geforderte Kompatibilität nicht vorliegt, wird versucht, den Wert des betroffenen Operanden in den gewünschten Datentyp zu überführen (man spricht von einem "type cast"). Diese Typkonvertierung läuft nach folgenden Regeln ab: Zulässige Umwandlungen ohne Informationsverlust sind
char in
int oder
char in
string, sowie
int in
double; ebenfalls zulässige Umwandlungen - jedoch mit möglichem Informationsverlust - sind
int in
char, sowie
double in
int. Der Compiler gibt Fehlermeldungen aus, wenn auch unter Ausnutzung der Typkonvertierungsregeln keine Typkompatibilität erreicht werden kann.
2.3.2 Variablen
Alle globalen und lokalen Variablen müssen vor ihrem Gebrauch deklariert werden, damit sowohl ihr Datentyp als auch ihr Name definiert sind. Durch derartige Vereinbarungen wird festgelegt, wie einzelne, vom Benutzer eingeführte Namen durch die
User Language zu interpretieren sind. Jede Vereinbarung besteht aus einer Datentypspezifikation sowie einer Liste von Deklaratoren; die Deklaratoren wiederum bestehen aus dem Variablennamen sowie wahlweise einer Initialisierung der Variablen.
Elementare Datentypen
Beispiel für die Deklaration von
char-Variablen:
char c;
char TAB = '\t', NEWLINE = '\n';
In obigem Beispiel werden die
char-Variablen
c (nicht initialisiert) sowie
TAB und
NEWLINE (initialisiert mit dem Tabulator- bzw. dem Zeilenvorschub-Zeichen) deklariert.
Beispiel für die Deklaration von
int-Variablen:
int i, MAXLINELEN = 80;
int pincount = 0;
In obigem Beispiel werden die
int-Variablen
i (nicht initialisiert) und
MAXLINELEN (initialisiert mit dem Wert 80), sowie
pincount (initialisiert mit 0) vereinbart.
Beispiel für die Deklaration von
double-Variablen:
double x_coord, y_coord;
double MMTOINCH = 1.0/25.4;
double starttime = clock();
In obigem Beispiel werden die
double-Variablen
x_coord und
y_coord (nicht initialisiert),
MMTOINCH (initialisiert mit einem numerischen Ausdruck), sowie
starttime deklariert; die Variable
starttime wird initialisiert mit dem Resultatwert der (System-)Funktion
clock, welche die Prozessor-Zeit zurückgibt.
Beispiel für die Deklaration von
string-Variablen:
string s1;
string ProgName = "TESTPROGRAM", ProgVer = "V1.0";
string ProgHeader = ProgName+"\t"+ProgVer;
In obigem Beispiel werden die
string-Variablen
s1 (nicht initialisiert),
ProgName und
ProgVer (initialisiert mit
TESTPROGRAM und
V1.0), sowie
ProgHeader deklariert;
ProgHeader wird dabei mit einem Ausdruck initialisiert, der sich durch Aneinanderfügen der
string-Variablen
ProgName, des Tabulatorzeichens, sowie der
string-Variablen
ProgVer ergibt.
Beispiel für die Deklaration von
index-Variablen:
index L_MACRO macro;
index L_CNET net1, net2;
In obigem Beispiel werden die
index-Variablen
macro (vom
index-Variablentyp
L_MACRO) sowie
net1 und
net2 (vom
index-Variablentyp
L_CNET) vereinbart. Bei der Deklaration von
index-Variablen besteht die Spezifikation des Datentyps aus dem Schlüsselwort
index und zusätzlich dem Namen des
index-Variablentyps (hier
L_MACRO bzw.
L_CNET). Die Namen für die
index-Variablentypen sind vordefiniert (siehe
Anhang B).
Es muss sichergestellt sein, dass in einem Programm nur zueinander kompatible
index-Variablentypen verwendet werden. Dies beruht auf der Tatsache, dass über
index-Datentypen der Zugriff auf entsprechende Einträge aus der Design-Datenbank (DDB) des
Bartels AutoEngineer definiert wird; die Verfügbarkeit dieser
DDB-Einträge unterscheidet sich je nach Interpreterumgebung (im
Schaltplaneditor sind andere Datentypen definiert als im Layout). Bei der Verwendung zueinander nicht kompatibler
index-Variablentypen im selben Programm gibt der
User Language Compiler eine entsprechende Fehlermeldung aus und erzeugt keinen Code. Ähnlich verhält sich der
User Language Interpreter; beim Versuch ein
User Language-Programm aufzurufen, das zur Interpreterumgebung inkompatible
index-Datentyp-Referenzen enthält, gibt das System eine entsprechende Fehlermeldung aus und führt das betreffende Programm nicht aus. Die Information über die Kompatibilität der
index-Datentypen ist dem
Anhang A bzw. dem
Anhang B zu entnehmen.
Vektoren
Unter einem Vektor, auch bezeichnet als Feld oder Array, versteht man die Zusammenfassung einzelner Elemente gleichen Datentyps. Bei der Deklaration von Vektorvariablen wird neben der Spezifikation des Datentyps und der Definition des Variablennamens zusätzlich die Angabe der Vektordimension benötigt. Diese Dimensions-Angabe erfolgt durch Anfügen eckiger Klammern an den Variablennamen, wobei jeweils ein Klammernpaar einer Dimension entspricht. Bei der Initialisierung von Vektor-Elementen sind die Initialisierungswerte durch Kommata zu trennen, und jede Vektordimension ist in geschweifte Klammern einzuschließen.
Beispiel für die Deklaration von Vektor-Variablen:
int intary[], intfield[][][];
double valtab[][] = {
{ 1.0, 2.54, 3.14 },
{ 1.0/valtab[0][1], clock() }
};
string TECHNOLOGIES[] = {
"TTL", "AC", "ACT", "ALS", "AS", "F",
"H", "HC", "HCT", "HCU", "L", "LS", "S"
};
Obiges Beispiel enthält die Deklarationen der
int-Vektoren
intary und
intfield (ein- bzw. dreidimensional), des zweidimensionalen
double-Vektors
valtab, sowie des eindimensionalen
string-Vektors
TECHNOLOGIES. In den Deklarationen für
valtab und
TECHNOLOGIES sind Initialisierungen angegeben, die den folgenden Zuweisungen entsprechen:
valtab[0][0] = 1.0;
valtab[0][1] = 2.54;
valtab[0][2] = 3.14;
valtab[1][0] = 1.0/valtab[0][1];
valtab[1][1] = clock();
TECHNOLOGIES[0] = "TTL";
TECHNOLOGIES[1] = "AC";
TECHNOLOGIES[2] = "ACT";
:
TECHNOLOGIES[11] = "LS";
TECHNOLOGIES[12] = "S";
Es sei an dieser Stelle nochmals darauf hingewiesen, dass in der
User Language der elementare Datentyp
string einem eindimensionalen
char-Vektor entspricht. Die Deklarationen
string s;
und
char s[];
sind also äquivalent.
Strukturen
Unter einer Struktur versteht man die Zusammenfassung mehrerer, jeweils durch Name und Datentyp definierter Elemente, die in einem bestimmten verarbeitungstechnischen oder auch nur logischen Zusammenhang stehen. Bei der Vereinbarung von Strukturen unterscheidet man die Strukturdefinition und die Strukturdeklaration. Die Strukturdefinition besteht aus dem Schlüsselwort
struct, dem Namen der Strukturdefinition, und - in geschweiften Klammern - den Definitionen der Strukturelemente. Die Strukturdeklaration besteht aus dem Schlüsselwort
struct, dem Namen einer gültigen Strukturdefinition, sowie dem Namen der Variablen, die der Strukturdefinition zugeordnet wird. Strukturdefinition und Strukturdeklaration können zusammengefasst werden, wobei dann auch der Name für die Strukturdefinition entfallen kann. Initialisierungen innerhalb von Strukturdeklarationen sind in der aus den Vektordeklarationen bekannten Nomenklatur zulässig.
Beispiel für die Vereinbarung von Strukturen:
// Structure declarations
struct coordpair {
double x
double y;
};
struct coordpair elementsize = {
bae_planwsux()-bae_planwslx(),
bae_planwsuy()-bae_planwsly()
};
struct elementdes {
string fname, ename;
int class;
struct coordpair origin, size;
} element = {
bae_planfname(),
bae_planename(),
bae_planddbclass(),
{
bae_planwsnx(),
bae_planwsny()
},
elementsize
};
struct {
string id, version;
struct {
int day;
string month;
int year;
} reldate;
} program = {
"UL PROGRAM",
"Version 1.1",
{ 4, "July", 1992 }
};
Obiges Beispiel enthält die Definition der Struktur
coordpair, die Deklaration der Variablen
elementsize (Struktur vom Typ
coordpair), die Definition der Struktur
elementdes, die Deklaration der Variablen
element (Struktur vom Typ
elementdes), sowie die Deklaration der Strukturvariablen
program. Die in den Deklarationen für
elementsize,
element und
program enthaltenen Initialisierungen entsprechen den folgenden Zuweisungen:
elementsize.x=bae_planwsux()-bae_planwslx();
elementsize.y=bae_planwsuy()-bae_planwsly();
element.fname=bae_planfname();
element.ename=bae_planename();
element.class=bae_planddbclass();
element.origin.x=bae_planwsnx();
element.origin.y=bae_planwsny();
element.size=plansize;
program.id="UL PROG";
program.version="Version 1.1";
program.reldate.day=4;
program.reldate.month="July";
program.reldate.year=1992;
Auch die Definition von Vektoren aus Strukturen bzw. die Verwendung von
Vektordatentypen innerhalb von Strukturen ist möglich, wie das folgende Beispiel demonstriert:
struct drilldef {
index L_DRILL drilltool;
struct { double x, y; } drillcoords[];
} drilltable[];
Datentypumbenennung
Bartels User Language verfügt über einen Mechanismus zur Umbenennung von Datentypen. Dabei handelt es sich nicht um die Schaffung eines neuen Datentyps, sondern lediglich um die Vergabe eines zusätzlichen Namens für einen bereits bekannten Typ. Eine derartige Typumbennung erfolgt durch die Angabe des Schlüsselwortes
typedef gefolgt von der Spezifikation des Datentyps sowie dem zur Bezeichnung dieses Datentyps zusätzlich einzuführenden Namen. Ein mit
typedef eingeführter Name kann anschließend zur Typspezifikation bei der Deklaration von Variablen, Funktionen und Funktionsparametern verwendet werden.
Beispiel für Typ-Umbennungen:
typedef index L_CNET NETLIST[];
typedef int IARY[];
typedef IARY MAT_2[];
typedef struct {
int pointcount;
struct {
int t;
double x,y;
} pointlist[];
} POLYLIST[];
MAT_2 routmatrix;
NETLIST netlist;
POLYLIST polygonlist;
In obigem Beispiel werden die drei Variablen
routmatrix (zweidimensionaler int-Vektor),
netlist (eindimensionaler index-Vektor vom Typ
L_CNET), sowie
polygonlist (eindimensionaler Vektor aus Strukturen, die ihrerseits ein
int-Element und einen
struct-Vektor enthalten) deklariert.
2.3.3 Funktionen
Bei komplexen Operationen und Berechnungen ist es meist nicht notwendig, zu wissen, wie das Ergebnis zustande kommt; interessant ist lediglich das Ergebnis selbst. Auch ist es wünschenswert, bestimmte Bearbeitungsfolgen immer wieder verwenden zu können. Mit Hilfe von Funktionen ist die Zerlegung großer Problemstellungen in kleinere, d.h. die Modularisierung und Vereinfachung von Programmen möglich. In der
Bartels User Language wird unterschieden zwischen den Systemfunktionen und den durch den Anwender definierten Funktionen.
Funktionsdefinition
Die Definitionen der Systemfunktionen sind dem Compiler bekannt, die Funktionen selbst sind in den Interpreter eingebunden.
Anhang C enthält die Beschreibung dieser Systemfunktionen. Der Anwender kann also bei der Implementierung seiner Programme die Systemfunktionen verwenden und hat darüber hinaus die Möglichkeit, eigene Funktionen zu definieren.
Eine Funktionsdefinition besteht aus dem Funktionskopf (Header) und dem Funktionsrumpf (Block). Der Header enthält eine Typspezifikation und den Namen der Funktion, sowie die Definition und Deklaration der Funktionsparameter. Die Typspezifikation definiert den Datentyp des Wertes, den die Funktion an den Aufrufer zurückliefert (Rückgabewert). Hierbei steht zusätzlich der Datentyp
void zur Verfügung, der dem Compiler angibt, dass die Funktion keinen Rückgabewert liefert. Wird die Datentypspezifikation weggelassen, dann wird der Funktion automatisch der Datentyp
int zugeordnet. Nach dem Funktionsnamen folgt die Parameterdefinition. Diese besteht aus einer in runde Klammern eingeschlossenen Liste von durch Kommata getrennten Parameternamen bzw. Parameterdeklarationen. Für den Fall, dass die Funktion gar keine Parameter enthält, ist lediglich das Klammernpaar anzugeben. Alle definierten Parameter (außer den bereits in der Liste der Parameterdefinitionen deklarierten sowie den
int-Typen) müssen nach der Liste der Parameterdefinitionen explizit vereinbart werden. Diese Parameterdeklarationen sind wie Variablendeklarationen vorzunehmen. Nach dem Funktionskopf muss der Funktionsrumpf definiert werden. Dieser ist ein durch geschweifte Klammern umschlossener Block von Anweisungen.
Beispiele für Funktionsdefinitionen:
double netroutwidth(index L_CNET net)
// Get the routing width of a given net
// Returns : width or 0.0 if two pins with different width
{
index L_CPIN pin; // Pin index
int pincnt=0; // Pin count
double rw=0.0; // Rout width
// Loop thru all pins
forall (pin of net) {
// Test if the pin introduces a new rout width
if (pin.RWIDTH!=rw && pincnt++>0)
return(0.0);
// Set the rout width
rw=pin.RWIDTH;
}
// Return the rout width
return(rw);
}
int allpartsplaced()
// Test if all netlist-defined parts are placed
// Returns : 1 if all parts are placed or zero otherwise
{
index L_CPART cpart; // Connection part index
// Loop thru the connection part list
forall (cpart where !cpart.USED)
// Unplaced part matched
return(0);
// All parts are placed
return(1);
}
double getdistance(xs,ys,xe,ye)
// Get the distance between two points
// Returns : the distance length value
double xs, ys; // Start point coordinate
double xe, ye; // End point coordinate
{
double xd=xe-xs; // X distance
double yd=ye-ys; // Y distance
// Calculate and return the distance (Pythagoras)
return(sqrt(xd*xd+yd*yd));
}
double arclength(r,a1,a2)
// Get arc segment length by radius and start-/end-point angle
// Returns : the arc segment length value
double r; // Radius
double a1; // Start point angle (in radians)
double a2; // End point angle (in radians)
{
// Arc; "absolute" angle between start and end point
double arc = a1<a2 ? a2-a1 : 2*PI()+a2-a1;
// Get and return the arc segment length
return(arc*r);
}
double getangle(cx,cy,x,y)
// Get the angle of a circle arc point
// Returns : the angle (in radians; range [0,2*PI])
double cx, cy; // Circle center coordinate
double x, y; // Circle arc point coordinate
{
double res; // Result value
// Get arc tangent of angle defined by circle point
res=atan2(y-cy,x-cx);
// Test the result
if (res<0.0)
// Get the "absolute" angle value
res=PI()-res;
// Return the result value
return(res);
}
double PI()
// Returns the value of PI in radians
{
// Convert 180 degree and return the result
return(cvtangle(180.0,1,2));
}
void cputimeuse(rn,st)
// Report CPU time usage (in seconds)
string rn; // Routine name
double st; // Start time
{
// Print CPU time elapsed since start time
printf("(%s) Elapsed CPU Time = %6.1f [Sec]\n",rn,clock()-st);
}
Funktionsaufruf und Wertübergabe
Jede in einem
User Language-Programm (bzw. Programmtext) per Definition bekannte Funktion kann innerhalb dieses Programmes (bzw. in dem entsprechenden Programm-Modul) auch aufgerufen werden. Bei der Verwendung von
User Language Systemfunktionen besteht jedoch die Einschränkung, dass in einem Programm nur zueinander kompatible Systemfunktionen verwendet werden können. Dies beruht auf der Tatsache, dass über derartige Funktionsaufrufe ggf. Aktionen ausgelöst werden, die nur in einer bestimmten Interpreterumgebung ausgeführt werden können (die Funktion zur Festlegung von Plotparametern im
CAM-Prozessor des
AutoEngineers kann selbstverständlich nicht im
Schaltplaneditor aufgerufen werden). Bei der Verwendung zueinander nicht kompatibler Systemfunktionen gibt der
User Language Compiler eine Fehlermeldung aus und erzeugt keinen Programm-Code. Ähnlich verhält sich der
User Language Interpreter; beim Versuch ein
User Language-Programm aufzurufen, das zur Interpreterumgebung inkompatible Systemfunktions-Referenzen enthält, erzeugt das System eine entsprechende Fehlermeldung und führt das betreffende Programm nicht aus. Die Information über die Kompatibilität der
User Language-Systemfunktionen ist dem
Anhang A bzw. dem
Anhang C zu entnehmen.
Der Funktionsaufruf setzt sich zusammen aus dem Funktionsnamen und der in runden Klammern eingeschlossenen Liste der aktuellen Parameter, die der Funktion übergeben werden soll.
Die Inhalte der global definierten Variablen eines Programms stehen grundsätzlich in jeder Funktion desselben Geltungsbereichs zur Verfügung, d.h. globale Variablen können zur Übergabe von Werten an Funktionen benutzt werden. Darüber hinaus besteht die Möglichkeit der Wertübergabe über Funktionsparameter. Die Übergabe per Parameter kann einfach kontrolliert werden und ist daher i.d.R. der Methode der Übergabe über globale Variablen vorzuziehen. Die Liste der aktuellen Parameter, also der Ausdrücke, die man bei einem Funktionsaufruf übergibt, muss mit der formalen Parameterdefinition (also Anzahl und Datentypen) der aufzurufenden Funktion übereinstimmen. Beim Funktionsaufruf werden die Werte der aktuellen Parameter in die entsprechenden formalen Parameter kopiert. Nach erfolgreicher Beendigung der Funktion wird jeder durch die Funktion geänderte Parameterwert wieder auf den aktuellen Parameter zurückgespeichert, sofern dieser eine Variablenreferenz darstellt. Schließlich besteht noch die Möglichkeit der Wertübergabe über den Rückgabewert der Funktion. Dabei wird innerhalb der Funktion mit Hilfe der
return-Anweisung ein Funktionsergebnis gesetzt, das anschließend vom Aufrufer innerhalb des Ausdrucks, der den Funktionsaufruf enthält, ausgewertet werden kann.
Beispiel für Funktionsaufruf und Wertübergabe:
// Date structure
struct date { int day, month, year; };
// Global program variables
string globalstr="Global string";
int fctcallcount=0;
// Main program
main()
{
// Local variables of main
string resultstr="function not yet called";
struct date today = { 0, 0, 0 };
double p=0.0, b=2.0, e=10.0;
// Print the global variables
printf("fctcallcount=%d, %s\n",fctcallcount,globalstr);
// Print the local variables
printf("resultstr=\"%s\"\n",resultstr);
printf("today : %d,%d,%d",today.day,today.month,today.year);
printf("\t\tb=%.1f, e=%.1f, p=%.1f\n",b,e,p);
// Call function
resultstr=function(today,b,e,p);
// Print the global variables
printf("fctcallcount=%d, %s\n",fctcallcount,globalstr);
// Print the local variables
printf("resultstr=\"%s\"\n",resultstr);
printf("today : %d,%d,%d",today.day,today.month,today.year);
printf("\t\tb=%.1f, e=%.1f, p=%.1f\n",b,e,p);
}
string function(curdate,base,exponent,power)
struct date curdate; // Current date parameter
double base; // Base parameter
double exponent; // Exponent parameter
double power; // Power parameter
{
// Increment the function call count
fctcallcount++;
// Set the global string
globalstr="Global string changed by function";
// Get the current date
get_date(curdate.day,curdate.month,curdate.year);
// Calculate the power
power=pow(base,exponent);
// Return with a result string
return("function result string");
}
Obiges Beispiel-Programm erzeugt folgende Ausgabe:
fctcallcount=0, Global string
resultstr="function not yet called"
today : 0,0,0 b=2.0, e=10.0, p=0.0
fctcallcount=1, Global string changed by function
resultstr="function result string"
today : 4,6,92 b=2.0, e=10.0, p=1024.0
Kontrollfluss und Programmstruktur
Jede Funktion der
User Language behält nach ihrem Aufruf solange die Kontrolle, bis sie auf einen weiteren Funktionsaufruf, auf eine
return-Anweisung, oder nach der Abarbeitung der letzten Anweisung der Funktion auf das Funktionsende trifft. Bei einem Funktionsaufruf wird die Kontrolle an die aufgerufene Funktion weitergegeben. Beim Erreichen einer
return-Anweisung oder am Funktionsende wird die Kontrolle an den Aufrufer der Funktion zurückgegeben. Ist in einem Programm eine Anwenderfunktion mit dem Namen
main definiert, dann erzeugt der
User Language Compiler Programm-Code, der dafür sorgt, dass - unmittelbar nach der Initialisierung der globalen Variablen - diese Funktion aufgerufen wird. Der Kontrollfluss eines
User Language-Programms beginnt also üblicherweise bei der Funktion
main. Da bei rekursionsfreier Programmierung jede Funktion irgendwann ihre Kontrolle wieder an den Aufrufer zurückgibt, fällt die Kontrolle schließlich wieder an die
main-Funktion. Wird darin dann das Funktionsende oder eine
return-Anweisung erreicht, dann ist auch das Programmende erreicht, und der
User Language Interpreter kann den Kontrollfluss beenden.
Rekursive Funktionen
Funktionen dürfen rekursiv benutzt werden, d.h. eine Funktion darf sich direkt oder indirekt selbst aufrufen. Dies ist jedoch nur dann sinnvoll, wenn sich bei jedem Aufruf ein Zustand derart verändert, dass sich irgendwann ein eindeutig definierter Endzustand einstellt, mit dessen Hilfe sich die Rekursion abbrechen lässt.
Durch die rekursive Programmierung von Funktionen kann man im Allgemeinen Programm-Code einsparen und eventuell die Lesbarkeit erhöhen. Die Programmlaufzeit und der Speicherplatzbedarf hingegen werden sich durch Rekursionen erhöhen. Daher sollte man jeweils prüfen, ob die Verwendung einer Rekursion tatsächlich nützlich ist. Auch besteht die Gefahr, dass man "versehentlich" eine Endlosrekursion implementiert, d.h. eine Rekursion, die nie den Endzustand erreicht. Der
User Language Interpreter wird bei der Abarbeitung einer solchen Endlosrekursion irgendwann einen Speicher- bzw. Stapel-Überlauf feststellen, da für jeden Funktionsaufruf zumindest eine Rücksprung-Adresse gespeichert werden muss.
2.3.4 Regeln zum Geltungsbereich
Bei der Referenzierung der Objekte eines
User Language-Programms muss der Compiler jeweils die Gültigkeit der Referenz überprüfen. Hierzu ist jedem Objekt ein bestimmter Geltungsbereich innerhalb des Programms zugeordnet. Innerhalb dieses Geltungsbereiches ist das entsprechende Objekt bekannt und kann referenziert werden. Es wird unterschieden zwischen globalem und lokalem Geltungsbereich. Der globale Geltungsbereich erstreckt sich über das gesamte Programm (also auch auf noch einzubindende, getrennt kompilierte Programmteile bzw. Libraries), während die lokalen Geltungsbereiche des Programms Bezug nehmen auf die Funktionsdefinitionen.
Die Funktionen eines Programms sind global, d.h. im gesamten Programm gültig. Variablen- und Typ-Definitionen, die in einer Funktion vorgenommen werden, gelten nur lokal innerhalb dieser Funktion; außerhalb von Funktionen gelten derartige Definitionen als global. Die Parameterdefinitionen einer Funktione werden wie lokale Variablen behandelt und gelten daher immer nur lokal innerhalb der betreffenden Funktion. Strukturdefinitionen gelten allgemein als global im aktuell zu übersetzenden Programmtext. Durch die Zuweisung der Speicherklasse
static kann der Geltungsbereich von Funktionen und globalen Variablen eingeschränkt werden auf den aktuell zu übersetzenden Programmtext. Die Speicherklasse
static dient insbesondere der Vermeidung von Namenskonflikten beim Binden bzw. Linken unterschiedlicher Programm-Module bzw. Libraries.
Um Namenskonflikte zu vermeiden, müssen die Elemente jeder Objektklasse innerhalb ihres Geltungsbereichs jeweils unterschiedliche Namen besitzen. Bei der Referenzierung haben die lokalen Objekte Vorrang vor den globalen.
Datentypen und Definitionen © 1985-2025 Oliver Bartels F+E • Aktualisiert: 11. October 2010, 10:45 [UTC]
|