Forum: Mikrocontroller und Digitale Elektronik C Anfängerfrage (static innerhalb einer Funktion)


von UnderDog (Gast)


Lesenswert?

Wunderschönen ;)

kurze Frage.:

Eigentlich kann man ja überhaupt keine lokalen Variablen zurück an den 
Aufrufer geben, wenn ich Sie jedoch mit "static" deklariere, 
funktioniert das?
Weil "static" festen Speicherplatz reserviert?

Danke im vorraus..

von A. S. (Gast)


Lesenswert?

Wenn Du Rückgabe per Pointer meinst: JA.

Ansonsten zeige ein Beispiel.

von UnderDog (Gast)


Lesenswert?

Achim S. schrieb:
> Wenn Du Rückgabe per Pointer meinst: JA.
>
> Ansonsten zeige ein Beispiel.

Genau das meinte Ich. Wieso klappt das?

von Curby23523 N. (Gast)


Lesenswert?

Ohne static wird die Variable nach dem Funktionsaufruf wieder zerstört 
und bei neuem Aufruf wieder angelegt.

Wenn sie static ist, bleibt sie für immer erhalten und kann somit auch 
mit einem Pointer übergeben werden. Eine static Variable solltest du 
immer initialisieren!
1
uint8_t * test(){
2
static uint8_t i = 0; //WIrd nur einmal gemacht beim STart des Programm.
3
4
i++;
5
6
return &i;
7
}

von UnderDog (Gast)


Lesenswert?

Nils N. schrieb:
> uint8_t * test(){
> static uint8_t i = 0; //WIrd nur einmal gemacht beim STart des Programm.
>
> i++;
>
> return &i;
> }

geht aber auch ohne Pointer?!

von Nils P. (torus)


Lesenswert?

UnderDog schrieb:
>
> geht aber auch ohne Pointer?!

Klar geht das auch ohne Pointer:

uint8_t test()
{
  static uint8_t i = 0;
  i++;
  return i;
}

von UnderDog (Gast)


Lesenswert?

Was hat es denn für einen Vorteil wenn die Variable innerhalb einer 
Funktion nicht "static" ist? Performance?

von Alex G. (dragongamer)


Lesenswert?

UnderDog schrieb:
> Was hat es denn für einen Vorteil wenn die Variable innerhalb einer
> Funktion nicht "static" ist? Performance?
Eher Speicher. Wie oben erwähnt wurde, existieren statische Variablen 
dauerhaft. hast du in nem etwas größeren projekt, 10 Funktionen mit je 3 
lokalen Variablen, bräuchtest du mal eben 30 statische Variablen.

von Nils P. (torus)


Lesenswert?

Underdog, überlese diesen Post mal, das ist nur für C++ und nicht für C 
relevant.

Aber weil wir beim Thema sind und mir genau dieses Verhalten vor kurzer 
Zeit in C++ um die Ohren geflogen ist:


Bei C++ wird die lokale statische Variable nicht beim Programmstart 
sondern bei der ersten Benutzung initialisiert. Dafür baut der Compiler 
im Zweifelsfall extra Code ein, der erkennt ob man im ersten Aufruf 
steckt oder nicht.

* Vor C++11 ist das ganze nicht Thread-save. D.h. man kann sich ganz 
gehörig in den Fuß schießen wenn man mehrere Threads benutzt.

* Ab C++11 ist die Initialisierung Thread-save mit dem Nebeneffekt, das 
man bei jedem Aufruf durch eine Synchronisation durch muss.


Ihr könnt euch sicher mein dummes Gesicht vorstellen, als ich 
feststellte das eine völlig harmlos aussehende Helper Funktion jedes mal 
durch einen System-Mutex geht und tonnenweise Rechenzeit frisst. Einfach 
mal die static Variable auf File-Level statt Function-Level zu 
deklarieren brachte einen satten Performance Boost.

Glücklicherweise ist der Compiler häufig in der Lage zu erkennen wann 
das nötig ist, und wann nicht. Die genauen Regeln dafür hab ich 
allerdings noch nicht durchblickt.

Also aufgepasst, liebe C++ Entwickler.

von Stefan F. (Gast)


Lesenswert?

> Also aufgepasst, liebe C++ Entwickler.
Danke für den Hinweis. Ich wäre sicher früher oder später über diesen 
feinen Unterscheid gestolpert.

von Alex G. (dragongamer)


Lesenswert?

Threadsafety ist natürlich noch eine ganze, andere Baustelle.
Static variablen können von überall zugegriffen werden. Entsprechend 
auch aus zwei Funktionen gleichzeitig.
Herkömmliche Mikrokontroler haben keine paralellen Ausführungseinheiten.

@torus
Hast du variable wirklich global deklariert, wegen "File level"?
Eigentlich sollte das keinen Optimierungsunterschied bewirken.
Eher deklariert man dafür die variable volatile.

von Nils P. (torus)


Lesenswert?

Alex G. schrieb:
> Hast du variable wirklich global deklariert, wegen "File level"?
> Eigentlich sollte das keinen Optimierungsunterschied bewirken.
> Eher deklariert man dafür die variable volatile.

Ja, in meinem Fall war es eine etwas größere Tabelle, die per static 
lokal in der Funktion definiert war. Static const ging leider nicht, da 
sich einige Werte zur Laufzeit ändern konnten.

Der GCC hat von der Tabelle eine Kopie ins Flash gelinkt und im BSS 
Segment entsprechend Speicher alloziert. Beim ersten Aufruf hat er dann 
per memcpy aus dem Flash in das BSS kopiert. Mit entsprechendem Mutex 
versteht sich.

Ich habe lediglich die Deklaration der Tabelle aus der Funktion heraus 
geschoben und ganz gewöhnlich als static im File deklariert. Dann 
verschwand die GCC Magie restlos aus der Funktion. Die Initialisierung 
erfolge nun zeitlich vor main().

von Nop (Gast)


Lesenswert?

Nils N. schrieb:
> Eine static Variable solltest du immer initialisieren!

Kann man aus Stilgründen machen, um zu zeigen, daß man dran gedacht hat. 
Nötig ist das aber nicht, weil static-Variablen genau wie alle anderen 
globals mit 0 initialisiert werden, wenn man nichts ausdrückliches 
hinschreibt.

UnderDog schrieb:
> Was hat es denn für einen Vorteil wenn die Variable innerhalb
> einer Funktion nicht "static" ist? Performance?

"Normalerweise" macht man das nicht static, außer man hat gute Gründe 
dafür. Nämlich den, daß man möchte, daß die Funktion sich eine Variable 
über mehrere Aufrufe hinweg merken soll. Das ist zugleich aber auch eine 
Falle, weil das Verhalten der Funktion dann nämlich davon abhängt, was 
sie bei vorherigen Aufrufen getan hat.

Ein typisches Beispiel für static ist, daß man in einer Funktion 
mitzählen will, wie oft sie aufgerufen wurde.

von Nop (Gast)


Lesenswert?

Nils P. schrieb:

> Bei C++ wird die lokale statische Variable nicht beim Programmstart
> sondern bei der ersten Benutzung initialisiert. Dafür baut der Compiler
> im Zweifelsfall extra Code ein, der erkennt ob man im ersten Aufruf
> steckt oder nicht.

Ist das nur beim GCC so oder bei allen Compilern? Normalerweise heißt es 
bei C++ ja immer, daß man nichts bezahlt, was man nicht auch haben will?

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Ist das nur beim GCC so oder bei allen Compilern?
Wahrscheinlich bei allen.

Nop schrieb:
> Normalerweise heißt es
> bei C++ ja immer, daß man nichts bezahlt, was man nicht auch haben will?
Korrekt, wenn du "static" in Funktionen nicht nutzt, wird da kein Code 
für generiert. Wenn du es aber nutzt, ließe es sich wohl kaum anders 
umsetzen, denn der C++ Standard schreibt das Verhalten ja so vor.

von Curby23523 N. (Gast)


Lesenswert?

Nop schrieb:
> Nötig ist das aber nicht, weil static-Variablen genau wie alle anderen
> globals mit 0 initialisiert werden, wenn man nichts ausdrückliches
> hinschreibt

Nötig ist es dann, wenn der Startwert ungleich 0 sein soll. Also lieber 
gleich angewöhnen und static immer initalisieren.

von Georg A. (georga)


Lesenswert?

Nils P. schrieb:
> Static const ging leider nicht, da
> sich einige Werte zur Laufzeit ändern konnten.

Hm, dann ist doch wieder das Thema der Thread-Sicherheit da... Kann es 
sein, dass der gcc das daran erkannt hat?

von Nop (Gast)


Lesenswert?

Dr. Sommer schrieb:

> Korrekt, wenn du "static" in Funktionen nicht nutzt, wird da kein Code
> für generiert. Wenn du es aber nutzt, ließe es sich wohl kaum anders
> umsetzen, denn der C++ Standard schreibt das Verhalten ja so vor.

Und das wundert mich, denn bei C geht das auch ohne extra Code.

von Stefan F. (Gast)


Lesenswert?

> bei C geht das auch ohne extra Code.

Nicht ganz richtig. Das compilierte Programm enthält einige 
Initialisierungs-Routinen die vor der main() Funktion ausgeführt werden. 
Dazu gehört unter anderem:

1) Kopieren aller Variablen mit Startwert (ungleich 0) vom Flash ins 
RAM.
2) Initialisierung aller anderen globalen und statischen Variablen mit 
0.
3) Einstellen des Stack-Pointers.

von Dr. Sommer (Gast)


Lesenswert?

Nop schrieb:
> Und das wundert mich, denn bei C geht das auch ohne extra Code.
C hat ja auch keine Konstruktoren, die Seiteneffekte haben könnten. Ob 
die Variablen also am Anfang oder später initialisiert werden spielt da 
keine  Rolle.

von Nop (Gast)


Lesenswert?

Stefan U. schrieb:

> Nicht ganz richtig. Das compilierte Programm enthält einige
> Initialisierungs-Routinen die vor der main() Funktion ausgeführt werden.

Ja klar, gemeint war natürlich der Laufzeit-Overhead.


Dr. Sommer schrieb:

> C hat ja auch keine Konstruktoren, die Seiteneffekte haben könnten.

Auch wieder wahr. Also hätte man das Problem nicht, wenn die fragliche 
Funktion in C++ eine standalone-Funktion anstatt einer Methode wäre? 
Obwohl.. doch, ja die Konstruktoren könnten ja auch so eine FUnktion 
aufrufen?

von Dr. Sommer (Gast)


Angehängte Dateien:

Lesenswert?

Nop schrieb:
> Auch wieder wahr. Also hätte man das Problem nicht, wenn die fragliche
> Funktion in C++ eine standalone-Funktion anstatt einer Methode wäre?
Versteh nicht ganz was du meinst... Das Programm im Anhang gibt
1
1
2
X::X()
3
2
4
3
5
4
6
X::X()
7
5
8
6
aus; damit das klappt, müssen die beiden test()-Funktionen jeweils 
prüfen, ob die "static"-Variable bereits initialisiert wurde. Das wird 
per Mutex abgesichert (Aufrufe zu __cxa_guard_acquire & Co).

von Peter S. (Gast)


Lesenswert?

UnderDog schrieb:
> Was hat es denn für einen Vorteil wenn die Variable innerhalb einer
> Funktion nicht "static" ist? Performance?

In der Regel geht es hier weder um Speicher noch um Performance, sondern 
einfach um einen sauberen Programmierstil, der hilft Bugs zu vermeiden.

Wenn möglich, sollte eine Funktion bei gleichen Parametern immer den 
gleichen Rückgabewert liefern und auch sonst keine Seiteneffekte haben. 
Wenn innerhalb einer Funktion eine Variable static ist, dann Teilen sich 
alle Aufrufe dieser Funktion diese Variable. Das kann zu schwer 
erkennbaren Bugs führen.

von Einer K. (Gast)


Lesenswert?

Peter S. schrieb:
> sondern
> einfach um einen sauberen Programmierstil,

Funktionen mit statischen Variablen, im Bauch, sind erstmal nicht 
Wiedereintrittsfähig.
Es drohen unerwünschte Seiteneffekte.

Im Grunde sind solche Funktionen "Wegwerf Funktionen".
Nur für dieses eine Projekt tauglich.
Eher nicht wiederverwendbar.

--- wenn man damit leben kann --- dann men zu ----
Aber man muss sich dessen immer bewusst sein!

Ansonsten gilt der Leitsatz:
Nur statische Variablen, auf welche man verzichtet, sind gute statische 
Variablen.

von derjaeger (Gast)


Lesenswert?

>Was hat es denn für einen Vorteil wenn die Variable innerhalb einer
>Funktion nicht "static" ist? Performance?

Eine statische Variable ist global, d.h. sie ist dauerhaft im RAM und 
für diese muss schon vor Beginn des Programms Speicher reserviert 
werden.

Eine nicht statische Variable existiert im RAM nur temporär, d.h. sobald 
du die Funktion verlässt belegt die nicht statische Variable keinen 
Speicher mehr im RAM. Dafür ist der Stack da, der dynamisch wächst und 
schrumpft im RAM.

von mapfile (Gast)


Lesenswert?

Arduino F. schrieb:
> Ansonsten gilt der Leitsatz:
> Nur statische Variablen, auf welche man verzichtet, sind gute statische
> Variablen.

Nicht alle statischen Variablen werden mit 'static' eingeleitet. Ich 
vermute, dass auch deine Projekte voller statischer Variablen sind, du 
es nur nicht erkennst. ;)

von mapfile (Gast)


Lesenswert?

Stefan U. schrieb:
> 1) Kopieren aller Variablen mit Startwert (ungleich 0) vom Flash ins
> RAM.
> 2) Initialisierung aller anderen globalen und statischen Variablen mit
> 0.

Variablen kopieren? Variablen sind nur reservierte (zugeordnete) 
Speicherbereiche. Sie werden initialisiert, d. h. der Speicherbereich 
mit den definierten Werten beschrieben. Und dabei ist es egal, ob mit 0 
oder einem anderen Wert.

