global oder nicht global

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Sonntag 1. Juni 2014, 18:16

snafu hat geschrieben:
Darii hat geschrieben:global ist der "last resort". Genau wie goto in C.
Dafür, dass ``goto`` ein "last resort" sein soll, wird es in echten Programmen - u.a. im C-Quelltext von Python und im Linux-Kernel - aber ganz schön oft verwendet. Wie passt das mit deiner Aussage zusammen? Sind das für dich allesamt schlechte Programmierer oder setzt du eine sehr spezielle Definition von "last resort" voraus?
Meine Definition "last resort = letzter Ausweg" (laut Wörterbuch). Dass dieser letzte Ausweg trotzdem oft genommen wird liegt einfach daran, dass C keine äquivalenten besseren Sprachmittel z.B. zur Fehlerbehandlung anbietet.

Sprich goto sollte man in C genau wie global in Python nur verwenden, wenn es gar nicht anders (oder nicht besser) geht. Kommt in C leider nunmal recht häufig vor…
BlackJack

Sonntag 1. Juni 2014, 18:44

@Darii: ``goto`` ist nicht letzter Ausweg, sondern das Mittel der Wahl um die Sprünge, die in anderen Sprachen per Ausnahmebehandlung geregelt werden, in C zumindest ansatzweise umzusetzen. Letzter Ausweg ist etwas was man nimmt wenn man verzweifelt ist. Es mag sicher Leute geben die beim C-Programmierung ständig am verzweifeln sind, aber das ist nicht der Masstab an dem man das festmachen sollte. ;-)
jerch
User
Beiträge: 1633
Registriert: Mittwoch 4. März 2009, 14:19

Sonntag 1. Juni 2014, 19:02

@gNeandr: Hier mal ein simples Beispiel, einmal mit globaler Variable und einmal mit Parameter. Wenn Du mir die -1 für a global erklären kannst, hast Du gut aufgepasst - dann ist aber interessant, was nötig war, um das nachzuvollziehen. In real world code würde ich sowas immer als Programmierfehler ansehen. Beachte bitte auch, wie sich der Generator für a als Parameter immer gleich verhält.

Code: Alles auswählen

def gen():
    global a
    while a > 0:
        yield a
        a -= 1

print 'a as global'
a = 10
for i in gen():
    print i, a, list(gen())
print a, list(gen())

#################################

def reentrant_gen(a):
    while a > 0:
        yield a
        a -= 1

print 'a as parameter'
a = 10
for i in reentrant_gen(a):
    print i, a, list(reentrant_gen(a))
print a, list(reentrant_gen(a))
gNeandr
User
Beiträge: 68
Registriert: Sonntag 11. Mai 2014, 16:48

Montag 2. Juni 2014, 00:02

@jerch ... besonders spannend finde ich das jetzt nicht, sorry.
Vielleicht liegt es daran, dass ich bestimmte "Werte" sehe, die ich an verschiedenen Stellen im Programm benutzen muss,
a) feste "Werte" -- zB 'server', die IP die ich praktischerweise beim Start einlese und in mehreren Funktionen / Threads verwenden muss,
oder
b) "Werte" die ich nach Berechnung (von importierten Ausgangswerten) weiter 'global' verfügbar halte (zB. Geo-Koordinaten zur Berechnung von 'sunrise' und 'sunset')

In beiden Fällen werden die einmal "ermittelt" und warten dann nur noch verwendet zu werden. Also recht einfach ..'global'.

Sicher gibt's Fälle in denen das "rumreichen" von Zuständen Sinn macht. BlackJack hat ja dankenswerterweise meinen ersten Entwurf entsprechend verbessert. Und Jerchs Beispiel zeigt das ja auch.

Nix für Ungut, eure Hinweise helfen und eines Tages werde ich wohl pythonischer denken ... :wink:
jerch
User
Beiträge: 1633
Registriert: Mittwoch 4. März 2009, 14:19

Montag 2. Juni 2014, 07:46