Man kann den Linker anweisen, Speicherbereiche von der Initialisierung 
auszuschließen. Das ist wichtig und nötig, um z. B. bei einem Reboot 
(Warmstart) Daten vor dem Programmabbruch zu bewerten.

In den Startup Files findet man die ganzen Abläufe.

von Dr. Sommer (Gast)


Lesenswert?

mapfile schrieb:
> Sie werden initialisiert, d. h. der Speicherbereich
> mit den definierten Werten beschrieben.
Und das erfolgt eben, indem die Vorbelegung aus dem .text Segment 
(Flash) in das .data Segment (RAM) kopiert wird.

mapfile schrieb:
> Und dabei ist es egal, ob mit 0
> oder einem anderen Wert.
0-Initialisierte Variablen landen im .bss Segment und werden mit einer 
dedizierten Schleife im Startup-Code initialisiert. So vermeidet man 
große 0-Blöcke im Flash-Image. Das ganze ist natürlich aus C-Sicht 
unsichtbar und wird durch die Laufzeitumgebung gemacht, von der der 
Startup-Code ein Teil ist.

von Peter D. (peda)


Lesenswert?

Arduino F. schrieb:
> Funktionen mit statischen Variablen, im Bauch, sind erstmal nicht
> Wiedereintrittsfähig.
> Es drohen unerwünschte Seiteneffekte.
>
> Im Grunde sind solche Funktionen "Wegwerf Funktionen".
> Nur für dieses eine Projekt tauglich.
> Eher nicht wiederverwendbar.

Nicht generell.
Z.B. eine Entprellfunktion muß sich den alten Portzustand und den 
Entprellzähler merken. Die einzige Hardwareabhängigkeit ist das 
Porteinlesen, das man leicht als Macro oder Unterfunktion definieren 
kann. Daher ist eine solche Funktion mit statischen Variablen universell 
und leicht wiederverwendbar.

von A. S. (Gast)


Lesenswert?

mapfile schrieb:
> Und dabei ist es egal, ob mit 0 oder einem anderen Wert.

Nein, bei ungleich 0 wird kopiert, wie Stefan schrieb.

mapfile schrieb:
> In den Startup Files findet man die ganzen Abläufe.

Dann schaue es Dir auch einmal an.

von mapfile (Gast)


Lesenswert?

Achim S. schrieb:
> Dann schaue es Dir auch einmal an.

Mache ich dauernd, ich schreibe sie ja auch. ;)

Und lies mal richtig: Es werden keine Varibalen kopiert, sondern deren 
reservierten Speicherbereiche initialisiert.

von Curby23523 N. (Gast)


Lesenswert?

Wie mich dieses Gelaber aufregt, dass man dieses und jenes nicht tun 
darf, wegen gutem Programmierstil (gibts da ein Gsetzt zu?). Dass man 
nie eine static nehmen soll, weil es kein guter Stil und angeblich diese 
Funktionen nicht wiederverwendbar sind.

Leute, selbst ein goto kann man noch an manchen Stellen sinnvoll 
benutzen. Genauso eine statische Variable - sonst könnte beim nächsten 
C-Standard das beide gerne rausfliegen. Es geht hier nicht um Stil, 
sondern um Elemente der Programmiersprache. Nutze es mit Bedacht, aber 
nutze es - Fehler kann man wirklich überall einbauen.

von Einer K. (Gast)


Lesenswert?

mapfile schrieb:
> Nicht alle statischen Variablen werden mit 'static' eingeleitet. Ich
> vermute, dass auch deine Projekte voller statischer Variablen sind, du
> es nur nicht erkennst. ;)
Sicher....
Du kennst meine Programme, und darfst mich für blöd erklären.
Fein, weiter so....

Wenn es dir dabei besser geht...


---------------------



Peter D. schrieb:
> Nicht generell.
> Z.B. eine Entprellfunktion muß sich den alten Portzustand und den
> Entprellzähler merken. Die einzige Hardwareabhängigkeit ist das
> Porteinlesen, das man leicht als Macro oder Unterfunktion definieren
> kann. Daher ist eine solche Funktion mit statischen Variablen universell
> und leicht wiederverwendbar.
Das macht sie aber nicht Wiedereintrittsfähig.

Einigkeit haben wir mit Sicherheit, darin, dass eine Entprellroutine 
einen Status halten muss. Das kann sie intern tun, statisch, oder 
extern, in dem man ihr einen Zeiger auf eine Struktur übergibt.

Der zweite Weg macht sie deutlich universeller.
Wesentlich wiedereintrittsfähiger, solange sich die Pointer auf den 
Status unterscheiden.

Ansonsten, sehe ich nicht, über welche Entprellroutine du spricht....
Meine EntprellDinger haben keine statischen Variablen im Bauch.
Und irgendwelche Nachteile, kann ich da so nicht erkennen.

Und nein, ich finde, dass statische Variablen auch durch Macros nicht 
schöner werden.


---------------


Nils N. schrieb:
> (gibts da ein Gsetzt zu?)
Nein, nur einen Willen!

Funktionen mit statischen Variablen ändern ihr Verhalten in Abhängigkeit 
von der Variablen.
Das ist dann halt die Frage...
Will man das?
Wenn ja, dann gut..
Wenn nein, dann ist man ein Idiot, wenn man da eine Statische Variable 
einbaut.

Der Wille!

von mapfile (Gast)


Lesenswert?

Arduino F. schrieb:
> Sicher....
> Du kennst meine Programme

Nö, daher schrieb ich

mapfile schrieb:
> Ich
> vermute, dass auch deine Projekte

Lesen, verstehen und erst dann antworten.
Das hält Puls und Blutdruck in Grenzen. ;)

Und benutzt du jetzt statische Variablen? Gerne helfe ich beim Suchen. 
Wo gibt es Programme von dir?

von W.S. (Gast)


Lesenswert?

UnderDog schrieb:
> Was hat es denn für einen Vorteil wenn die Variable innerhalb einer
> Funktion nicht "static" ist? Performance?

Begreife doch mal das Prinzip des Ganzen.

Also:
Normale Variablen, die du innerhalb einer Funktion deklarierst, werden 
auf dem Stack angeordnet. Deshalb sind sie nach Verlassen der Funktion 
quasi weg, nicht mehr zugreifbar (bzw. werden von anderem Zeugs 
überschrieben).

Wenn man aber für eine Funktion eine persistente (also statische) 
Variable haben will, dann muß man so eine Variable eben außerhalb 
jeglicher Funktionen deklarieren. Dann landet diese Variable eben im 
ganz normalen RAM und nicht auf dem Stack.

Nun kennt C blöderweise eben keine echten Units, die ihren Inhalt 
kapseln und nur das nach außen lassen, was sie nach außen lassen wollen. 
Deshalb sind im Prinzip alle statischen Variablen in C automatisch 
globale Variablen, auf die auch von anderen Programmteilen zugegriffen 
werden kann - auch dann, wenn sie nicht in der zugehörigen Headerdatei 
auftauchen. Sie müssen woanders bloß mit "extern" benannt werden und - 
voila - der Zugriff funktioniert. Läßt man das "extern" weg, dann findet 
der Linker zwei namensgleiche Variablen im Objektcode und meckert, wenn 
man ihn läßt.

Dieser Mangel an einem ordentlichen Unitsystem in C hat viele Leute 
geärgert - und wie immer bei C wird der Mangel nicht abgestellt, sondern 
man begegnet ihm mit einem Workaround.

Natürlich kann man in jedem Programm sich diszipliniert benehmen und 
doppelte Variablennamen eben vermeiden sowie den Zugriff auf alles, was 
nicht in den Headerdateien steht, sich verkneifen.

Aber C-Programmierer hassen Disziplin und so besteht der Workaround 
darin, daß man mit "static" innerhalb einer Funktion eine globale 
Variable erzeugt, die beim Übersetzen auf irgend eine 
compilerspezifische Weise so in ihrem Namen verändert wird, daß sie mit 
keiner anderen namensgleichen Variablen kollidiert. Damit ist das eine 
globale Variable, die quasi nur von der Funktion angesprochen werden 
kann, wo sie deklariert wurde.

Nebenbei bemerkt, finde ich diese Namensgebung miserabel, man hätte das 
Ganze besser "private" nennen sollen. Ist was Ähnliches wie "typedef", 
was man besser "rename" hätte nennen sollen.

W.S.

von Dr. Sommer (Gast)


Lesenswert?

W.S. schrieb:
> Deshalb sind im Prinzip alle statischen Variablen in C automatisch
> globale Variablen, auf die auch von anderen Programmteilen zugegriffen
> werden kann - auch dann, wenn sie nicht in der zugehörigen Headerdatei
> auftauchen.

Nein, eben nicht. Markiert man eine globale Variable (außerhalb von 
Funktionen) als static, erhält sie kein Linker Symbol, sondern ist für 
andere Source Dateien unsichtbar.  Das ist die C-variante von "Kapselung 
ohne OOP".

W.S. schrieb:
> Dieser Mangel an einem ordentlichen Unitsystem in C hat viele Leute
> geärgert - und wie immer bei C wird der Mangel nicht abgestellt,

Wenn man in C alles so wie in Pascal machen würde, wäre es Pascal.

von Einer K. (Gast)


Lesenswert?

mapfile schrieb:
> Und benutzt du jetzt statische Variablen?

Natürlich!
Mein Sohn ...

Dann, wenn die Faulheit es einfordert.

von Peter D. (peda)


Lesenswert?

Arduino F. schrieb:
> Einigkeit haben wir mit Sicherheit, darin, dass eine Entprellroutine
> einen Status halten muss. Das kann sie intern tun, statisch, oder
> extern, in dem man ihr einen Zeiger auf eine Struktur übergibt.

Static sagt dem Compiler und dem Leser, die Variable hat zwar globale 
Lebensdauer, wird aber von keiner anderen Task benutzt. Dadurch läßt 
sich der Code einfacher verstehen. Eine globale Struct würde hier nur 
unnötig die Komplexität erhöhen.

von mapfile (Gast)


Lesenswert?

Arduino F. schrieb:
> Dann, wenn die Faulheit es einfordert.

Glaube ich nicht. Du wirst statische Variablen in allen deinen 
Programmen verwenden.

Nochmal als Tipp für dich: statische Variablen müssen nicht zwingend mit 
'static' eingeleitet werden. ;)
Es gibt nicht nur local statics. ;)

von Dr. Sommer (Gast)


Lesenswert?

Peter D. schrieb:
> Dadurch läßt
> sich der Code einfacher verstehen. Eine globale Struct würde hier nur
> unnötig die Komplexität erhöhen.

Wie machst du das denn, wenn man mehrere Ports entprellen möchte? Man 
braucht ja einen Satz Variablen pro Port, aber in "static"-Variablen in 
einer Funktion hat man ja nur genau einen. Da wäre es irgendwie 
intuitiver, wenn man einen "struct" pro Port hat und z.B. als globale 
"static" Variable anlegt, und den eben an die Entprell-Routinen 
übergibt.

von Dr. Sommer (Gast)


Lesenswert?

mapfile schrieb:
> Nochmal als Tipp für dich: statische Variablen müssen nicht zwingend mit
> 'static' eingeleitet werden. ;)
> Es gibt nicht nur local statics. ;)
Jetzt klär uns mal auf, was das sein soll...
So etwas:
1
int foo;
2
int main () { }
ist ja keine statische, sondern nur eine globale Variable.

von Stefan F. (Gast)


Lesenswert?

> Wie mich dieses Gelaber aufregt, dass man dieses und jenes nicht
> tun darf, wegen gutem Programmierstil

Jetzt weißt du, warum so mancher gut gebildeter Programmiere mehrere 
Anläufe braucht, um ein Team zu finden, mit dem zusammen arbeiten kann.

Ein anderer Knackpunkt den ich häufig erlebe ist, sich mit den 
Arbeitsmitteln und Libraries/Frameworks zufrieden zu geben, die 
vorgegeben wurden. Oft habe ich gehört "mit diesem alten Kram will ich 
nicht arbeiten". Es hilft einer Firma jedoch wenig, wenn der eine 
Missionar auf einen Schlag zig neue Sachen einbaut, mit denen die 
anderen dann nicht zurecht kommen.

Fortschritt ist gut, wenn er an das Lerntempo des gesamten Teams 
angepasst ist.

von Einer K. (Gast)


Lesenswert?

Gerade ein solches Team, wird mit Argwohn auf jede statische Variable 
schielen.

von Stefan F. (Gast)


Lesenswert?

> Da wäre es irgendwie intuitiver, wenn man einen "struct" pro
> Port hat und z.B. als globale "static" Variable anlegt, und
> den eben an die Entprell-Routinen übergibt.

Womit du schon einen wesentlichen Schritt in Richtung objektorientierter 
Programmierung getan hast - ganz ohne C++.

von Dr. Sommer (Gast)


Lesenswert?

Stefan U. schrieb:
>> Da wäre es irgendwie intuitiver, wenn man einen "struct" pro
>> Port hat und z.B. als globale "static" Variable anlegt, und
>> den eben an die Entprell-Routinen übergibt.
>
> Womit du schon einen wesentlichen Schritt in Richtung objektorientierter
> Programmierung getan hast - ganz ohne C++.

In C++ gehts aber trotzdem besser, da könnte man das struct als template 
ausführen und somit an die Portbreite (8,16,32 Pins) anpassen, wodurch 
der Code portabel würde! Das Wörtchen "private" hilft da sowieso.

von Peter D. (peda)


Lesenswert?

Dr. Sommer schrieb:
> Wie machst du das denn, wenn man mehrere Ports entprellen möchte? Man
> braucht ja einen Satz Variablen pro Port, aber in "static"-Variablen in
> einer Funktion hat man ja nur genau einen.

Static kann auch ein Byte-Array sein. Oder man nimmt uint64_t für bis zu 
64 Tasten.

von mapfile (Gast)


Lesenswert?

Dr. Sommer schrieb:
> ist ja keine statische, sondern nur eine globale Variable.

Sie ist statisch und global, das schließt sich nicht aus. Es ist besser 
lokale statische Variablen zu verwenden, als globale. Bei globalen 
Variablen besteht die Gefahr des Zugriffs mit Seiteneffekten. Lokale 
statische Variablen schränken die Sichtbarkeit - und damit Fehler - ein.
D. h. nicht, dass lokale statische Variablen möglichst oft einzuzsetzten 
sind, aber allemal sind sie besser als globale Variablen.

Ergo ist der folgende Satz Blödsinn
Arduino F. schrieb:
> Nur statische Variablen, auf welche man verzichtet, sind gute statische
> Variablen.

Unser Bastelfreund hat hier einfach nur falsch zitiert, denn es heisst:
Nur globale Variablen, auf die man verzichtet, sind gute globale 
Variablen. ;)

Und ja, es gibt immer Situationen, in denen eine globale Variable, ein 
goto, usw. sinnvoll sind. Das sind aber sehr, sehr, sehr wenige.

von Dr. Sommer (Gast)


Lesenswert?

Peter D. schrieb:
> Static kann auch ein Byte-Array sein. Oder man nimmt uint64_t für bis zu
> 64 Tasten.

Und woher weiß die Funktion, wie viele Ports eine konkrete Anwendung 
jetzt tatsächlich benutzt? Per #define festlegen? Ziemlich unschön...

mapfile schrieb:
> Sie ist statisch und global,
Wenn
1
int foo; int main () {}
statisch und global ist, was ist dann
1
static int foo; int main () {}
Auch statisch und global? Aber das ist ja nicht das gleiche.

mapfile schrieb:
> Und ja, es gibt immer Situationen, in denen eine globale Variable, ein
> goto, usw. sinnvoll sind. Das sind aber sehr, sehr, sehr wenige.
Wenn man auf eingebetteten Systemen C++- Klassen, aber keine dynamische 
Speicherverwaltung nutzen möchte, ist es sinnvoll "große" Objekte als 
(ggf. statische) globale Variable anzulegen, u.a. eben um den genannten 
Overhead zu sparen. Gleiches gilt sowieso für große Puffer für DMA usw. 
Globale (statische) Konstanten sind auch sauberer als #define's.
goto kann man z.B. in C sinnvoll für Fehlerbehandlung nutzen, weil es da 
keine Exceptions gibt. Fehler zu behandeln ist kein besonders seltenes 
Anliegen...

von mapfile (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Objekte als
> (ggf. statische) globale Variable anzulegen

Das Objekt selber kapselt aber die Variablen, die in einzelnen Methoden 
genutzt werden. In C hast du keine Kapsel.
Dein Apfel/Kartoffel Vergleich läßt mich an dir zweifeln. :(

Dr. Sommer schrieb:
> Wennint foo; int main () {}statisch und global ist, was ist dannstatic
> int foo; int main () {}Auch statisch und global? Aber das ist ja nicht
> das gleiche.

Das ist statisch, global und auf das Modul eingeschränkte Sichtbarkeit. 
Entscheidend ist doch die "Haltbarkeit" der Variablen, die sie zu 
statischen macht. Nach der Initialisierung bleiben sie bis zum 
Programmende erhalten, quasi statisch. ;)

von Dr. Sommer (Gast)


Lesenswert?

mapfile schrieb:
> Das Objekt selber kapselt aber die Variablen, die in einzelnen Methoden
> genutzt werden. In C hast du keine Kapsel.
In C kannst du die Variablen auch in ein struct packen, und dann 
Funktionen für den Zugriff verwenden; genau wie man das für alle anderen 
"Objekte" in C auch macht. Wenn man sich schon für C und gegen Kapselung 
und C++ entscheidet, ist das bei globalen Variablen auch kein 
Unterschied.

mapfile schrieb:
> Das ist statisch, global und auf das Modul eingeschränkte Sichtbarkeit.
Ah. Nur globale aber nicht statische Variablen gibts also nicht?

Wie heißen eigentlich statische nicht-sichtbarkeitseingeschränkte 
gloable Variablen auf Englisch, damit man das mal Googlen kann? "static 
not-externally visible variables which are not static"? Das "static" im 
Namen würde irgendwie das "static" im Quellcode implizieren.

mapfile schrieb:
> Entscheidend ist doch die "Haltbarkeit" der Variablen, die sie zu
> statischen macht. Nach der Initialisierung bleiben sie bis zum
> Programmende erhalten, quasi statisch. ;)
Das ist bei allen globalen Variablen gleich.

von mapfile (Gast)


Lesenswert?

Dr. Sommer schrieb:
> In C kannst du die Variablen auch in ein struct packen, und dann
> Funktionen für den Zugriff verwenden;

Und wenn die global sind, kann ich dann nur über die Funktionen oder 
auch direkt auf die Struktur (und darin enthaltenen Daten) zugreifen? 
Eine Struktur hat doch nichts mit Datenkapselung zu tun. Global 
angelegt, kann jeder (bei static jeder im Modul) darauf zugreifen.

Dr. Sommer schrieb:
> Nur globale aber nicht statische Variablen gibts also nicht?

Jepp, eine globale Variable ist immer statisch.

Dr. Sommer schrieb:
> Wie heißen eigentlich statische nicht-sichtbarkeitseingeschränkte
> gloable Variablen auf Englisch, damit man das mal Googlen kann?

https://en.wikipedia.org/wiki/Global_variable

Und danke für den Hinweis, denn im Text steht das, genau so:
"...  In compiled languages, global variables are generally static 
variables, whose extent (lifetime) is the entire runtime of the program 
..."

Dr. Sommer schrieb:
> Das ist bei allen globalen Variablen gleich.

Jepp, die sind ja auch immer statisch. ;)

@Sommer
Bevor du jetzt weitere Veränkungen anstellts und von C++ nach Python 
oder sonst was ausweichst: Im Titel steht "C". Und darüber sollten wir 
in diesem Thread auch schreiben.

von Dr. Sommer (Gast)


Lesenswert?

mapfile schrieb:
> Eine Struktur hat doch nichts mit Datenkapselung zu tun. Global
> angelegt, kann jeder (bei static jeder im Modul) darauf zugreifen.
Ach, womit denn sonst?
Also ich kenn das in C z.B. so:
1
struct X {
2
  int a, b, c;
3
};
4
void doSomething (struct X* x) {
5
  x->a += a->b + a->c;
6
}
7
int main () {
8
  struct X x { 1, 2, 3 };
9
  doSomething (&x);
10
}
Das ist eine ganz typische Verwendung von strukturierten Daten, 
angenähert objektorientiert. C-Programmierer erkennen hier normalerweise 
nichts schlechtes dran, obwohl man die "geheimen" Member a, b, c von 
außen modifizieren kann. Wenn ich die "x" variable jetzt einfach global 
mache, ists plötzlich schlecht?
1
struct X x { 1, 2, 3 };
2
int main () {
3
  doSomething (&x);
4
}

mapfile schrieb:
> Jepp, eine globale Variable ist immer statisch.
> Und danke für den Hinweis, denn im Text steht das, genau so:
> "...  In compiled languages, global variables are generally static
Das ist eine eher theoretische Betrachtung. Ich kannte das immer so, 
dass man in C mit "static" Variablen immer eine meint, an der auch 
"static" dran steht, weil das sonst ziemlich verdreht wäre. Das sehen 
auch andere so:
http://codingstreet.com/c-basic-questions/what-is-difference-between-global-and-static-variables-in-c/
https://stackoverflow.com/a/13162135

Wenn man es ganz genau haben will, sollte man sagen dass alle globalen 
Variablen "static storage duration" haben (§6.2.4 im Standard), und die 
mit "static" keyword haben "internal linkage" (6.2.2). Aber einfach alle 
globalen Variablen als "static/statisch" zu bezeichnen finde ich 
uneindeutig/verwirrend.

mapfile schrieb:
> Bevor du jetzt weitere Veränkungen anstellts und von C++ nach Python
> oder sonst was ausweichst:
Das hab ich doch gar nicht gemacht.

von mapfile (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Aber einfach alle
> globalen Variablen als "static/statisch" zu bezeichnen finde ich
> uneindeutig/verwirrend.

Der Kernpunkt dabei ist, dass die Eingenschaft statisch nicht zwingend 
durch das Schlüsselwort 'static' eingeleitet werden muss. Und dass das 
Schlüsselwort 'static' auch für die Einschränkung der Sichbarkeit 
genutzt wird. Wenn du das verwirrend findest, wie erklärst du dir dann 
das Schlüsselwort 'static' bei Funktionen ("C"-Funktionen). Sind alle 
sonstigen C-Funktionen dynamisch? ;)))

Dr. Sommer schrieb:
> Das ist eine ganz typische Verwendung von strukturierten Daten,
> angenähert objektorientiert. C-Programmierer erkennen hier normalerweise
> nichts schlechtes dran, obwohl man die "geheimen" Member a, b, c von
> außen modifizieren kann.

Wo bitte schön ist da etwas mit OOP? Du hast eine lokale Variable, die 
an eine Funktion übergeben wird. Du kannst 1, 2, 3 auch als einzelne 
Parameter übergeben. Du hast die Einzelwerte in der Struktur zusammen 
gefasst, aber keine Schale (Kapsel) drumherum. Und natürlich kann man 
nicht ausserhalb der main() auf x.a zugreifen. (???) :(((
Zeig doch bitte den Zugriff anhand deines Beispiels. ;)))

Dr. Sommer schrieb:
> Wenn ich die "x" variable jetzt einfach global
> mache, ists plötzlich schlecht?

Ja, ist unglücklich, da (erst) jetzt jeder zugreifen kann.
1
...
2
void foo (void);
3
4
struct X x { 1, 2, 3 };
5
int main () {
6
  doSomething (&x);
7
  ...
8
  foo ();
9
}
10
11
void foo (void) {
12
  x.a = 0;
13
}

Dr. Sommer schrieb:
> Das hab ich doch gar nicht gemacht.

Dr. Sommer schrieb:
> Wenn man auf eingebetteten Systemen C++- Klassen ...

Selbstsprechend, oder? ;)

von Dr. Sommer (Gast)


Lesenswert?

mapfile schrieb:
> Der Kernpunkt dabei ist, dass die Eingenschaft statisch nicht zwingend
> durch das Schlüsselwort 'static' eingeleitet werden muss.
Sag doch bitte, die Eigenschaft "static storage duration". Alles andere 
verwirrt. Dann wäre die ganze Diskussion gar nicht erst entstanden.

mapfile schrieb:
> Sind alle
> sonstigen C-Funktionen dynamisch? ;)))
Globale nicht-"static" Variablen sind auch nicht "dynamisch". Ich kannte 
das einfach nur so, ist so auch alles intuitiv klar:
* Globale Funktionen & Variablen mit "static" nennt man auch einfach 
"static" (Deutsch: "statisch")
* Globale Funktionen ohne static sind einfach "normal", ohne weiteren 
Zusatz (genau genommen haben sie "external linkage").
* Globale Variablen ohne static sind einfach nur "global" (dito zu 
"external linkage").
* Alle globalen Variablen existieren für die gesamte Programmdauer 
(haben "static storage duration").

mapfile schrieb:
> Wo bitte schön ist da etwas mit OOP?
Zusammenhängende Daten werden in einem "struct" zusammengefasst. Eine 
Instanz davon ist ein "Objekt". Zu diesem Objekt gehören Funktionen 
(hier ungeschickterweise "doSomething" genannt; besser wäre 
"X_doSomething" o.ä.), die die Daten manipulieren. So wird es bspw. in 
den großen Bibliotheken GLib und Gtk+ gemacht. Eine andere Art, in C 
objektorientiert zu programmieren, ist mir nicht bekannt, außer 
vielleicht dem "pImpl" Pattern, aber das funktioniert im Endeffekt 
genauso.

mapfile schrieb:
> Du kannst 1, 2, 3 auch als einzelne
> Parameter übergeben.
Dann gehören sie aber konzeptuell nicht mehr zusammen.

mapfile schrieb:
> Du hast die Einzelwerte in der Struktur zusammen
> gefasst, aber keine Schale (Kapsel) drumherum.
Die gibt's in C auch nicht. Aber wir haben ja angenommen, dass man, 
warum auch immer, auf C besteht.

mapfile schrieb:
> Und natürlich kann man
> nicht ausserhalb der main() auf x.a zugreifen.
Aber innerhalb der main(), außerhalb der zu X gehörigen Funktion 
"X_doSomething". Das ist genauso falsch, lässt sich aber in C nunmal 
nicht verhindern, was aber in Kauf genommen wird. Bei globalen Variablen 
geht diese Verletzung der Kapselung halt nur einem größeren Bereich. Das 
kann man genauso in Kauf nehmen.

mapfile schrieb:
> Dr. Sommer schrieb:
>> Wenn man auf eingebetteten Systemen C++- Klassen ...
>
> Selbstsprechend, oder? ;)
Das war eine komplett andere Diskussion.

von mapfile (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Zusammenhängende Daten werden in einem "struct" zusammengefasst. Eine
> Instanz davon ist ein "Objekt". Zu diesem Objekt gehören Funktionen

Dr. Sommer schrieb:
>> Du hast die Einzelwerte in der Struktur zusammen
>> gefasst, aber keine Schale (Kapsel) drumherum.
> Die gibt's in C auch nicht.

Erkennst du den Widerspruch?

In C kannst du keine Objekte erzeugen! Du bekommst die Daten und 
Funktionen (wären dann Mehtoden) nicht gekapselt.

Dr. Sommer schrieb:
> Aber innerhalb der main(), außerhalb der zu X gehörigen Funktion
> "X_doSomething". Das ist genauso falsch, lässt sich aber in C nunmal
> nicht verhindern

???

Wenn du doSomething() als Objektinstanz siehst (für mich etwas sehr 
weit hergeholt), solltest du x als static in doSomething() definieren.

Dr. Sommer schrieb:
> Bei globalen Variablen
> geht diese Verletzung der Kapselung halt nur einem größeren Bereich.

Das ist dann aber keine Kapselung mehr, oder?

@Sommer
Noch einmal zum Ursprung: Ein Fanboy haut die Parole raus, dass in "C" 
lokale 'static' definierte Variablen der totale Humbug sind.

Und jetzt erklärst du mir, dass (Modul- oder auch nicht) globale 
Variablen die bessere Lösung dafür sind?

(Mit OOP und Kapselung lassen wir noch aussen vor.) ;)