@gNeandr: Das hat doch nichts mit pythonisch/unpythonisch zu tun, in C, C++ oder Java würde man das auch so machen. Und spätenstens bei Threads handelst Du Dir mit globalen Variablen entweder sowas wie Schrödingers Katze oder ein segfault ein, wenn da zeitgleich dranrum manipuliert wird. :roll:
BlackJack

Montag 2. Juni 2014, 07:47

@gNeandr: Das hat nichts mit „pythonisch” zu tun, das ist allgemein gültig. Es gibt nicht bestimmte Fälle in denen das vermeiden von globalen Variablen Sinn macht, sondern das macht generell Sinn. Das was Du da jetzt beschrieben hast (Server, feste Koordinaten) sind ja auch keine Variablen sondern Konstanten, also braucht man da auch keine ``global``-Anweisung. Wenn man die ”braucht” ist das ein „code smell”, und IMHO in 99,9% der Fälle ein Entwurfsfehler.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Montag 2. Juni 2014, 08:49

BlackJack hat geschrieben:@Darii: ``goto`` ist nicht letzter Ausweg, sondern das Mittel der Wahl um die Sprünge, die in anderen Sprachen per Ausnahmebehandlung geregelt werden, in C zumindest ansatzweise umzusetzen.
Der einzige Ausweg ist zwangsläufig auch der letzte. ;) Fakt ist, dass man bei goto sehr leicht übersehen kann, irgendwelche Ressourcen freizugeben, was für mich eigentlich ein Grund ist, es nicht benutzen zu wollen…
Es mag sicher Leute geben die beim C-Programmierung ständig am verzweifeln sind, aber das ist nicht der Masstab an dem man das festmachen sollte. ;-)
Ich wage einfach mal die Behauptung, dass jeder, der bei C nicht verzweifelt, C nicht benutzen sollte. Ich hoffe ja, dass nach heartbeat & co endlich mal ein paar Leute aufgewacht sind…
BlackJack

Montag 2. Juni 2014, 09:10

@Darii: Das ist eine unsinnige Argumentation weil dann *alles* ein letzter Ausweg ist. Man kann auch ohne ``goto`` leicht übersehen Ressourcen freizugeben, das ist eben so wenn man sich selbst um die Verwaltung kümmern muss. Es macht, richtig eingesetzt, den Quelltext übersichtlicher, was wiederum dazu führt, das eben nicht so schnell etwas übersehen wird als bei unübersichtlichem Quelltext ohne das ``goto``.

Wenn dann effektiv niemand C benutzen sollte, fehlt irgendwie eine Alternative. Ich will ja nicht behaupten das C der Weisheit letzter Schluss ist, sehe aber nicht wodurch man es ersetzen sollte. Also ganz praktisch gesehen, nicht was theoretisch besser wäre.
jerch
User
Beiträge: 1633
Registriert: Mittwoch 4. März 2009, 14:19

Montag 2. Juni 2014, 09:28

Darii hat geschrieben:Ich wage einfach mal die Behauptung, dass jeder, der bei C nicht verzweifelt, C nicht benutzen sollte.
Haha, in der Tat kenne ich den Frust mit C - allerdings eher daher, dass mir Sprachmittel fehlen und man soviel "zu Fuss" erledigen muss. Aber Verzweiflung ist so ein starkes Wort :wink:

Und wenn man sich heartbleed anschaut - nunja, da sind schon grobe Schnitzer drin gewesen. Das man in C IMMER die Größe von Pointern auf Arrays/Strings (oder allgemeiner Speicherbereiche) checken muss, ist hinlänglich bekannt. Traurig daran ist, dass das durch die angeblich zweistufige QA gekommen ist.

Die richtige Benutzung von GOTO steht und fällt mit der eigenen Codedisziplin und da es "nur" innerhalb eines Funktionsblockes erlaubt ist, ist die Tragweite durchaus überschaubar (im Sinne von Codezeilen). Aber auch ich bin kein Fan von GOTO.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Montag 2. Juni 2014, 21:17