von Einer K. (Gast)


Lesenswert?

mapfile schrieb:
> Ein Fanboy haut die Parole raus, dass in "C"
> lokale 'static' definierte Variablen der totale Humbug sind.
Entweder lügst du bewusst, oder du verstehst einfach nur meine Texte 
nicht.

von mapfile (Gast)


Lesenswert?

Arduino F. schrieb:
>> Ein Fanboy haut die Parole raus, dass in "C"
>> lokale 'static' definierte Variablen der totale Humbug sind.
> Entweder lügst du bewusst, oder du verstehst einfach nur meine Texte
> nicht.

Arduino F. schrieb:
> Ansonsten gilt der Leitsatz:
> Nur statische Variablen, auf welche man verzichtet, sind gute statische
> Variablen.

Hoffentlich verstehst du deine eigenen Texte noch. ;)

von Dr. Sommer (Gast)


Lesenswert?

mapfile schrieb:
> Erkennst du den Widerspruch?
Nö. Bevor wir das weiter auseinandernehmen, wie machst du denn OOP in C? 
Ich kenn das so wie z.B. hier:
https://developer.gnome.org/glib/stable/glib-Strings.html#GString
Man hat ein "struct", hier "GString" wo zusammengehörige Daten 
zusammengepackt werden. Auf diese greift man über eine Reihe von 
Funktionen namens "g_string_xx" zu. Man kann auch direkt auf die Member 
von Außen zugreifen, aber so könnte man die Daten in einen 
inkonsistenten Zustand bringen. So ist das nunmal in C.

Ein solches struct könnte man so verwenden:
1
int main () {
2
  GString* str = g_string_new (NULL);
3
  str->len = 7; // verboten!
4
  g_string_append (str, "foo");
5
  g_string_free (str);
6
}
Diese Nutzung scheint von C-Programmierern akzeptiert zu werden, auch 
wenn der falsche Zugriff vom Compiler nicht verhindert wird. Das ist 
m.W. das übliche Schema von OOP in C, es wird in der Doku sogar von 
"Object" geredet.

Wenn man jetzt die "str" Variable global macht:
1
GString* str;
2
3
int main () {
4
  str = g_string_new (NULL);
5
  test ();
6
  g_string_append (str, "foo");
7
  g_string_free (str);
8
}
9
10
void test () {
11
  str->len = 7; // verboten!
12
}
kann man halt in mehreren Funktionen "verbotene" Zugriffe durchführen. 
Das ist m.M.n. jetzt auch nicht viel schlimmer. Das erkauft man eben 
durch das Bestehen auf C.

mapfile schrieb:
> Wenn du doSomething() als Objektinstanz siehst (für mich etwas sehr
> weit hergeholt), solltest du x als static in doSomething() definieren.
Nein, als (Nachbildung einer) "Member"-Funktion. das "x" ist die Instanz 
(Objekt). Es wird halt explizit als Parameter übergeben, statt implizit 
als "this" wie in C++.
Eine Funktion mit lokaler "static" Variable könnte man als Instanz 
ansehen, oder eine .c Datei mit diversen (ggf. "static") globalen 
Variablen als ein Singleton. Finde ich beides eher unschön.

mapfile schrieb:
> Das ist dann aber keine Kapselung mehr, oder?
Es ist Kapselung soweit wie C es eben ermöglicht.

mapfile schrieb:
> Und jetzt erklärst du mir, dass (Modul- oder auch nicht) globale
> Variablen die bessere Lösung dafür sind?
In C++ u.U. schon, aber nicht generell... Ich finde Variablen mit 
"static storage duration" (also alle globalen und solche mit "static", 
quasi Singletons) generell etwas unsauber, sofern sie nicht konstant 
sind. Funktionslokale statische Variablen sind hinterhältigerweise auch 
noch versteckt.
Bei eingebetteten Systemen ist es (mangels dynamischer 
Speicherverwaltung - aber das ist eine andere Diskussion) aber oft 
erforderlich, Dingen eine "static storage duration" zu verpassen. Ich 
finde es persönlich am saubersten, alle solche Variablen, die in einer 
Anwendung gebraucht werden, an eine Stelle (typischerweise die 
main.c(pp)) zu packen, und dann darauf nur Member-Funktionen (C++) bzw. 
die o.g. "Pseudo-Member-Funktionen" (C) aufzurufen. Das erfordert 
natürlich, dass alles sauber in (verschachtelten) structs bzw. Klassen 
verpackt ist - so braucht man nur eine Hand voll solcher globaler 
Variablen, anstatt eines Riesenwusts an Integern o.ä.
Das sehe ich aber mehr als Idealvorstellung, nicht als zwingende Regel. 
Die anderen Varianten (globale oder funktionslokale "static" Variablen) 
würde ich nicht prinzipiell verbieten.

von W.S. (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Nein, eben nicht. Markiert man eine globale Variable

kannst du eigentlich lesen? Genau dieses Detail habe ich dem TO 
ausführlich erklärt.

W.S.

von Dr. Sommer (Gast)


Lesenswert?

W.S. schrieb:
> kannst du eigentlich lesen? Genau dieses Detail habe ich dem TO
> ausführlich erklärt.

Mit falschen Aussagen? Total hilfreich.

von mapfile (Gast)


Lesenswert?

Dr. Sommer schrieb:
> wie machst du denn OOP in C?

Gar nicht, weil es nicht geht. ;)
Aber natürlich strukturiere ich Programme, teile sie in Module auf und 
verbinde die Module per Funktionsaufrufe (und nicht über globale 
Variablen). Aber das ist noch lange keine OOP!
Ich kann über diesen Weg in C keine Instanzen von Objekten anlegen.

Wie du jetzt selber erkannt hast, gibt es keine Kapselung:
Dr. Sommer schrieb:
> auch
> wenn der falsche Zugriff vom Compiler nicht verhindert wird
Dr. Sommer schrieb:
> kann man halt in mehreren Funktionen "verbotene" Zugriffe durchführen

Mit dem folgenden Beitrag schlage ich dich zum Aussenminister oder 
sonstigem "wasch mich, aber mach mich nicht nass" Oberdiplomaten vor. 
;)))
Dr. Sommer schrieb:
>> Das ist dann aber keine Kapselung mehr, oder?
> Es ist Kapselung soweit wie C es eben ermöglicht.
Wenn ich das nächste Mal geblitzt werde, sage ich: Ich bin so langsam 
gefahren, wie es meine Zeit zulässt. ;)))



Dr. Sommer schrieb:
> Ich
> finde es persönlich am saubersten, alle solche Variablen, die in einer
> Anwendung gebraucht werden, an eine Stelle (typischerweise die
> main.c(pp)) zu packen, und dann darauf nur Member-Funktionen (C++) bzw.
> die o.g. "Pseudo-Member-Funktionen" (C) aufzurufen.
D. h. jede statische Variable (Instanz) wird global in einem zentralen 
Modul definiert und erhält eigene Zugriffsfunktionen?
Nur so als Hinweis: Ich kann die Variable ausserhalb des "eine Stelle" 
Moduls nicht sehen. ;)

Wenn du hierfür ein kleines C Projekt zeigen könntest. >:>>>

von W.S. (Gast)


Lesenswert?

Arduino F. schrieb:
> Einigkeit haben wir mit Sicherheit, darin, dass eine Entprellroutine
> einen Status halten muss. Das kann sie intern tun, statisch, oder
> extern, in dem man ihr einen Zeiger auf eine Struktur übergibt.
>
> Der zweite Weg macht sie deutlich universeller.
> Wesentlich wiedereintrittsfähiger, solange sich die Pointer auf den
> Status unterscheiden.

Nö. Beides grundfalsch.

Deine Denkweise ist schlichtweg falsch, denn du versuchst, sowas wie 
eine allgemeine Entprellroutine zu etablieren, der man dann irgend einen 
Input zuweist. Das ist das Grundfalsche.

Weitaus besser ist es, Ebenen in eine Firmware einzuziehen. Das 
bedeutet, daß man einen lowlevel-Treiber für seine Tasten (o.ä.) hat, 
der nur über eine abstrahierend definierte Schnittstelle mit den 
höheren Programmschichten kommuniziert und der sich intern ansonsten um 
genau die Tasten oder ähnliche Input's kümmert, die wirklich im 
aktuellen Projekt an den aktuellen Stellen der Hardware vorhanden sind.

Zwei kleine Beispiele in Neudenglisch:
a) per Polling:
1
void InitTasten(void);
2
bool IstTasteAvailable(void);
3
char GetTastenCode(void);

b) per Event:
1
void InitTasten(void);
2
// und sonst nix, da Tastatur-Ereignisse vom LL-Treiber
3
// in die allgemeine Event-Queue eingespeist werden

Das bedeutet, daß man zum Portieren oder für ein anderes Projekt eben 
nur genau diesen lowlevel-Treiber an die anderen Verhältnisse anpassen 
muß. Das Gute daran ist, daß wirklich alles Zeugs inclusive 
projektangepaßter Statusbits in irgendwelchen treiberinternen Variablen 
innerhalb des Treibers bleiben kann (und sollte), so daß alle anderen 
Programmteile mit diesen konkreten Details einfach nichts zu tun haben. 
Obendrein kann dann der Treiber sehr viel einfacher und übersichtlicher 
formuliert werden, als bei deiner Verfahrensweise.

W.S.

von mapfile (Gast)


Lesenswert?

W.S. schrieb:
> Deine Denkweise ist schlichtweg falsch, denn du versuchst, sowas wie
> eine allgemeine Entprellroutine zu etablieren, der man dann irgend einen
> Input zuweist. Das ist das Grundfalsche.

Na ja, das ist nicht unbedingt schlecht, eine universelle 
Entprellroutine, Filterroutine, Skalierroutine, ...

Nimm ein anderes Beispiel, CRC-Berechnung. Wenn du mehrere low level 
Treiber für unterschiedliche Schnittstellen hast, schreibst du doch auch 
nicht für jeden Treiber eine extra angepasste CRC-Routine. ;)

von Dr. Sommer (Gast)


Lesenswert?

mapfile schrieb:
> Ich kann über diesen Weg in C keine Instanzen von Objekten anlegen.

Wenn du das so siehst, ist die Diskussion hinfällig. OOP ist ein 
abstraktes Konzept, das von den diversen Programmiersprachen mehr oder 
weniger gut unterstützt wird. Viele sind sich einig, dass man auch in C 
objektorientiert programmieren kann, was aber mehr Disziplin erfordert; 
siehe eben GLib, GObject usw. Wie würdest du denn die gezeigte GString 
Implementation bezeichnen? Es geht ja schon über "Prozedural" oder 
"strukturiert" hinaus.

mapfile schrieb:
> Wenn ich das nächste Mal geblitzt werde, sage ich: Ich bin so langsam
> gefahren, wie es meine Zeit zulässt. ;)))
Ich sag einfach, "Ich hab die Geschwindigkeitsangabe in Meilen/Stunde 
interpretiert!"

mapfile schrieb:
> D. h. jede statische Variable (Instanz) wird global in einem zentralen
> Modul definiert und erhält eigene Zugriffsfunktionen?
Die Instanz erhält keine Funktionen. Die "Klasse" hat welche.

mapfile schrieb:
> Nur so als Hinweis: Ich kann die Variable ausserhalb des "eine Stelle"
> Moduls nicht sehen. ;)
So soll es sein.

mapfile schrieb:
> Wenn du hierfür ein kleines C Projekt zeigen könntest. >:>>>
Ich mach sowas normalerweise nur in C++. Sehr rudimentär ginge es so:
1
// ringbuffer.h
2
static const size_t bufferSize = 1024;
3
struct RingBuffer { ... };
4
void RingBuffer_Init (struct RingBuffer* rb);
5
void RingBuffer_Put (struct RingBuffer* rb, char data);
6
char RingBuffer_Pop (struct RingBuffer* rb);
1
// Sensor.h
2
struct Sensor { struct RingBuffer* rb; ... };
3
void Sensor_Init (struct Sensor* s, struct RingBuffer* rb);
4
void Sensor_I2C_Interrupt (struct Sensor* s);

Bis hier ist der Code flexibel und wiederverwendbar; erst in der main.c 
werden die Instanzen angelegt und verbunden, s.d. man simpel z.B. 
mehrere davon anlegen kann ohne die vorigen Dateien ändern zu müssen:
1
// main.c
2
static struct RingBuffer MyRingBuffer;
3
static struct Sensor MySensor;
4
5
void I2C2_IRQ (void) {
6
  Sensor_I2C_Interrupt (&MySensor);
7
}
8
9
int main () {
10
  RingBuffer_Init (&MyRingBuffer);
11
  Sensor_Init (&MySensor, &MyRingBuffer);
12
  
13
  while (1) sleep ();
14
}

So sieht man in der main.c automatisch was es so alles an Daten gibt. Es 
gibt keinen "versteckten" Zustand. Nur die Konstante(!) "bufferSize" ist 
woanders definiert.

W.S. schrieb:
> Deine Denkweise ist schlichtweg falsch, denn du versuchst, sowas wie
> eine allgemeine Entprellroutine zu etablieren, der man dann irgend einen
> Input zuweist. Das ist das Grundfalsche.
Warum? Das ist das Grundprinzip der Wiederverwendbarkeit, was der 
Hauptgrund für einen Großteil des Aufwands bezüglich Programmstruktur 
ist. Man könnte so ein Routine ja auch für Ports am Portexpander nutzen, 
wenn man eben flexibel neue Instanzen anlegen kann, indem man ein 
globales struct (pro Pin) hinzufügt.

W.S. schrieb:
> Zwei kleine Beispiele in Neudenglisch:
> a) per Polling:void InitTasten(void);
> bool IstTasteAvailable(void);
> char GetTastenCode(void);
Hier sieht man genau das Problem - die Routinen greifen immer auf die 
gleichen Ports zu. Wiederverwendbar wirds, wenn man pro gewünschter 
Taste ein "Objekt" (in C: ein struct) anlegt, und das an die Funktion 
übergibt. So wird's z.B. im Linux-Kernel gemacht; das ermöglicht erst, 
z.B. mehrere Tastaturen anzuschließen. Pro Tastatur wird ein neues 
"struct Keyboard" erzeugt, und dann sowas wie "get_keycode (struct 
Keyboard* kbd)" aufgerufen.

Beitrag #5268819 wurde von einem Moderator gelöscht.
von mapfile (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Es geht ja schon über "Prozedural" oder
> "strukturiert" hinaus.

Nö, genau das ist es.

Dr. Sommer schrieb:
> Ich sag einfach, "Ich hab die Geschwindigkeitsangabe in Meilen/Stunde
> interpretiert!"

Gibt es trotzdem ein Tiket, oder nicht?
=> Unwissenheit schützt ...

Dr. Sommer schrieb:
> Die Instanz erhält keine Funktionen. Die "Klasse" hat welche.

??? Es gibt doch keine Klasse. Ich kann doch keine Objekte (gekapselte 
Daten mit zugehörigen Methoden) instanzieren.

Dr. Sommer schrieb:
> Ich mach sowas normalerweise nur in C++

Dann solltest du dabei bleiben und nicht über C philosophieren. ;)

Dr. Sommer schrieb:
>> Wenn du hierfür ein kleines C Projekt zeigen könntest. >:>>>
> ... Sehr rudimentär ginge es so:
Was bitte schön ist daran OOP? Du hast 08/15 C Module geschaffen, denen 
du Parameter übergibst.
???

Aber danke, für dein Beispiel. Es öffnet die Augen, über deine aktuelle 
Stellung in der Programmierung. Ich wünsche dir noch einen schönen 
Abend. :)

von Dr. Sommer (Gast)


Lesenswert?

mapfile schrieb:
> Nö, genau das ist es.
Deiner Meinung nach ist Code ohne "private:" also kein OOP?

mapfile schrieb:
> Dann solltest du dabei bleiben und nicht über C philosophieren. ;)
Na, wenn du alles besser weißt. Jedenfalls ist es gängige Meinung, dass 
man in C objektorientiert programmieren kann und dass es genau so wie in 
den gezeigten Beispielen geht. Wenn bei dir alles anders ist, ist die 
Diskussion sinnfrei.

mapfile schrieb:
> Was bitte schön ist daran OOP?
Zusammengehörige Daten werden in einer "Einheit" (hier: struct) 
zusammengefasst und mit Funktionen versehen (hier: durch Namenspräfixe), 
die die Daten unter Einhaltung der Invarianten bearbeiten.

Prozedural und strukturiert wäre es, wenn die Innereien des "RingBuffer" 
globale ("static") Variablen in der ringbuffer.c wären, und es kein 
"struct RingBuffer" gäbe.

mapfile schrieb:
> Du hast 08/15 C Module geschaffen, denen
> du Parameter übergibst.
Definiere "Modul". Und was hast du erwartet? Es ist eine klassische (ja, 
objektorientierte) Programmstruktur, bei der funktionslokale "static" 
nicht-konstante Variablen vermieden werden. Du wolltest es so genau 
wissen...

mapfile schrieb:
> Aber danke, für dein Beispiel. Es öffnet die Augen, über deine aktuelle
> Stellung in der Programmierung. Ich wünsche dir noch einen schönen
> Abend. :)
Was auch immer das heißen soll. Du hast doch außer deinen eigenen 
Privat-Definitionen gängiger Begriffe auch noch nichts beigetragen; ich 
wüsste nicht, was am Erläutern der "Lehrmeinung" so falsch ist.

von Dr. Sommer (Gast)


Lesenswert?

Hier noch ein Beispiel wie man auch in C eine Kapselung erreicht (ja, 
auch nichts neues):
1
// ringbuffer.h
2
struct RingBuffer;
3
struct RingBuffer* RingBuffer_New (size_t size);
4
void RingBuffer_Free (struct RingBuffer* rb);
5
void RingBuffer_Put (struct RingBuffer* rb, char data);
6
char RingBuffer_Pop (struct RingBuffer* rb);
1
// ringbuffer.c
2
struct RingBuffer {
3
  char* data;
4
  size_t size, wptr, rptr, fill;
5
};
6
struct RingBuffer* RingBuffer_New (size_t size) {
7
  struct RingBuffer* rb = malloc (sizeof (struct RingBuffer));
8
  if (!rb) return NULL;
9
  rb->data = ...;
10
  return rb;
11
}
1
// main.c
2
3
static struct RingBuffer* globalRB;
4
5
int main () {
6
  struct RingBuffer* localRB = RingBuffer_New (1024);
7
  globalRB = RingBuffer_New (1024);
8
9
  // ...
10
  
11
  RingBuffer_Free (globalRB);
12
  RingBuffer_Free (localRB);
13
}

In dieser Form müsste das ja deiner Definition nach echte 
Objektorientierung sein, weil man nicht von außen auf die Member 
zugreifen kann. Somit sind sowohl die lokale als auch die globale 
Instanz gekapselt. Braucht aber dynamische Speicherverwaltung und ist 
somit für eingebettete Systeme nur bedingt geeignet.

von mapfile (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Du hast doch außer deinen eigenen
> Privat-Definitionen gängiger Begriffe auch noch nichts beigetragen

Na ja, das engl. Wiki sieht das anders und teilt meine Meinung. Hab 's 
ja oben irgendwo verlinkt.
Und die Definition und Begriffe zur OOP solltest du im deu. Wiki 
nachschlagen:
https://de.wikipedia.org/wiki/Objektorientierte_Programmierung
Deckt sich auch mit meiner Meinung. Kannst ja Mal schauen, wie nahe du 
daran bist. ;)

Dr. Sommer schrieb:
> Jedenfalls ist es gängige Meinung, dass
> man in C objektorientiert programmieren kann

Habe ich noch nie gesehen. Zentrale Bestandteile der OOP lassen sich in 
C nicht abbilden. Siehe auch im Wiki, da du ja den Verweis auf allgm. 
Wissen wünschst.

Dr. Sommer schrieb:
> mit Funktionen versehen (hier: durch Namenspräfixe),
> die die Daten unter Einhaltung der Invarianten bearbeiten

Heisst nichts anderes, als dass die OOP durch die (hoffentliche) 
Einhaltung besonderer Wünsche (nicht C, sondern 'sommerlicher' Zusatz) 
durch jeden Programmierer zu jeder Zeit erfolgt. Kein am Projekt 
Beteiligter darf einen Fehler bei der Namensgebung oder den 
Datenzugriffen machen. Menschliche Fehler sind generell verboten, denn 
Compiler, Linker und Co. helfen nicht und lösen solche Fehler nicht auf.
Au Backe. ;)

Dr. Sommer schrieb:
> Es ist eine klassische (ja,
> objektorientierte) Programmstruktur

Es ist ein stinknormales C Programm, dass aus mehreren Modulen besteht. 
Vgl. die Compiler Libs. Das lernt der C-ler in der dritten 
Unterrichtsstunde. Da steckt wirklich nichts objektorientiertes darin, 
sorry. Selbst wenn man mit ner Lupe hinguckt. :(

Dr. Sommer schrieb:
> Was auch immer das heißen soll

Dass ich - als netter Mensch - dir einen schönen Abend wünsche. ;)

von mapfile (Gast)


Lesenswert?

Dr. Sommer schrieb:
> In dieser Form müsste das ja deiner Definition nach echte
> Objektorientierung sein, weil man nicht von außen auf die Member
> zugreifen kann.

???

Anstatt der Variablen hast du jetzt einen Pointer und allokierst 
Speicher. Was ändert das an der Kapselung?

Dr. Sommer schrieb:
> In dieser Form müsste das ja deiner Definition nach echte
> Objektorientierung sein, weil man nicht von außen auf die Member
> zugreifen kann.

Nö, ich glaube, du hast OOP nicht verstanden. Und dynamische 
Speicherverwaltung auch nicht. :(
Jeder im Modul kann auf den modulglobalen Pointer zugreifen. Egal wann 
der Speicher dahinter allokiert wird. Und die lokale Variable in main() 
ist auch nichts besonderes. Wenn du das als OOP ansiehst, wäre jeder 
Funktionsaufruf mit einer lokalen Variable OOP!

Das wird immer besser hier. ;)

von Dr. Sommer (Gast)


Lesenswert?

Ich hör nur "nein, nein, nein, mimimi".

https://stackoverflow.com/questions/351733/can-you-write-object-oriented-code-in-c
https://wr.informatik.uni-hamburg.de/_media/teaching/wintersemester_2013_2014/epc-1314-droste-oop-praesentation.pdf
https://www.codementor.io/michaelsafyan/object-oriented-programming-in-c-du1081gw2
https://www.cs.rit.edu/~ats/books/ooc.pdf
usw.

https://www.google.de/search?q=oop+in+c => 36 Mio. Ergebnisse.

mapfile schrieb:
> Anstatt der Variablen hast du jetzt einen Pointer und allokierst
> Speicher. Was ändert das an der Kapselung?
Man kann in der main.c nicht auf die Member des Objekts direkt 
zugreifen. Genau wie in "richtigen" OOP-Sprachen.