Wenn dann effektiv niemand C benutzen sollte, fehlt irgendwie eine Alternative. Ich will ja nicht behaupten das C der Weisheit letzter Schluss ist, sehe aber nicht wodurch man es ersetzen sollte. Also ganz praktisch gesehen, nicht was theoretisch besser wäre.
Zugegeben fertige Alternativen gibt es noch keine, aber ich setze große Hoffnungen in Rust. Die Sprache ist zwar noch nicht fertig, aber die freuen sich über jeden Bugreport und das ist besser als den Kopf in den Sand zu stecken. Ich habe hoffentlich bald mal Zeit Rust bare metal auf einem Microcontroller auszuprobieren…
jerch hat geschrieben:Und wenn man sich heartbleed anschaut - nunja, da sind schon grobe Schnitzer drin gewesen. Das man in C IMMER die Größe von Pointern auf Arrays/Strings (oder allgemeiner Speicherbereiche) checken muss, ist hinlänglich bekannt. Traurig daran ist, dass das durch die angeblich zweistufige QA gekommen ist.
Wenn man in C *IMMER* die Größe von Speichersegmenten checken muss warum macht die Sprache das nicht für mich? Das würde eine komplette Klasse von Fehlern ausschließen. Die Lehre aus Heartbleed sollte eben sein, dass man solch gravierende Sprachdefizite nicht durch QA oder (reklamierte) Fertigkeiten des Programmierers kompensieren kann.
BlackJack

Montag 2. Juni 2014, 21:55

@Darii: Rust ist interessant, könnte aber zu kompliziert und zu ”exotisch” sein, zumindest um ”alte” Programmierer zu gewinnen.

C macht das überprüfen nicht für Dich weil die Sprache nichts von den Grössen weiss. Und Sprachen wie Pascal, die wissen wie gross Arrays sind, haben sich nicht durchgesetzt, unter anderem wegen dieser ”Einschränkung”.
EyDu
User
Beiträge: 4874
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Dienstag 3. Juni 2014, 00:01

Darii hat geschrieben:Wenn man in C *IMMER* die Größe von Speichersegmenten checken muss warum macht die Sprache das nicht für mich? Das würde eine komplette Klasse von Fehlern ausschließen. Die Lehre aus Heartbleed sollte eben sein, dass man solch gravierende Sprachdefizite nicht durch QA oder (reklamierte) Fertigkeiten des Programmierers kompensieren kann.
Irgendwo muss man beim Entwickeln der Sprache immer einen Schnitt machen. Der nächste wäre dann: Wenn C die Größe von Arrays kennt, warum wird der Speicher nicht automatisch mittels Reference-Counting verwaltet? Dann kommen die nächsten und fragen: Wenn man schon Reference-Counting hat, warum dann nicht gleich einen Garbage-Collector? Das kann beliebig weitergesponnen werden.

Jede Sprache hat ihren Einsatzzweck und wurde dafür entworfen. Bei C wurde eben genau hier ein Schnitt gemacht. Welcher, mit Bezug auf die Sprache, auch sinnvoll ist. C ist so nah an der Maschine, dass eine Prüfung keinen Sinn macht. Zum einen möchte man häufig nicht, dass der Compiler einfach (häufig unnötige) Checks einbaut, zum anderen sind Prüfungen, wie BlackJack schon geschrieben hat, teilweise gar nicht möglich. Arrays sind in C einfache Speicherblöcke, bzw. einfach nur Pointer auf eine Adresse. Was dahinter steht ist vollkommen unbestimmt.

Daraus ergeben sich natürlich viele Vorteile, besonders in der Echzeitfähigkeit und ich der Performance und mit irgendwie muss man sich diese erkaufen. Nicht ohne Grund ist der Python-Interpreter so viel langsamer als reiner C-Code. Wenn ein Programm effizient laufen muss, dann ist die Anzahl der Alternativen mit einem verlässlichen Compiler recht überschaubar.
Das Leben ist wie ein Tennisball.
jerch
User
Beiträge: 1633
Registriert: Mittwoch 4. März 2009, 14:19

Dienstag 3. Juni 2014, 08:41