mapfile schrieb:
> Nö, ich glaube, du hast OOP nicht verstanden. Und dynamische
> Speicherverwaltung auch nicht. :(
Genau, die ganze Welt versteht es falsch, nur du nicht!

mapfile schrieb:
> Jeder im Modul kann auf den modulglobalen Pointer zugreifen.
Logisch. Das ist der Grund, warum man globale Variablen nutzt. Aber 
keiner kann die Interna kaputt machen.

So, und jetzt geh woanders trollen.

von mapfile (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Man kann in der main.c nicht auf die Member des Objekts direkt
> zugreifen.

Natürlich kann man auf die globale Variable innerhalb der main.c 
zugreifen. Warum denn nicht. Wenn man Pech hat, wurde noch kein Speicher 
'hinter' dem Pointer allokiert. Aber das hat doch nichts, rein gar 
nichts, mit OOP zu tun. :(((

Dr. Sommer schrieb:
> Genau, die ganze Welt versteht es falsch

Nö, du bist nicht die Welt. ;)

Dr. Sommer schrieb:
>> Jeder im Modul kann auf den modulglobalen Pointer zugreifen.
> Logisch. Das ist der Grund, warum man globale Variablen nutzt. Aber
> keiner kann die Interna kaputt machen.

Warum kann jemand, der auf den Pointer zugreifen kann, nicht die Daten - 
auf die er zeigt - verändern können (wenn sie nicht const sind, im ROM 
liegen, ... Nur damit nicht neue Schauplätze geöffnet werden)?

Ich gehe einmal davon aus, dass du deine Links gelesen hast. Hast du sie 
auch verstanden? Ein Tipp, der Schwerpunkt liegt in Funktionszeigern, 
die innerhalb der Strukturen liegen. Das sit weit weg von dem, was du 
hier gezeigt hast.

Hier noch ein Zitat aus deinem Link 
(https://www.codementor.io/michaelsafyan/object-oriented-programming-in-c-du1081gw2):
"... Although, in some cases, the boilerplate that this approach 
generates may not always be worthwhile, writing imperative C code in OOP 
style can illuminate how OOP works. The ability to write in this style 
is also valuable for creating APIs that are shared between OOP and 
non-OOP languages ..."

Wer ist hier wohl der Troll? ;)

von Alles Humbug (Gast)


Lesenswert?

mapfile an Dr. Sommer

> Und die Definition und Begriffe zur OOP solltest du im deu. Wiki
> nachschlagen:

> Ich gehe einmal davon aus, dass du deine Links gelesen hast. Hast du sie
> auch verstanden? Ein Tipp, der Schwerpunkt liegt in Funktionszeigern,
> die innerhalb der Strukturen liegen. Das sit weit weg von dem, was du
> hier gezeigt hast.

> ich glaube, du hast OOP nicht verstanden. Und dynamische
> Speicherverwaltung auch nicht. :(

Ts ts, mein Gott habt ihr die Begriffe hier zerpflückt. Da wird einem ja 
ganz schummrig von.

@ Doc Sommer

Ist irgendwie nicht dein Tag heute was?

;-)

von Alex G. (dragongamer)


Lesenswert?

Also an der Uni lernt man auch dass Cpp objektorientiert ist. C nicht...

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

W.S. schrieb:
> Nun kennt C blöderweise eben keine echten Units, die ihren Inhalt
> kapseln und nur das nach außen lassen, was sie nach außen lassen wollen.
> Deshalb sind im Prinzip alle statischen Variablen in C automatisch
> globale Variablen, auf die auch von anderen Programmteilen zugegriffen
> werden kann - auch dann, wenn sie nicht in der zugehörigen Headerdatei
> auftauchen. Sie müssen woanders bloß mit "extern" benannt werden und -
> voila - der Zugriff funktioniert. Läßt man das "extern" weg, dann findet
> der Linker zwei namensgleiche Variablen im Objektcode und meckert, wenn
> man ihn läßt.

Das ist so nicht korrekt.

Wird in einem C-Modul außerhalb einer Funktion eine Variable 
definiert, ist sie global, und nicht statisch.

Dann wird ihr Name als Symbol in der Objektdatei exportiert und der 
Linker kann entsprechende Referenzen aus anderen Modulen auflösen.

Wird die Variable aber als static deklariert, ist sie statisch, und 
nur innerhalb des entsprechenden C-Moduls sichtbar. Ihr Name wird 
nicht als Symbol exportiert und es ist nicht möglich, mit externen 
Referenzen* aus anderen Objektdateien auf diese Variable zuzugreifen, 
weil der Linker diese Referenzen nicht auflösen kann.

Eine "extern"-Deklaration in einer Headerdatei ändert daran nichts.

Exakt das gleiche Verhalten gibt es mit Funktionsdefinitionen - eine als 
static definierte Funktion ist nur innerhalb des C-Modules sichtbar, 
in dem sie definiert wird, es gibt keinen Symbolnamen in der Objektdatei 
und ein Aufruf aus anderen Modulen heraus ist nicht möglich, da der 
Linker entsprechende Referenzen nicht auflösen kann.

Damit ist das von Dir gewünschte "Unit"-Kapselungsverhalten 1:1 in C 
umsetzbar.

Das Schlüsselwort static hat in C aber auch noch eine andere 
Bedeutung, wird es zur Definition einer Variablen innerhalb einer 
Funktion verwendet, ist diese Variable keine automatische Variable, 
d.h. sie landet nicht auf dem Stack und ihr Inhalt bleibt über mehrere 
Funktionsaufrufe hinweg erhalten.


*) hier sind nicht "Referenzen" im C++-Sinne gemeint.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Ihr seid ja schnuckelig....
Kaum ist man ein paar Stunden nicht da...

Alex G. schrieb:
> Also an der Uni lernt man auch dass Cpp objektorientiert ist. C nicht...

Wenn du damit sagen möchtest, dass C die Objekt orientierte Sichtweise, 
Denkart, nicht sonderlich gut unterstützt, dann stimme ich dir zu.
Schließlich wurde, genau aus dem Grund, aus C dann "C mit Klassen", und 
später dann das C++ entwickelt.

Wenn du aber damit meinst, man sollte auf die Objekt orientierte 
Sichtweise verzichten, nur weil man gerade mit einer Sprache arbeiten 
muss, welche das nicht direkt und vollumfänglich unterstützt, dann 
liegst du (aus meiner Sicht) falsch.

------

Mal zurück zur Frage "global, oder lokal statisch?", in Bezug zum 
Eingangsposting, und als Reaktion auf Posting 
Beitrag "Re: C Anfängerfrage (static innerhalb einer Funktion)"

Unbestritten, ist, dass ein Programm irgendwo Informationen halten muss.
Steckt man diese Information, in eine Funktion, in Form einer lokalen 
Variablen, dann muss man sie, wie es der TE vor hat/hatte, u.U. an die 
Aufrufende Schicht propagieren.

Dagegen muss die globale verfügbare Information an die tieferen 
Schichten weitergegeben werden.

Das ist ein klein bisschen wie die Frage: "Was hätten sie denn gerne, 
Erschossen werden, oder aufgehangen?"

Dem Priester mapfile nach, scheint der HAL ein guter Platz für lokale 
statische Variablen zu sein...
Dem möchte ich widersprechen.

Es ist eine Angelegenheit der Anwendung/Applikation, wie welche Hardware 
genutzt wird. Dieser Wunsch, der Anwendung, muss an die tieferen 
Schichten des HAL propagiert werden. Damit ist die Hardware Abstraktion, 
selber, frei von Anwendungsdetails.

Wir haben einerseits Informationen, welche aus tieferen Schichten hoch 
proagiert werden müssen, z.B. Tastendrücke, welche aus der Hardware 
kommen, und irgendwann in der Applikation zu Entscheidungen führen.

Und andererseits Informationen, welche von dem höchsten 
Entscheidungsträger aus, bis zur konkreten LED führen, damit sie dann 
leuchten kann, oder eben auch nicht.

Den einen Weg erreichen wir über die Parameter einer Funktion, den 
anderen, über ihren Returnwert.
So soll es sein, so ist es am schönsten.

Lokale statische Variablen sind dabei eher wie ein Stock in den 
Speichen. Es muss plötzlich nicht mehr nur die Signatur einer Funktion 
betrachtet werden, sondern auch noch ihr innerer Zustand. Eine Funktion, 
welche dauernd ihr Verhalten ändert, ist deutlich schwerer zu 
dokumentieren, und zu debuggen.


Aus meiner Sicht, "gehören" statische Dinge der Applikation.
Der obersten Schicht.

In den tieferen Schichten werden meist Bibliotheksfunktionen genutzt. 
Und diese sollen möglichst universell und gut wiederverwendbar sein. 
Seiteneffekte will man da eher nicht. Zumindest keine unerwünschten.

In der obersten Schicht, sehe ich keine Probleme, wenn man auf statische 
Variablen zurückgreift, oder auch auf globale Dinge.

Denn die oberste Schicht ist eine "Weg werf Schicht".
Eine Wiederverwendung ist da erstmal nicht sinnvoll.
Die nächste Applikation wird an der Stelle ganz anders aussehen.

von Wilhelm M. (wimalopaan)


Lesenswert?

Rufus Τ. F. schrieb:

> Wird in einem C-Modul außerhalb einer Funktion eine Variable
> definiert, ist sie global, und nicht statisch.

Das Problem ist m.E., dass jeder eine andere Vorstellung davon hat, was 
"statisch" bedeuten soll. Es ist wohl von dem Schlüsselwort "static" 
hergeleitet, was aber je nach Konstrukt in C etwas anderes bedeutet. Es 
ist besser, die Begriffe des Standards zu verwenden, dann gibt es 
weniger Mißverständnisse.

Ein Variable ausserhalb jeder Blockstruktur heißt "global" bzw. genauer 
"Programm-Global". Und diese hat "static-storage duration"! Und 
"external linkage".

Schreibt man "static" davor, wir sie "Übersetzungseinheit-Global": 
translation-unit global. Und hat auch static storage duration. Aber kein 
external linkage mehr.

> Eine "extern"-Deklaration in einer Headerdatei ändert daran nichts.

Bei übersetzungseinheit-globalen Variablen ist die Kombination aus o.g. 
Grund unzulässig.

> Exakt das gleiche Verhalten gibt es mit Funktionsdefinitionen - eine als
> static definierte Funktion ist nur innerhalb des C-Modules sichtbar

Verwendet die offiziellen Begriffe, die auch klarer sind (was ist ein 
Modul?): es heißt Translation-Unit.

> Das Schlüsselwort static hat in C aber auch noch eine andere
> Bedeutung, wird es zur Definition einer Variablen innerhalb einer
> Funktion verwendet, ist diese Variable keine automatische Variable,

Hier bedeutet "static" dann "static storage duration" und keine external 
linkage.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Danke für die begriffliche Präzisierung. Inhaltlich ändert sich 
dadurch jedoch nichts.

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino F. schrieb:
> Lokale statische Variablen sind dabei eher wie ein Stock in den
> Speichen. Es muss plötzlich nicht mehr nur die Signatur einer Funktion
> betrachtet werden, sondern auch noch ihr innerer Zustand. Eine Funktion,
> welche dauernd ihr Verhalten ändert, ist deutlich schwerer zu
> dokumentieren, und zu debuggen.

Man sollte auch nur eine Funktion nennen, was eine (reine) Funktion ist. 
Eine Funktion mit Zustand ist eher ein Funktor bzw. Elementfunktion 
(eines Objektes, was per def. einen Zustand hat).

> Aus meiner Sicht, "gehören" statische Dinge der Applikation.
> Der obersten Schicht.

Na ja: die allerunterste Schicht, die HW,  sprich der µC hat auch einen 
Zustand. Deswegen sind eben die meisten "Funktionen", die auf die HW 
angewendet wird, eben keine reinen Funktionen mehr.

von Wilhelm M. (wimalopaan)


Lesenswert?

Rufus Τ. F. schrieb:
> Danke für die begriffliche Präzisierung. Inhaltlich ändert sich
> dadurch jedoch nichts.

Aber es vereinfacht die Diskussion wahnsinnig, wenn man die offiziellen, 
eingeführten Begriffe mit ihrer festgelegten Semantik verwendet. Zudem 
findet man mit dem richtigen Begriff auch schnell mal eine Antwort z.B. 
im Standard. Außerdem könnten wir die Hälfte dieses Threads streichen 
... ;-)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> Aber es vereinfacht die Diskussion wahnsinnig,

Da hast Du natürlich recht. Asche->Haupt. Ich nutze C schon so lange, 
daß ich mir nie wirklich die Mühe gemacht habe, die Terminologie für 
derartiges in einem der neueren Standarddokumente nachzulesen. Ich war 
damals froh, auf den Systemen, mit denen ich gearbeitet habe, einen 
C89-Compiler zu bekommen, denn das asthmatische K&R-C davor war ein 
Graus. Damals aber war es nicht praktikabel, den Standard selbst zu 
lesen (der wäre nur aufwendig aufzutreiben gewesen), da musste die 
(deutsche) zweite Ausgabe des K&R und die vorzügliche deutschsprachige 
Dokumentation (geschrieben von Arne Schäpers) von Turbo-C 2.0 genügen.

Tja, jeder hat so seine Defizite.

von Einer K. (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Na ja: die allerunterste Schicht, die HW,  sprich der µC hat auch einen
> Zustand. Deswegen sind eben die meisten "Funktionen", die auf die HW
> angewendet wird, eben keine reinen Funktionen mehr.

Nunja...
Dass die Hardware, selber, Zustände hat, liegt in der Natur der Dinge.
Wäre auch untragbar, wenn es das nicht geben würde.

Aber das heißt ja nicht, dass man die Zugriffsfunktionen mit lokalen 
statischen  Variablen ausstatten sollte.


Wilhelm M. schrieb:
> es vereinfacht die Diskussion wahnsinnig, wenn man die offiziellen,
> eingeführten Begriffe mit ihrer festgelegten Semantik verwendet.
Ja!

Dazu:
Mir scheint, der Begriff "Funktion" in der C Welt doch recht eindeutig 
zu sein.
"Funktor" gehört eher zur C++ Welt.

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino F. schrieb:
> Wilhelm M. schrieb:
>> Na ja: die allerunterste Schicht, die HW,  sprich der µC hat auch einen
>> Zustand. Deswegen sind eben die meisten "Funktionen", die auf die HW
>> angewendet wird, eben keine reinen Funktionen mehr.
>
> Nunja...
> Dass die Hardware, selber, Zustände hat, liegt in der Natur der Dinge.
> Wäre auch untragbar, wenn es das nicht geben würde.
>
> Aber das heißt ja nicht, dass man die Zugriffsfunktionen mit lokalen
> statischen  Variablen ausstatten sollte.

Was aber an der Qualität nichts ändert.

von Rolf M. (rmagnus)


Lesenswert?

Wilhelm M. schrieb:
> Arduino F. schrieb:
>> Lokale statische Variablen sind dabei eher wie ein Stock in den
>> Speichen. Es muss plötzlich nicht mehr nur die Signatur einer Funktion
>> betrachtet werden, sondern auch noch ihr innerer Zustand. Eine Funktion,
>> welche dauernd ihr Verhalten ändert, ist deutlich schwerer zu
>> dokumentieren, und zu debuggen.
>
> Man sollte auch nur eine Funktion nennen, was eine (reine) Funktion ist.

Nur sehr wenige C-Funktionen sind Funktionen in dem von dir gedachten 
Sinne.

Wilhelm M. schrieb:
> Schreibt man "static" davor, wir sie "Übersetzungseinheit-Global":
> translation-unit global. Und hat auch static storage duration. Aber kein
> external linkage mehr.

Genauer gesagt hat sie dann internal linkage.

Wilhelm M. schrieb:
>> Das Schlüsselwort static hat in C aber auch noch eine andere
>> Bedeutung, wird es zur Definition einer Variablen innerhalb einer
>> Funktion verwendet, ist diese Variable keine automatische Variable,
>
> Hier bedeutet "static" dann "static storage duration" und keine external
> linkage.

Sie hat dann gar keine Linkage, weder external noch internal.

von Einer K. (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Was aber an der Qualität nichts ändert.

Irgendwie scheint mir das Wort "Qualität" in diesem Zusammenhang 
deplatziert zu sein.

Aus meiner Sicht macht es schon einen "Qualitätsunterschied" (wenn ich 
das Wort, auch mal verwenden darf), ob man aus Mutwilligkeit, 
Blauäugigkeit, statische Variablen, in Funktionen, einstreut, oder ob 
die Zustände durch eine Hardware erzwungen werden, bzw. ihr aufgezwungen 
werden.

Die enthaltende Alternativlosigkeit, Unabänderbarkeit, ist schon ein 
Qualitätsmerkmal.

von Wilhelm M. (wimalopaan)


Lesenswert?

Arduino F. schrieb:
> Wilhelm M. schrieb:
>> Was aber an der Qualität nichts ändert.
>
> Irgendwie scheint mir das Wort "Qualität" in diesem Zusammenhang
> deplatziert zu sein.

In keiner Weise:

https://de.wikipedia.org/wiki/Qualit%C3%A4t

von Alex G. (dragongamer)


Lesenswert?

Arduino F. schrieb:
> Ihr seid ja schnuckelig....
> Kaum ist man ein paar Stunden nicht da...
>
> Alex G. schrieb:
>> Also an der Uni lernt man auch dass Cpp objektorientiert ist. C nicht...
>
> Wenn du damit sagen möchtest, dass C die Objekt orientierte Sichtweise,
> Denkart, nicht sonderlich gut unterstützt, dann stimme ich dir zu.
> Schließlich wurde, genau aus dem Grund, aus C dann "C mit Klassen", und
> später dann das C++ entwickelt.
>
> Wenn du aber damit meinst, man sollte auf die Objekt orientierte
> Sichtweise verzichten, nur weil man gerade mit einer Sprache arbeiten
> muss, welche das nicht direkt und vollumfänglich unterstützt, dann
> liegst du (aus meiner Sicht) falsch.
>
Also aus meiner Sicht sollte man eine Sprache nunmal nicht zu etwas 
zwingen, wofür sie nicht gemacht ist.
Das Risiko ist sehr hoch dass man dadurch eher mehr Fehler einbaut, als 
man vermeidet.
Wenn man so sattelfest in der Programmierung ist, dass dies nicht 
passiert, würde man wahrscheinlich auch ohne diese Umwege gut klar 
kommen.

: Bearbeitet durch User
von mapfile (Gast)


Lesenswert?

Wilhelm M. schrieb:
> Das Problem ist m.E., dass jeder eine andere Vorstellung davon hat, was
> "statisch" bedeuten soll. Es ist wohl von dem Schlüsselwort "static"
> hergeleitet, was aber je nach Konstrukt in C etwas anderes bedeutet. Es
> ist besser, die Begriffe des Standards zu verwenden, dann gibt es
> weniger Mißverständnisse.

Schon interessant, dass das in diesem Thread mehrfach vorkommt. ;)

Und Schade, dass in Wikipedia nicht die "Begriffe des Standards" 
verwendet werden. Vielleicht kann ja einer von euch den Artikel 
korrigieren. :)

Und ja, ich kenne die Begriffe und kann sie deuten. Aber aus Sicht eines 
Anwendungsprogrammierer sind die Wirkung - wie bei Wikipedia beschrieben 
- einleuchtender und ausreichend. Ihn interessiert die Sichbarkeit und 
die Haltbarkeit, egal wie das im Hintergrund gemacht wird.

Arduino F. schrieb:
> Dem Priester mapfile nach, scheint der HAL ein guter Platz für lokale
> statische Variablen zu sein..
Da du ja auch die Inhalte deiner eigenen Posts vergisst, will ich dir 
auch hier unter die Arme greifen:
Arduino F. schrieb:
> Ansonsten gilt der Leitsatz:
> Nur statische Variablen, auf welche man verzichtet, sind gute statische
> Variablen.

Dieser pauschalen Aussage habe ich widersprochen! Und ich schließe die 
Verwendung statischer Variablen in einem HAL, einem BS, einer LIB nicht 
aus, fordere sie aber nicht.

von avr (Gast)


Lesenswert?

Alex G. schrieb:
> Also aus meiner Sicht sollte man eine Sprache nunmal nicht zu etwas
> zwingen, wofür sie nicht gemacht ist.
> Das Risiko ist sehr hoch dass man dadurch eher mehr Fehler einbaut, als
> man vermeidet.

Wenn du damit sagen willst, dass fehlerfreies Programmieren in C++ 
leichter sein soll, als die in C mit OOP-Nachbildung, dann stimmte ich 
dir definitiv nicht zu. C++ ist alles andere als C mit Klassen und vom 
Schwierigkeitsgrad auf einem anderen Level. Und so lange es bei 
einfachen Klassen bleibt, mit vielleicht ein wenig Vererbung, dann ist 
OOP in C kein Stück aufwändig. Hast du denn überhaupt schon in C OO 
programmiert?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Dr. Sommer schrieb:
> mapfile schrieb:
>> Nochmal als Tipp für dich: statische Variablen müssen nicht zwingend mit
>> 'static' eingeleitet werden. ;)
>> Es gibt nicht nur local statics. ;)
> Jetzt klär uns mal auf, was das sein soll...
> So etwas:
> int foo;
> int main () { }
> ist ja keine statische, sondern nur eine globale Variable.