Darii hat geschrieben:Die Lehre aus Heartbleed sollte eben sein, dass man solch gravierende Sprachdefizite nicht durch QA oder (reklamierte) Fertigkeiten des Programmierers kompensieren kann.
Wenn ich mit einem funktionstüchtigen Fahrrad hinfalle - dann ist das Fahrrad schuld? Oder fehlende Helm? Das sind doch alles nur Werkzeuge, welches jedes für sich einen gewissen Sachverstand in der Benutzung voraussetzt.
Die "Rohheit" von C hat eben ihre Vorteile und kommt zu einem Preis. Preis ist eben all das, was EyDu aufzählt, von Haus aus nicht mitgeliefert wird. Dir ist freigestellt, sowas zu nutzen (nichts hält Dich davon ab, einen smart_ptr zu implementieren), es liegt in Deiner Verantwortung.
Die Hauptvorteile folgen ganz klar aus der Maschinennähe, welche Laufzeiten, Speicherverbrauch und Kompilate klein hält. So schleppen die Wirthsprachen eine kleine Laufzeitumgebung mit, welche die Sicherheitsfeatures vorhält. Das verdoppelt bis verdreifacht mal eben die Laufzeit.

Das C nach wie vor diese ubiquitäre Verbreitung hat, liegt mMn nicht nur an geerbter Verbreitung oder dem "Druck" der alten Programmierer. Die meisten kompilierenden Sprachen verstehen die C-Aufrufkonvention, trotzdem findet man kaum Pascal oder Ada Drittbibliotheken, C++ ist hier die einzige Ausnahme. So werden selbst neue Programmierfelder wie die GPU-Programmierung per C-Syntax erschlossen (siehe OpenCL oder CUDA). Herr Ritchie hat mit der zugegeben schmalbrüstigen C-Lib einen Quasistandard geschaffen, den selbst der letzte Mikrocontrollerhersteller bedienen kann. Die Portierung vieler anderer Sprachen dürfte hier schon an den Systemanforderungen scheitern.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Mittwoch 4. Juni 2014, 07:59

Das ist mir alles klar und das will ich auch nicht abstreiten, aber das Hauptproblem von C ist, dass es keine Möglichkeit gibt auf einen "sicheren" Modus umzuschalten wenn man mal nicht die letzten 2% Geschwindigkeit braucht. In 99% der Fälle in denen C verwendet wird, würde ein Speichercheck zur Laufzeit nicht weh tun, aber sehr viel zur Sicherheit beitragen. C ist optimiert auf einen Grenzfall, den man fast nie braucht.

Das ist der Unterschied zu Rust. Rust ist standardmäßig sicher, mit all den Nachteilen den das mit sich bringt. Aber man darf, wenn man muss, "unsichere" Operationen in unsafe{}-Blöcken durchführen, also Arrays wie in C als Zeiger interpretieren, allgemein mit nullbaren C-artigen Zeigern hantieren, oder komische typecasts machen etc.. Das vereinfacht die Sicherheitsprüfung ungemein. Ein "grep unsafe" über den Code reicht, um die Stellen zu finden, die man sehr genau angucken muss.

Rust benötigt im Gegensatz zu allen anderen Sprachen die C ersetzen wollen weder einen GC noch eine Laufzeitumgebung. Ersterer ist ähnlich die in C++ als smart_pointer in der Library implementiert und letztere kann man beim kompilieren ausstellen. Rust läuft wie schon erwähnt ohne Probleme auf Mikrocontrollern (bis jetzt nur auf ARM).

Kleine Anmerkung: C ist selbst für embedded-Programmierung eigentlich nicht gut genug ist. Man muss sich oft mit häßlichen Makros helfen (C++ ist besser, aber templates werden sehr schnell sehr unleserlich wenn man vergleichsweise einfach Dinge tun will, sofern C++ überhaupt unterstützt wird, siehe PIC) die nicht Teil der Sprache, sondern stumpfes Suchen und Ersetzen durch den Preprocessor sind.
Antworten