Du wirfst hier 2 Dinge durcheinander:

1) C-Schlüsselwort "static".

2) Daten im "static storage", einer Speicherklasse.

1) ==> 2) aber nicht umgekehrt. Insbesondere ist foo von oben im static 
storage.

Je nachdem, was ihr oben mit "statics" meint, führt das dann zu beliebig 
viel Verwirrung.

Neben der Speicherklasse hat "static" auch Einfluß auf die Linkage. Da 
in C kein Identifier eine Sichtbarkeit größer als eine Compilation Unit 
hat, braucht es ein Feature, um Identifier in verschieden Units zu 
verbinden, welche das gleiche Objekt referenzieren sollen: External 
Linkage.

Zur weiteren Verwirrung bedeutet "extern" nicht notwendig external 
Linkage wie in
1
static int var; // ok, tentative decl
2
extern int var; // ok, refers to var from above
und für external Linkage ist nicht unbedingt "extern" erforderlich :-)

: Bearbeitet durch User
von Tina (Gast)


Lesenswert?

schon toll, dieses C...zu jeder noch so einfachen frage..meint man..gibt 
es eine riesige Diskussion...
Ich sag ja..Pascal/Lazarus...für 99% der Urer völlig ausreichend

von DanVet (Gast)


Lesenswert?

Der Thread ist ja schon etwas fortgeschritten und ich habe nicht alles 
gelesen, dennoch möchte ich noch auf eine *C++-Tücke* hinweisen:

Eine funktionslokale static variable wird nur EINMAL angelegt, egal 
wieviele Instanzen man von einer Klasse bildet.
D.h. jede Klasse verwendet mit der entsprechenden Funktion ein und 
dieselbe Variable! Das kann mächtig Ärger verusachen, wenn man das nicht 
so beabsichtigt hat (in der Regel hat man es nicht beabsichtigt).
Deswegen: Bei C++ möglichst keine funktionslokale static Variablen 
verwenden. ;-)

von Wilhelm M. (wimalopaan)


Lesenswert?

DanVet schrieb:
> Der Thread ist ja schon etwas fortgeschritten und ich habe nicht alles
> gelesen, dennoch möchte ich noch auf eine *C++-Tücke* hinweisen:
>
> Eine funktionslokale static variable wird nur EINMAL angelegt, egal
> wieviele Instanzen man von einer Klasse bildet.
> D.h. jede Klasse verwendet mit der entsprechenden Funktion ein und
> dieselbe Variable! Das kann mächtig Ärger verusachen, wenn man das nicht
> so beabsichtigt hat (in der Regel hat man es nicht beabsichtigt).
> Deswegen: Bei C++ möglichst keine funktionslokale static Variablen
> verwenden. ;-)

Das ist ein guter Hinweis! Sollte allerdings bei genauerer Betrachtung 
auch klar sein, denn eine Klasse ist (auch) ein (spezieller) Namensraum: 
Eine Klasse -> Eine Funktion -> ein static Objekt.

Bei Template: unterschiedliche Parametrierung(!) -> unterschiedliche 
Templateklassen -> unterschiedliche Funktionen -> mehrere static 
Objekte.

von W.S. (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Wird die Variable aber als static deklariert, ist sie statisch, und
> nur innerhalb des entsprechenden C-Moduls sichtbar. Ihr Name wird
> nicht als Symbol exportiert und es ist nicht möglich, mit externen
> Referenzen* aus anderen Objektdateien auf diese Variable zuzugreifen,
> weil der Linker diese Referenzen nicht auflösen kann.

Du schreibst Unsinn - jedenfalls sofern du dich auf die 
Mikrocontroller-Programmierung beziehst.

Also:
Richtig ist, daß JEDE Variable, die nicht auf dem Stack angeordnet ist 
und auch nicht zu den Hardware-Registern gehört, auch im Objektcode 
auftaucht.

Egal ob sie nun als "static" ausgewiesen ist oder nicht.

Das ist so und es ist der Linker, der all diesen Variablen ihren finalen 
Speicherplatz zuweist.

Und damit er das auch bei "static" Variablen tun kann, hat eben jede 
Toolchain ihre Mechanismen bei der Flag- oder Namensgebung im 
Objektcode, um Kollisionen (sprich Fremdzugriff) zu vermeiden. Aber 
auftauchen im Objektcode müssen sie, sonst gibt's keinen Speicherplatz 
dafür. Mag ja sein, daß eine "MySecretVariable" dann umbenannt als 
"$$mymodule$$$0004711" erscheint.

W.S.

von W.S. (Gast)


Lesenswert?

Tina schrieb:
> Ich sag ja..Pascal/Lazarus...für 99% der Urer völlig ausreichend

Wenn es dazu einen guten Compiler für bare-metal gäbe, wäre das für 100% 
aller Leute völlig ausreichend. Aber Pascal kann man ja relativ 
problemlos lesen - und genau DAS ist so vielen Programmierern ein Dorn 
im Auge...

W.S.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

W.S. schrieb:
> Aber auftauchen im Objektcode müssen sie, sonst gibt's keinen
> Speicherplatz dafür. Mag ja sein, daß eine "MySecretVariable" dann
> umbenannt als "$$mymodule$$$0004711" erscheint.

Tu Dir einfach den Gefallen, mal mit dem zu Deiner Toolchain passenden 
Objektdump-Werkzeug eine Objektdatei anzusehen.

Wobei: Selbst wenn Deine suggerierte Umbenennung stattfände - worin 
unterscheidet sich die von der von Dir unterstellt nicht vorhandenen 
Kapselungsmöglichkeit?

Und welchen magischen Mechanismus soll Pascal hier verwenden, der 
effektiv anders aussieht?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

W.S. schrieb:
> Rufus Τ. F. schrieb:
>> Wird die Variable aber als static deklariert, ist sie statisch, und
>> nur innerhalb des entsprechenden C-Moduls sichtbar. Ihr Name wird
>> nicht als Symbol exportiert und es ist nicht möglich, mit externen
>> Referenzen* aus anderen Objektdateien auf diese Variable zuzugreifen,
>> weil der Linker diese Referenzen nicht auflösen kann.
>
> Du schreibst Unsinn - jedenfalls sofern du dich auf die
> Mikrocontroller-Programmierung beziehst.
>
> Also:
> Richtig ist, daß JEDE Variable, die nicht auf dem Stack angeordnet ist
> und auch nicht zu den Hardware-Registern gehört, auch im Objektcode
> auftaucht.

Dass sie im Object-Code auftaucht bedeutet aber nicht, dass sie die 
nötige Linkage hat um von anderen Compilation units aus zugreifbar zu 
sein.  Auf Object-Ebene zeigt sich das darin, dass entsprechende Objekte 
nicht global sind.  Beispiel:
a.c
1
int aaa;
2
__attribute((used)) static int bbb;
3
4
int main(){}

b.c
1
__attribute((used)) static int bbb;
1
$gcc a.c b.c && nm a.out | sort
2
3
000000000060103c B aaa
4
0000000000601034 b bbb
5
0000000000601038 b bbb
6
...

> Egal ob sie nun als "static" ausgewiesen ist oder nicht.

Nein, eben nicht.

> Das ist so und es ist der Linker, der all diesen Variablen ihren finalen
> Speicherplatz zuweist.

Ja, der weist den Speicherplatz zu. Dennoch kann man b.c::bbb nicht von 
a.c aus zugreifen, und man kann a.c::bbb nicht von b.c aus zugreifen.

> Mag ja sein, daß eine "MySecretVariable" dann umbenannt als
> "$$mymodule$$$0004711" erscheint.

Die kann aber immer nocht nicht von C aus zugegriffen werden, es sein 
denn man ist in der gleichen Compilation Unit.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Und welchen magischen Mechanismus soll Pascal hier verwenden, der
> effektiv anders aussieht?

Ich entsinne mich nicht, in diesem Thread das Wort "Pascal" zuvor je 
hingeschrieben zu haben.


Aber zur Erklärung deiner Frage:
Pascal verwendet ein tatsächlich funktionierendes Unit system, das so 
aussieht, daß es in jeder Unit-Quelle eine Sektion "interface" gibt, 
welche all die Deklarationen, Variablen, Funktionen und sonstiges Zeugs, 
was man anderen Programmteilen zur Kenntnis geben will, enthalten. 
Danach kommt die Sektion "implementation", wo man deklarien und 
definieren kann was man will - es bleibt strikt innerhalb des Units und 
ist von außen unzugänglich.

Wie das in der konkreten Toolchain gemacht wird, müßte man nachlesen.

Ebenso, wie es gemacht wird, daß Funktionen und Prozeduren lokale 
Funktionen und Prozeduren haben können.
So.
Bei einem funktionablen Unit-System gibt man lediglich an, welche Units 
man zu benutzen gedenkt - und deshalb ist so ein albernes Herumfuchteln 
mit #include und "extern" gar nicht erforderlich. Jaja, man kann in 
Pascal auch sowas wie #include benutzen - aber es wird noch viel weniger 
benötigt als goto.

Wobei der #include-Workaround um das fehlend Unitsystem in C wieder mal 
herzlich unkonsistent gemacht wurde: externe Daten brauchen ein 
"extern", sonst sind sie doppelt da und bei externen Funktionen galt das 
bis vor einiger Zeit nicht - woran sich manche Leute partout noch immer 
nicht gewöhnen können. Gottseidank ist das vorbei und man komplett alle 
externen Daten und Funktionen mit "extern" kennzeichnen, ist ja auch das 
einzig logisch Richtige.

Nebenbei hat man eine Entsprechung dieses Systems aus Interface und 
Implementation auch bei VHDL, nur Verilog gibt sich vergleichsweise so 
schlampig wie C.

W.S.

von W.S. (Gast)


Lesenswert?

Johann L. schrieb:
>> Egal ob sie nun als "static" ausgewiesen ist oder nicht.
>
> Nein, eben nicht.

Ja, eben DOCH!


>> Das ist so und es ist der Linker, der all diesen Variablen ihren finalen
>> Speicherplatz zuweist.
>
> Ja, der weist den Speicherplatz zu. Dennoch kann man b.c::bbb nicht von
> a.c aus zugreifen, und man kann a.c::bbb nicht von b.c aus zugreifen.

Hast du es noch immer nicht begriffen?
Variablen auf dem Stack sind kein Thema für den Linker, aber alles 
Andere IST en Thema für den Linker. Egal ob static oder nicht. 
Lediglich durch Maßnahmen, die in der jeweiligen Toolchain vorgesehen 
sind, werden Variablen, die als static deklariert sind, nur mit den 
Zugriffen aus ihrem eigenen Objektcode verlinkt. Normalerweise erfolgt 
dies durch eine relativ radikale Umbenennung, die man im Quellcode 
nicht machen kann, um zufällige Namensgleichheiten auszuschließen.

Noch Fragen, Kienzle?

W.S.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

W.S. schrieb:
> Hast du es noch immer nicht begriffen?

Doch.  Du kannst davon ausgehen, dass ich ein Minimum an Vertändnis 
dafür habe, welche Aufgaben Tools wie Compiler oder Linker erledigen.

Dass man hier prinzipiell via Hardware-Adresse auf ein Objekt zugreifen 
kann, falls man Kenntnis über diese erlangt, sollte klar sein.

Aber auch, dass das mit der aktuellen Verwirrung, was mit "statics" 
überhaupt gemneint ist, hat das ziemlich wenig bis garnix zu tun:  Die 
Implementation folgt dem Standard, und dieser legt Konzepte wie Static 
Storage, Linkage und Semantik und Syntax von "static" fest.  Was im 
Gedärm der Tools geschieht — und dazu gehören hier Linker und 
Binär-Format — ist für die Frage und das Verständnis des TO irrelevant, 
denn sie spielen im Standard schlichweg keine Rolle.

von Markus F. (mfro)


Lesenswert?

W.S. schrieb:
> Bei einem funktionablen Unit-System gibt man lediglich an, welche Units
> man zu benutzen gedenkt - und deshalb ist so ein albernes Herumfuchteln
> mit #include und "extern" gar nicht erforderlich. Jaja, man kann in
> Pascal auch sowas wie #include benutzen - aber es wird noch viel weniger
> benötigt als goto.

1.) Eine FreePascal-Unit definiert im Interface-Teil der Unit, welche 
Typen, Funktionen/Prozeduren und Variablen sie anderen Units zur 
Verfügung stellt.
2.) Ein(e) FreePascal Unit/Programm definiert im Uses-Teil, welche Units 
sie/es benutzen will

Wo ist der funktionale Unterschied zwischen 1.) und einem C 
include-File?
Wo ist der funktionale Unterschied zwischen 2.) und einem C 
#include-Statement?

Ich mag Pascal auch, aber bahnbrechende Unterschiede kann ich nicht 
erkennen. Wenn ich in C etwas "geheimhalten" will, muss ich halt 
"static" dazuschreiben, wenn ich in Pascal etwas "veröffentlichen" will, 
muss es eben ins Unit-Interface. Letztendlich ist die Funktionalität 
dieselbe, der Rest ist eine Frage der persönlichen Vorlieben.

Auch ein Pascal-Binary muss irgendwann mal gebunden werden. FreePascal 
beispielsweise nutzt dafür den GNU ld. Also haben wir auch beim Linken 
exakt dieselbe Funktionalität bzw. Pascal kann gar nicht so viel 
toller Linken als die C-Toolchain.

von Kastanie (Gast)


Lesenswert?

W.S. schrieb:
> Nebenbei bemerkt, finde ich diese Namensgebung miserabel, man hätte das
> Ganze besser "private" nennen sollen. Ist was Ähnliches wie "typedef",
> was man besser "rename" hätte nennen sollen.

Full ACK!

von Tina (Gast)


Lesenswert?

es ging mir auch weniger um den grundsätzlichen Unterschied..eher um die 
Fallstricke..
Bei C geht es irgendwie ständig um Fallstricke :-(

von Alex G. (dragongamer)


Lesenswert?

Das haben maschinen-nahe Sprachen leider so an sich...

von Tina (Gast)


Lesenswert?

im vergleich zwischen Pascal zu C ??! Ist das so schwer zu verstehen?!

von W.S. (Gast)


Lesenswert?

Markus F. schrieb:
> Wo ist der funktionale Unterschied zwischen 1.) und einem C
> include-File?
> Wo ist der funktionale Unterschied zwischen 2.) und einem C
> #include-Statement?

Es ist eben die Funktionalität, die du offensichtlich nicht zu 
erkennen vermagst.

Bei Pascal hat es eine klare Ansage innerhalb eines Units, was man zu 
exportieren gedenkt und was nicht. Bei C gibt es so etwas nicht.

Ich breche das hier mal ab, schließlich geht es in diesem Thread ja um 
C.

Ansonsten frag ich mal provokativ, wo der Unterschied zwischen C und 
Assembler ist.

W.S.

von Einer K. (Gast)


Lesenswert?

W.S. schrieb:
> Ansonsten frag ich mal provokativ, wo der Unterschied zwischen C und
> Assembler ist.

Ist der C Kompiler nicht einfach nur ein aufgebohrter Macro Assembler?

Hihihi...

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

W.S. schrieb:
> Bei Pascal hat es eine klare Ansage innerhalb eines Units, was man zu
> exportieren gedenkt und was nicht. Bei C gibt es so etwas nicht.

Du weigerst Dich mit beeindruckender Hartnäckigkeit, zu akzeptieren, daß 
diese "klare Ansage" genauso und mit genau der gleichen Funktionalität 
in C existiert.

Aber es ist vermutlich müßig, Dich darauf hinzuweisen, haben ja schon 
mehrere hier vergebens versucht.

von Jobst Q. (joquis)


Lesenswert?

W.S. schrieb:
> Aber Pascal kann man ja relativ
> problemlos lesen - und genau DAS ist so vielen Programmierern ein Dorn
> im Auge...

Ein Dorn nicht gerade, aber zuviele Ballaststoffe. Wenn ein Quelltext 
fast zur Hälfte aus BEGIN und END besteht, ist das einfach nur lästig 
und damit nicht mehr problemlos.

In C ist die Struktur bis auf wenige Schlüsselworte in einfachen Zeichen 
und der Text bleibt für die Namen. Wenn man nicht gerade absoluter 
Anfänger ist, ist ein Quelltext in C viel schneller überschaubar als das 
schwätzerische Pascal.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Ich glaube nicht, daß ein Programmiersprachenlesbarkeitsflamewar diesen 
Thread voranbringen würde.

von Einer K. (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Ich glaube nicht, daß ein Programmiersprachenlesbarkeitsflamewar
> diesen
> Thread voranbringen würde.

Glaube ich ich auch nicht!

Wobei ich schon sagen muss, dass Pascal oft besser zu lesen ist, als 
C/C++
Ich mag es. Aber nutze es kaum noch.
1
Program Visual;
2
3
Uses 
4
   Protokoll,Sheduler,Visualisierung ; // und so weiter
5
6
Const 
7
   StromAusfall = FALSE;
8
9
Begin
10
   while(not StromAusfall) do  Shedule();
11
End;

von Tina (Gast)


Lesenswert?

Ich wollte auch gar nicht auf Begin und end oder sowas hinaus.
Schaut doch einfach mal in einem Pascal Forum
Stellt da einer eine Frage, gibt es eine klare Antwort.
In C bzw C++ kommt eine Antwort und dann kommen ganz viel weitere die 
sagen es wäre falsch, oder das stimmt nur wenn xy oder in anderen fällen 
passiert aber dieses oder jenes...
NUR darauf wollte ich hinaus.
In C gibt es zu jedem Mückenschiss 1000 Sonderfälle...
Wobei für 98% aller Fälle Lazarus Pascal oder Delphi  völlig ausreichen 
würde, auch für welche die das gewerblich nutzen, quälen sich doch immer 
wieder welche mit C bzw C++ rum.
Derzeit etwas entschärft durch viele Neueinsteiger die die mit Python 
beschäftigen, dem ich etwas skeptisch gegenüber stehe, aber zu wenig 
darüber weiß als das ich dagegen ´reden könnte

Beitrag #5272920 wurde von einem Moderator gelöscht.
von W.S. (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Du weigerst Dich mit beeindruckender Hartnäckigkeit, zu akzeptieren, daß
> diese "klare Ansage" genauso und mit genau der gleichen Funktionalität
> in C existiert.

Du redest noch immer Unsinn. Was du sagst, ist schlichtweg FALSCH. Ich 
geb dir mal ein Beispiel:

Quelle "eins.c":
hier deklarieren wir ne Variable und ne Funktion
aber wir schreiben davon NICHTS in eine .h hinein,
weil wir weder A noch Blabla exportieren wollen.
1
int A;
2
int Blabla (void)
3
{....
4
}


Quelle "zwei.c": hier verschaffen wir uns Zugang zu Zeugs in "eins.c" 
durch Verwenden von "extern"
1
extern int A;
2
extern int Blabla (void);
3
4
int Naguckmal (void)
5
{ int Y;
6
  Y = A * Blabla();
7
  return Y;
8
}

Hier erzeugen wir einen Linkfehler:
1
int A;
2
3
int Naguckmal (int B)
4
{ int Y;
5
  Y = A * B;
6
  return Y;
7
}


So. In "zwei.c" greifen wir einfach auf Internes von "eins.c" zu, ohne 
daß dieses in "eins.h" jemals erwähnt wurde. Das bedeutet, daß es eben 
keine funktionierende Kapselung in C gibt - und meines Wissens kann man 
auch nicht die Funktion Blabla als "static" deklarieren.

In Pascal hingegen sind solche Dinge einfach nicht möglich - eben wegen 
des Konzeptes von Interface und Implementation. Das ist ein ziemlich 
heftiger Unterschied zu C.

Es sind eben doch Welten zwischen C und Pascal - und es ist eben NICHT 
die "genau .. gleiche Funktionalität".
Man könnte als anderes Beispiel heranziehen, daß es in Pascal 
Parameterübergabe als Wert oder Referenz gibt, seit einiger Zeit auch 
als dedizierten Input oder Output und daß es so etwas bei C eben 
überhaupt nicht gibt und man sich deshalb mit Zeiger-Übergaben behelfen 
muß. Es wäre auch da schlichtweg grundfalsch, von "genau gleicher 
Funktionalität" reden zu wollen.

Kapierst du nun das Ganze?
Ich nehme mal an, daß deine Pascal-Kenntnisse ziemlich eingerostet sind, 
ist ja auch kein Wunder, wenn man Dinge vergißt, die man zu lange nicht 
ausgeübt hat. Aber sei nicht so störrisch und versuche nicht, zu 
rechthabern. Ich weiß das nämlich wirklich besser als du.

W.S.

von Oliver S. (oliverso)


Lesenswert?

W.S. schrieb:
> und meines Wissens kann man
> auch nicht die Funktion Blabla als "static" deklarieren.

Das zeigt nur den wahren Unterschied zwischen C und Pascal. C lässt mehr 
zu, ist dafür aber nicht idiotensicher. Gemeinsam haben beide, daß, wenn 
man die Sprache nicht kennt, und nicht weiß, was man tut, es 
fürchterlich schief gehen kann.

Oliver
P.S Selbstvertändlich kann man Funktionen in C als static deklarieren.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

W.S. schrieb:
> Du redest noch immer Unsinn. Was du sagst, ist schlichtweg FALSCH.

W.S. schrieb:
> meines Wissens kann man
> auch nicht die Funktion Blabla als "static" deklarieren.

Du lehnst dich aber schon etwas weit aus dem Fenster, oder?

von Wilhelm M. (wimalopaan)


Lesenswert?

Michael R. schrieb:
> W.S. schrieb:
>> Du redest noch immer Unsinn. Was du sagst, ist schlichtweg FALSCH.
>
> W.S. schrieb:
>> meines Wissens kann man
>> auch nicht die Funktion Blabla als "static" deklarieren.
>
> Du lehnst dich aber schon etwas weit aus dem Fenster, oder?

Leider gibt es Leute, die sich nicht die Mühe machen, die Beiträge 
anderer (etwa Johanns, Rufus' oder auch meinen) zu lesen und auch mal 
darüber nach zu denken. Stattdessen wird immer dasselbe in immer neuen 
Worthülsen wiederholt ... Schade, aber wohl nicht zu ändern.

von Yalu X. (yalu) (Moderator)


Lesenswert?

W.S. schrieb:
> So. In "zwei.c" greifen wir einfach auf Internes von "eins.c" zu, ohne
> daß dieses in "eins.h" jemals erwähnt wurde. Das bedeutet, daß es eben
> keine funktionierende Kapselung in C gibt - und meines Wissens kann man
> auch nicht die Funktion Blabla als "static" deklarieren.

Natürlich gibt es die, nämlich mittels des Schlüsselworts static.
Damit sind wir sogar fast wieder zum Thread-Thema zurückgekehrt.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

W.S. schrieb:
> Du redest noch immer Unsinn. Was du sagst, ist schlichtweg FALSCH. Ich
> geb dir mal ein Beispiel:
>
> Quelle "eins.c":
> hier deklarieren wir ne Variable und ne Funktion
> aber wir schreiben davon NICHTS in eine .h hinein, weil wir weder A noch
> Blabla exportieren wollen.
1
int A;
2
int Blabla (void)
3
{....
4
}

Der Fehler liegt hier bei Dir und Deiner konsequenten Weigerung, C 
lernen zu wollen.

Würdest Du weder A noch Blabla exportieren wollen, müsstest Du das hier 
schreiben:
1
static int A;
2
static int Blabla (void)
3
{....
4
}

Wie wäre es, wenn Du einfach mal ein Buch über C lesen würdest?

von Rolf M. (rmagnus)


Lesenswert?

W.S. schrieb:
> Du redest noch immer Unsinn. Was du sagst, ist schlichtweg FALSCH.

Nein, genau das trifft auf dich zu!

> und meines Wissens kann man auch nicht die Funktion Blabla als "static"
> deklarieren.

Dann ist dein Wissen falsch, um nicht zu sagen: kompletter Blödsinn! 
Natürlich kann man Funktionen als static deklarieren, und dann ist sie 
auch über eine extern-Deklaration in einem anderen C-File nicht 
erreichbar. Gleiches gilt im übrigen für die Variable. Also exakt das, 
von dem du felsenfest behauptest, es sei in C nicht möglich.
Wenn du schon so laut tönst, solltest du wenigstens ein bisschen Ahnung 
von dem haben, wovon du sprichst, sonst machst du dich ziemlich 
lächerlich.

> Ich nehme mal an, daß deine Pascal-Kenntnisse ziemlich eingerostet sind,
> ist ja auch kein Wunder, wenn man Dinge vergißt, die man zu lange nicht
> ausgeübt hat. Aber sei nicht so störrisch und versuche nicht, zu
> rechthabern. Ich weiß das nämlich wirklich besser als du.

Die drei Sätze sind in dem Kontext nun echt der Abschuss. Ersetze 
"Pascal" durch "C", und es trifft perfekt auf dich zu.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.