Hallo,
in C hat ja static eine doppelbedeutung.
-bei lokalen variablen innerhalb von funktionsrümpfen wird eine variable
statisch im speicher abgelegt und bleibt somit auch nach dem
funktionsaufruf erhalten. hier hat "static" die bedeutung von
"feststehend"
-bei funktionen/variablen wird mit static die sichtbarkeit auf die
aktuelle übersetzungseinheit der funktion/variable beschränkt. warum zum
teufel haben die macher von C hier auch das schlüsselwort
static=feststehend verwendet???? das macht doch gar keinen sinn und
führt zu verwirrung bei dieser doppelverwendung? oder findet irgendwas
im hintergrund statt, das die bedeutung von static an dieser stelle
erklärt??
mfg
Sina stellte fest:
>..und führt zu verwirrung bei dieser doppelverwendung
Die Syntax dieser Sprache führt ohnehin oft zu Verwirrung und ist schwer
zu erlernen. Da kommt es auf diese Doppeldeutigkeit auch nicht mehr an.
Return of Schnulli schrieb:> Die Syntax dieser Sprache führt ohnehin oft zu Verwirrung und ist schwer> zu erlernen. Da kommt es auf diese Doppeldeutigkeit auch nicht mehr an.
Man stelle sich vor, es gibt Programmiersprachen, da hat sogar schon ein
simples Gleichheitszeichen eine mehrfache Bedeutung, die sich nur aus
dem Kontext erschließt...
Mit B=3 ist je nach Positionierung etwas anderes als B=3 gemeint:
> das macht doch gar keinen sinn und> führt zu verwirrung bei dieser doppelverwendung?
Wir C-Programmier wollen halt nicht das sich jeder Schnullerbubi
Programmierer schimpfen kann. :-)
Olaf
ist doch ganz einfach - man muss weniger Schlüsselworte lernen.
auch die Buchstaben haben in C oft eine mehrfache Verwendung: "i" wird
in if und while verwendet.
Im Kern ist das static in beiden Fällen die Ansage, dass der Compiler
direkt eine feste Adresse benutzen soll. Bei einer Funktion hat das dann
die Folge, das der Linker die Funktion nicht mehr bearbeitet und externe
die nicht nutzen können. Für eine Variable ist der Nebeneffekt halt dass
der Wert erhalten bleibt.
Das kommt hat weil C eine alte Hardware nahe Sprache ist, mehr von der
ASM Seite gewachsen als als Hochsprache geplant.
Es gibt schlimmere Doppelbelegungen.
Z.B. wenn man eine Schleife verlassen will, geht das mit Break.
Hat man mehrere Abbruchbedingungen, würde sich ein Switch geradezu
anbieten und wäre auch am besten lesbar.
Dummm nur, daß dann das Break nicht die Schleife verläßt.
Hier kann man nur ein Goto zum Verlassen benutzen.
sina anargo schrieb:> warum zum teufel haben die macher von C hier auch das schlüsselwort> static=feststehend verwendet?
Warum zum Teufel ist „modul-lokal“ nicht die voreingestellte
Sichtbarkeitsregel? Dann hätte man “global” als Schlüsselwort für
solche Daten und Funktionen festlegen können, die auch außerhalb der
aktuellen Übersetzungseinheit sichtbar sein müssen.
Die Antwort ist ganz einfach: historischer Ballast.
@dl8dtl modul-lokal in einer Sprache in der Module allenfalls als
Toolchain-Konzept aber nicht wirklich als Sprachkonstrukt vorkommen?
Klingt riskant...
sina anargo schrieb:> in C hat ja static eine doppelbedeutung.
Das sieht nur auf den ersten Blick so aus. Beide Deiner Beschreibungen
passen sowohl bei lokalen als auch bei globalen:
1. Beide Variablen-Typen sind "feststehend", liegen also nicht auf dem
Stack oder Heap.
2. Beide Typen sind "von außen" nicht sichtbar.
Da ist also gar keine Doppelbedeutung, wenn man etwas länger drüber
nachdenkt.
Peter Dannegger schrieb:> Dummm nur, daß dann das Break nicht die Schleife verläßt.> Hier kann man nur ein Goto zum Verlassen benutzen.
Oder einfach 'continue' ?
Andy D. schrieb:> @dl8dtl modul-lokal in einer Sprache in der Module allenfalls als> Toolchain-Konzept aber nicht wirklich als Sprachkonstrukt vorkommen?> Klingt riskant...
hä? In C heißt das eben anders, z.b. "internal linkage" und "translation
unit" etc.
Siehe 6.2.2 Linkages of Identifiers.
>> Alles nur kein GOTO :P
Peter meinte eine Schleife mit echter Abbruchbedingung - darin ein
switch. Man kann die Schleife innerhalb des Switches entweder mit einem
goto verlassen oder ... so mache ich das meist ... vor dem break dafür
sorgen, dass die Bedingung der Schleife nicht mehr erfüllt ist.
Gruß,
Frank
Ulrich schrieb:> Im Kern ist das static in beiden Fällen die Ansage, dass der Compiler> direkt eine feste Adresse benutzen soll. Bei einer Funktion hat das dann> die Folge, das der Linker die Funktion nicht mehr bearbeitet und ...
Käse :-) Der Compiler hat mit Adressvergabe grad garnix am Hat, das
macht immer noch der Linker / Lokator, im Fall der GCC also ld.
Random ... schrieb:> ... dann gibt es noch die Variante in C++, hier haben alle Instanzen> Zugriff auf die gleiche static variable innerhalb einer> member-funktion :-)
Und dann gibt's auch noch Member-Funktionen, die static sind.
Frank M. schrieb:> sina anargo schrieb:>> in C hat ja static eine doppelbedeutung.>> Das sieht nur auf den ersten Blick so aus. Beide Deiner Beschreibungen> passen sowohl bei lokalen als auch bei globalen:>> 1. Beide Variablen-Typen sind "feststehend", liegen also nicht auf dem> Stack oder Heap.
Das tut eine Variable außerhalb der Funktion auch ohne static.
> 2. Beide Typen sind "von außen" nicht sichtbar.
Das ist bei lokalen Variablen aber immer so und kommt ebenfalls nicht
erst durch static.
> Da ist also gar keine Doppelbedeutung, wenn man etwas länger drüber> nachdenkt.
Und wenn man noch etwas länger drüber nachdenkt, ist doch eine da. ;-)
Johann L. schrieb:> Ulrich schrieb:>> Im Kern ist das static in beiden Fällen die Ansage, dass der Compiler>> direkt eine feste Adresse benutzen soll. Bei einer Funktion hat das dann>> die Folge, das der Linker die Funktion nicht mehr bearbeitet und ...>> Käse :-) Der Compiler hat mit Adressvergabe grad garnix am Hat, das> macht immer noch der Linker / Lokator, im Fall der GCC also ld.
Das ist nicht ganz richtig. Der Compiler könnte static Funktionen z.b.
inlinen.
Rolf Magnus schrieb:>> Da ist also gar keine Doppelbedeutung, wenn man etwas länger drüber>> nachdenkt.>> Und wenn man noch etwas länger drüber nachdenkt, ist doch eine da. ;-)
Welche denn? Die beiden im Ausgangsposting genannten jedenfalls nicht.
Denn diese treffen für beide Typen von static-Variablen zu.
Auch Deine (natürlich korrekte) Aussage
> Das tut eine Variable außerhalb der Funktion auch ohne static.
ist für mich kein wirklicher Widerspruch.
Mike Roh schrieb:> Johann L. schrieb:>> Ulrich schrieb:>>> Im Kern ist das static in beiden Fällen die Ansage, dass der Compiler>>> direkt eine feste Adresse benutzen soll. Bei einer Funktion hat das dann>>> die Folge, das der Linker die Funktion nicht mehr bearbeitet und ...>>>> Käse :-) Der Compiler hat mit Adressvergabe grad garnix am Hat, das>> macht immer noch der Linker / Lokator, im Fall der GCC also ld.>> Das ist nicht ganz richtig. Der Compiler könnte static Funktionen z.b.> inlinen.
Was aber nix mit Adressvergabe zu tun hat, sondern damit, ob er die
Implementierung der Funktion kennt oder nicht. Er kann auch extern
Funktionen inlinen, etwa mit Optimierungen wie LTO. Auch das hat im
Kern nix mit Adressvergabe zu tun. Der Compiler vergibt keine
Adressen.
Im Ur-C-Compiler für Unix war der "static"-Qualifier lokalen Variablen
vorbehalten, wo er festlegt, dass die Lebensdauer einer Variable im
Gegensatz zu "auto" nicht auf die Dauer der Funktionsausführung
beschränkt sein soll.
Globale Variablen mit "static" gab es nicht, was ja auch logisch ist, da
globale Variablen in C immer statisch sind.
Es entstand neben dem Unix-C-Compiler noch einer für GCOS, der bereits
die spezielle Bedeutung von "static" für globale Variablen implementiert
hatte. Dass für dieses Feature ein bereits vorhandenes Schlüsselwort
genutzt wurde, hatte den Vorteil, dass der GCOS-Compiler (zumindest in
dieser Punkt) abwärtskompatibel zum Unix-Compiler war.
Später wurde dieses Feature dann auch in den Unix-Compiler übernommen,
zusammen mit der Möglichkeit, statische lokale Veriablen initialisieren
zu können, was vorher mit dem Unix-Compiler ebenfalls nicht möglich war.
Andy D. schrieb:> modul-lokal in einer Sprache in der Module allenfalls als> Toolchain-Konzept aber nicht wirklich als Sprachkonstrukt vorkommen?
Dann nenne es „lokal zur Übersetzungseinheit“, wenn dir das Wort besser
als „Modul“ gefällt.
Yalu X. schrieb:> Es entstand neben dem Unix-C-Compiler noch einer für GCOS, der bereits> die spezielle Bedeutung von "static" für globale Variablen implementiert> hatte.
Sag ich doch, historischer Ballast. :-)
Return of Schnulli schrieb:> Sina stellte fest:>>..und führt zu verwirrung bei dieser doppelverwendung>> Die Syntax dieser Sprache führt ohnehin oft zu Verwirrung und ist schwer> zu erlernen. Da kommt es auf diese Doppeldeutigkeit auch nicht mehr an.
Ja eine gewisse Barriere gibt es schon um C zu lernen.
Wenn man weiss was man erreichen will, gibts auch keine Verwirrung.
Must du halt lernen wie es verwendet wirdt.
>> Alles nur kein GOTO :P
wieso denn nicht? Ich finde GOTO gut. Wird ja ohnehin in ein GOTO (JMP)
uebersetzt auf assemblerebene.
ein seitenlanges switch statement mit breaks ist auch unuebersichtlich.
In Turbo Basic war SELECT CASE ein richtiges Schnuerkorsett.
Peter Dannegger schrieb:> Es gibt schlimmere Doppelbelegungen.>> Z.B. wenn man eine Schleife verlassen will, geht das mit Break.> Hat man mehrere Abbruchbedingungen, würde sich ein Switch geradezu> anbieten und wäre auch am besten lesbar.> Dummm nur, daß dann das Break nicht die Schleife verläßt.> Hier kann man nur ein Goto zum Verlassen benutzen.
Die richtig notorischen C programmierer schreiben eine Schleife ohne for
zu verwenden, also z.B.
Jörg Wunsch schrieb:> Dann nenne es „lokal zur Übersetzungseinheit“, wenn dir das Wort besser> als „Modul“ gefällt.
Ach Jörg, laß dich nicht foppen.
Es gibt halt mittlerweile zu wenige Leute, die des Pascales noch mächtig
sind. Dort braucht man keine Headerdateien, dort kann man dediziert in
der Quelle festlegen, welche Dinge des Moduls (oder nennen wir es
einfach wieder "UNIT" - dieses Wort gefällt mir sowieso besser) von
außen sichtbar sein sollen und welche nicht. Obendrein kann man dort
Variablen mit feststehender Adresse ('absolute') vereinbaren. Das wäre
wesentlich schicker und lesbarer als das Geprassel, was man sich bei µC
in C antun muß, um eines der Hardware-Register zu beschreiben.
Man hätte C schon längst reformieren können, anstatt immer noch eine
Version draufzusetzen. Aber seit dem Übergang von K&R nach ANSI ist den
Gremien wohl die Puste ausgegangen.
Tja, mal wieder das alte Thema..
W.S.
W.S. schrieb:> Jörg Wunsch schrieb:>> Dann nenne es „lokal zur Übersetzungseinheit“, wenn dir das Wort besser>> als „Modul“ gefällt.>> Ach Jörg, laß dich nicht foppen.> Es gibt halt mittlerweile zu wenige Leute, die des Pascales noch mächtig> sind. Dort braucht man keine Headerdateien, dort kann man dediziert in> der Quelle festlegen, welche Dinge des Moduls (oder nennen wir es> einfach wieder "UNIT" - dieses Wort gefällt mir sowieso besser) von> außen sichtbar sein sollen und welche nicht. Obendrein kann man dort> Variablen mit feststehender Adresse ('absolute') vereinbaren. Das wäre> wesentlich schicker und lesbarer als das Geprassel, was man sich bei µC> in C antun muß, um eines der Hardware-Register zu beschreiben.>> Man hätte C schon längst reformieren können, anstatt immer noch eine> Version draufzusetzen. Aber seit dem Übergang von K&R nach ANSI ist den> Gremien wohl die Puste ausgegangen.>> Tja, mal wieder das alte Thema..>>> W.S.
Also ich finde C gut.
mach doch mal einen Typ Cast in Pascal- es geht zwar, allerdings toll
ist es nicht gerade.
Ich finde C gut da ich es fast genauso wie Assembler verwenden kann.
Es gibt unions und es gibt Funktionszeiger. Deklariere doch mal in
Pascal ein Array mit funktionszeigern...
Und ja, es gibt Anwendungen dafuer.
Takao K. schrieb:> Es gibt unions und es gibt Funktionszeiger. Deklariere doch mal in> Pascal ein Array mit funktionszeigern...
Hä?
Wo lebst du?
Also
Erstens: Sowas wie unions gibt es auch in Pascal, nämlich records mit
variablem Innenleben.
Zweitens: Typecasts gibt es auch, wird aber wesentlich seltener benötigt
als in C und ist einleichtender: typebezeichner(operand).
function MyThreadProc(zahl:Pointer):longint;
begin
if (dword(zahl) and 16) <> 0 then blablabla..
Drittens:Funktionszeiger gibt es natürlich auch:
type
TWriter = procedure(S : String);
TReader = function : char;
var
MyWriter : TWriter;
MyReader : TReader;
Man kann dann, nachdem man den entsprechenden Funktionspointer in
MyReader und MyWriter eingetragen hat, MyReader und MyWriter wie normale
Prozeduren bzw. Funktionen aufrufen.
begin
MyReader:= @UART_In;
MyWriter:= @Drucker_Output;
c:= MyReader;
MyWriter('Hallo');
Also, wo ist dein Problem? Offenbar nur dieses, daß du Pascal nicht so
recht kennst.
W.S.
W.S. schrieb:> Sowas wie unions gibt es auch in Pascal, nämlich records mit variablem> Innenleben.
Mit dem Unterschied, dass man den Varianten-Selektor dort zwangsweise
als Bestandteil des Varianten-Records mit angeben muss, zumindest in
Standard-Pascal.
Pascal ist halt als Lehrsprache entwickelt worden und von da dann
aufgebohrt, wobei die einzelnen Hersteller nicht alle den gleichen
Bohrer benutzt haben. ;-) Herr Wirth wollte das dann mit Modula
wieder ausgleichen, was aber bei weitem nicht die Verbreitung
gefunden hat, die er sich gewünscht haben mag.
Jörg Wunsch schrieb:> W.S. schrieb:>> Sowas wie unions gibt es auch in Pascal, nämlich records mit variablem>> Innenleben.>> Mit dem Unterschied, dass man den Varianten-Selektor dort zwangsweise> als Bestandteil des Varianten-Records mit angeben muss, zumindest in> Standard-Pascal.>> Pascal ist halt als Lehrsprache entwickelt worden und von da dann> aufgebohrt, wobei die einzelnen Hersteller nicht alle den gleichen> Bohrer benutzt haben. ;-) Herr Wirth wollte das dann mit Modula> wieder ausgleichen, was aber bei weitem nicht die Verbreitung> gefunden hat, die er sich gewünscht haben mag.
PASCAL ist keine wirklich neue Sprache, hat der Herr Wirth von PL/1
abgekupfert. habe mich jahrelang damit abgegeben und oft hatte ich halt
Ideen, wurde aber von der Syntax eingeschraenkt.
Und es hat halt den ruf einer Hobby und Bastelsprache.
richtig eklig wird es wenn in Pascal pointer zusammengebaut werden
sollten. In C ist es schon schlimm genug.
Takao K. schrieb:> PASCAL ist keine wirklich neue Sprache, hat der Herr Wirth von PL/1> abgekupfert.
Ich hätte jetzt eher auf Algol (60/68) getippt.
> Und es hat halt den ruf einer Hobby und Bastelsprache.
Naja, sowas ist nicht unumstößlich. Ich habe zu CP/M-Zeiten gern in
Turbo-Pascal programmiert, denn die Programmierumgebung war angenehm
zu bedienen und recht flott (anders als die meisten C-Compiler und
auch alternative Pascal-Implementierungen damals), und man hatte
gegenüber Assembler den Vorteil einer deutlich effektiveren (bezüglich
des zu spendierenden Zeitaufwands) Programmierung. Als der EPROMmer
dann erstmal grundsätzlich lief, habe ich die innere Schleife in
Inline-assembler nachgeschrieben. Danach war es sowohl schnell als
auch gut bedienbar.
Jörg Wunsch schrieb:> Takao K. schrieb:>>> PASCAL ist keine wirklich neue Sprache, hat der Herr Wirth von PL/1>> abgekupfert.>> Ich hätte jetzt eher auf Algol (60/68) getippt.>>> Und es hat halt den ruf einer Hobby und Bastelsprache.>> Naja, sowas ist nicht unumstößlich. Ich habe zu CP/M-Zeiten gern in> Turbo-Pascal programmiert, denn die Programmierumgebung war angenehm> zu bedienen und recht flott (anders als die meisten C-Compiler und> auch alternative Pascal-Implementierungen damals), und man hatte> gegenüber Assembler den Vorteil einer deutlich effektiveren (bezüglich> des zu spendierenden Zeitaufwands) Programmierung. Als der EPROMmer> dann erstmal grundsätzlich lief, habe ich die innere Schleife in> Inline-assembler nachgeschrieben. Danach war es sowohl schnell als> auch gut bedienbar.
Zugegeben, als ich Schueler war in der Realschule, konnte ich mit C
nicht viel anfangen. Das war installiert auf den Rechnern, aber zum
Kompilieren mussten halt bestimmte Einstellungen gemacht werden.
Internet oder Handbuecher gabs damals nicht.
Bei Turbo Pascal war ja eine Hilfefunktion dabei.
Habe ich dann z.B. verkettete Liste programmiert, und auch OOP
ausprobiert. Dann Mitte der 1990er bin ich auf Assembler umgestiegen- da
war halt das Schnuerkorsett weg.
Wenn ich mir Pascal Programme heute mal anschaue, moechte ich das
garnicht mehr machen.
Heutzutage gibts ja internet, es ist viel einfacher eine Antwort auf ein
bestimmtes Verstaendnissproblem zu erhalten.
Wenn C erst einmal richtig verstanden wird, ist es sehr leistungsfaehig
und die Art und Weise von Deklarierungen, Addressierung usw. ist sehr
praktisch.
z.B. mit MPLABX, gibt es Autocomplete fuer Strukturen, und Variablen
einfach im Debugger anzeigen (auch fuer Array/Strukture).
Das gabs 1990 nicht. So kann C dann auch recht schnell erlernt werden.
Peter Dannegger schrieb:> Es gibt schlimmere Doppelbelegungen.>> Z.B. wenn man eine Schleife verlassen will, geht das mit Break.> Hat man mehrere Abbruchbedingungen, würde sich ein Switch geradezu> anbieten und wäre auch am besten lesbar.> Dummm nur, daß dann das Break nicht die Schleife verläßt.> Hier kann man nur ein Goto zum Verlassen benutzen.
Break und goto arbeiten unterschiedlich. Das ist dir schon bekannt,
oder?
Wer goto braucht, kann nicht programmieren. :-P
anti c schrieb:> Wer goto braucht, kann nicht programmieren.
Ist auch mit Smiley eine unsinnige Aussage.
Kennst du Donald Knuth? Er hat mal einen Aufsatz geschrieben
"Structured Programming with Go To". Das war sein Protest gegen
Dijkstras dogmatisch gepredigten Verzicht auf goto.
Jörg Wunsch schrieb:> anti c schrieb:>> Wer goto braucht, kann nicht programmieren.>> Ist auch mit Smiley eine unsinnige Aussage.>> Kennst du Donald Knuth? Er hat mal einen Aufsatz geschrieben> "Structured Programming with Go To". Das war sein Protest gegen> Dijkstras dogmatisch gepredigten Verzicht auf goto.
Also ich will es garnicht mutmassen was Herr D. so privat macht wass Ihn
in die Lage versetzt solch ein Pamphlet anzufertigen.
Koennte ein Fall sein von "Ich will es garnicht wissen mir reicht schon
was ich sehe".
Und 20 Jahre spaeter dann so ein Krampf ein jeder plappert es nach, ja
nicht auch nur ein GOT0 verwenden oder Bestien aus dem Hades werden sich
manifestieren.
Es ist total egal- im Endeffekt gibt es einen Assembler mit Switch
Opcodes nicht. Nach einem Vergleich wird ja ohnehin ein GOTO verwendet
wie sollte es anders gehen? Es wird halt nur nicht ausgeschrieben.
Aus so einem Grund ist dieses Pamphlet halt ein Krampf.
Von mir aus kann auch Donald Duck was dazu schreiben. Das goto zerstört
den Programmfluss und macht die Software unübersichtlich. Im
Profibereich also ein no go.
anti c schrieb:> Peter Dannegger schrieb:>> Es gibt schlimmere Doppelbelegungen.>>>> Z.B. wenn man eine Schleife verlassen will, geht das mit Break.>> Hat man mehrere Abbruchbedingungen, würde sich ein Switch geradezu>> anbieten und wäre auch am besten lesbar.>> Dummm nur, daß dann das Break nicht die Schleife verläßt.>> Hier kann man nur ein Goto zum Verlassen benutzen.>> Break und goto arbeiten unterschiedlich. Das ist dir schon bekannt,> oder?>> Wer goto braucht, kann nicht programmieren. :-P
Was mir selbst zu eigen ist unterstelle ich halt anderen, um davon
abzulenken. Da wird aus dem Rowdy in der Schule der dich schikaniert
halt ein "Beschuetzer", er will dich ja nur abhaerten und er tut es nur
damit es andere nicht tun.
Alles Mueller oder was.
anti c schrieb:> Von mir aus kann auch Donald Duck was dazu schreiben. Das goto zerstört> den Programmfluss und macht die Software unübersichtlich. Im> Profibereich also ein no go.
Kannste darueber lachen wenn du dir die Disassemblierung anschaust. Es
zerstoert den Programfluss. Also wo denn, im Geiste?
Wenn du verschachtelte switch statements hast, und dann break
verwendest, musst du es halt schoen abarbeiten und viel Spass dabei.
SWITCH erst garnicht verwenden.
Wenn es nur bis zu 5 Vergeleiche sind, einfach mit IF abfragen ansonsten
einen Parser mit Tabelle verwenden.
anti c schrieb:> Von mir aus kann auch Donald Duck was dazu schreiben.
Nun, mit derart Überheblichkeit wirst du nicht weit kommen. Du
verspottest etwas, ohne es dir überhaupt angesehen zu haben.
> Das goto zerstört> den Programmfluss und macht die Software unübersichtlich. Im> Profibereich also ein no go.
Beides Unsinn.
Lassen wir das. Wir werden uns nicht einigen: ich kenne Knuths Gründe
(und nicht mehr alle davon stimmen heutzutage), und ich weiß, wann ich
selbst auch mal ein goto benutzen würde und wann lieber nicht.
Übrigens: wenn du kein goto benutzen willst, dann musst du auch unter
allen Umständen und komplett dogmatisch auf ein explizites "return"
aus einer Funktion verzichten (ausgenommen ganz am Ende). Das ist
nämlich auch nur ein verkapptes "goto". (Pascal hat sowas schließlich
auch nicht. ;-)
Jörg Wunsch (dl8dtl) (Moderator) schrieb:
anti c schrieb:
>> Von mir aus kann auch Donald Duck was dazu schreiben.> Nun, mit derart Überheblichkeit wirst du nicht weit kommen. Du> verspottest etwas, ohne es dir überhaupt angesehen zu haben.
Wahrscheinlich ist "anti c" nur ein verkanntes, unbekanntes Genie und
kann einiges mehr vorweisen, als "die paar Werke", die der "nur"
Stanford Prof. Donald E. Knuth, Autor des Standardwerks "The Art of
Computer Programming" sowie Urvater des Textsatzsystems TeX beigesteuert
hat, siehe
http://de.wikipedia.org/wiki/Donald_E._Knuth
Und als "anti c" wird er mit Freude und Wonne den Pascal Code im
angesprochenen Machwert über das "Pöse goto" förmlich in sich aufsaugen
http://cs.sjsu.edu/~mak/CS185C/KnuthStructuredProgrammingGoTo.pdf
und seine Bildungslücken damit eventuell ein wenig aufpolieren.
Achja, ich hab das goto Paper übrigens auch nicht gelesen. Dafür aber
u.A. das ein- oder andere TeX Buch mal von ihm gekauft und gelesen
(laaange her).
Jörg Wunsch schrieb:> Übrigens: wenn du kein goto benutzen willst, dann musst du auch unter> allen Umständen und komplett dogmatisch auf ein explizites "return" aus> einer Funktion verzichten (ausgenommen ganz am Ende). Das ist nämlich> auch nur ein verkapptes "goto". (Pascal hat sowas schließlich auch> nicht. ;-)
Ob Fortran oder Pascal irgendetwas haben oder nicht, spielt doch keine
Rolle. Ein goto ist in jeder Sprache Mist!
Übrigens: gibt es einen großen Unterschied zwischen return und goto.
Beim return weiss man genau wo es landet. In Unterprogrammen werden
garantiert stack und Register nach return restauriert. Beim goto ist das
Staunen des super spitzen Programmierers garantiert, wenn er damit wild
durchs Programm springt.
Ein guter Programmierer braucht kein goto! Es gibt keinen Fall, den man
nicht genauso gut und viel besser nachvollziehbar hin bekommt.
Nur weil es diesen Befehl gibt, muss er nicht sinnvoll sein und genutzt
werden. :-P
anti c schrieb:> Ob Fortran oder Pascal irgendetwas haben oder nicht, spielt doch keine> Rolle. Ein goto ist in jeder Sprache Mist!
Hast du das in der Schule / auf der Uni gelernt, oder sprichst du aus
Erfahrung?
Jeder gute, weise und erfahrene Programmierer wird dir sagen, dass deine
Pauschalaussage falsch ist.
Es gibt Fälle, wo ein goto sehr sinnvoll ist, den Programmfluss und die
Intention des Programmierers viel klarer hervortreten lässt, und
nebenbei noch viel ressourcenschonender ist.
Aber dazu gehört eben Erfahrung, viel (extrem viel) Code lesen und
verstehen.
Aber natürlich ist es viel einfacher, "goto ist böse" nachzuplappern...
Michael Reinelt schrieb:> Jeder gute, weise und erfahrene Programmierer wird dir sagen, dass deine> Pauschalaussage falsch ist.
Schon deshalb, weil man in FORTRAN (zumindest bis F77) praktisch nicht
ohne GOTO auskam. ;-)
anti c schrieb:> Nur weil es diesen Befehl gibt, muss er nicht sinnvoll sein und genutzt> werden. :-P
Nur, weil du mal gehört hast, dass er böse wäre, heißt das noch lange
nicht, dass es keine sinnvollen Einsatzfälle dafür gäbe.
Jörg Wunsch schrieb:> Schon deshalb, weil man in FORTRAN (zumindest bis F77) praktisch nicht> ohne GOTO auskam. ;-)
Und, stell dir vor, ich hab mein ganzes Leben lang (leider) nie FORTRAN
programmiert, und trotzdem verteidige ich das GOTO :-)
Ich spreche aus Erfahrung.
Und wie schon geschrieben: Es gibt keinen Fall, der nicht ohne goto für
die Nachwelt besser verständlich und nachvollziehbar ist.
Natürlich kann man mit einem goto aus einer for Schleife springen. Das
ist einfach und überschaubar. Aber das geht mit einem break genauso gut.
Goto ist mächtig und erlaubt Sprünge quer durchs Programm. Das ist
gefährlich und bei einer vernünftigen Programmstruktur völlig unnötig.
Ich bleigbe dabei: goto ist gefährlich und überflüssig!
anti c schrieb:> Ich spreche aus Erfahrung.
Ah! Dann solltest dir vielleicht einen seriöseren Nick zulegen? Deiner
klingt jetzt nicht grad nach 15 Jahren Programmiererfahrung und >1Mio
LOC
Michael Reinelt schrieb:> Und, stell dir vor, ich hab mein ganzes Leben lang (leider) nie FORTRAN> programmiert
Hast du nichts verpasst. :-)
anti c schrieb:> Und wie schon geschrieben: Es gibt keinen Fall, der nicht ohne goto für> die Nachwelt besser verständlich und nachvollziehbar ist.
Doch, gibt es. Aber die willst du ja gar nicht wissen.
Jörg Wunsch schrieb:> anti c schrieb:> Und wie schon geschrieben: Es gibt keinen Fall, der nicht ohne goto für> die Nachwelt besser verständlich und nachvollziehbar ist.>> Doch, gibt es. Aber die willst du ja gar nicht wissen.
Bla blab bla, wo ist den der Stein der Weisen?
anti c schrieb:> Ich spreche aus Erfahrung.>> Und wie schon geschrieben: Es gibt keinen Fall, der nicht ohne goto für> die Nachwelt besser verständlich und nachvollziehbar ist.>> Natürlich kann man mit einem goto aus einer for Schleife springen. Das> ist einfach und überschaubar. Aber das geht mit einem break genauso gut.> Goto ist mächtig und erlaubt Sprünge quer durchs Programm. Das ist> gefährlich und bei einer vernünftigen Programmstruktur völlig unnötig.>> Ich bleigbe dabei: goto ist gefährlich und überflüssig!
also mit deinem Sprachgebrauch hast du wohl mal ein Beratungsgespraech
noetig.
Goto ist mächtig
Nee ist es nicht.
und erlaubt Sprünge quer durchs Programm
Ja klar aber wer will das wirklich?
Vielleicht siehst du es ein dass der Compiler aus dem C Source ein
Assembler programm erzeugt, und dass ist voll mit GOTOs.
Wie sollte denn ein IF funtionieren wenn nicht mit GOTO? Es ist nur eine
andere Schreibweise.
CMP Register, Value
JNE Do_Something1
// Do_Something2
JMP Ready
Do_Something1:
// something
Ready:
Oder willst du est abstreiten dass die CPU genau dass macht?
if (var=value)
{
do_something();
} else
{
do_something2();
}
ein Lastwagen mit 80 KMH auf der Autobahn ist auch gefaehrlich.
anti c (Gast) schrieb:
Jörg Wunsch schrieb:
>> anti c schrieb:>> Und wie schon geschrieben: Es gibt keinen Fall, der nicht ohne goto für>> die Nachwelt besser verständlich und nachvollziehbar ist.>>>> Doch, gibt es. Aber die willst du ja gar nicht wissen.> Bla blab bla, wo ist den der Stein der Weisen?
Lies beispielsweise "Programmieren in C", Kernighan/Ritchie, 2. Ausgabe,
Kapitel 3.8 goto und Marken
Dort findet sich ein Beispiel was auch hier illustriert ist
http://openbook.galileocomputing.de/c_von_a_bis_z/008_c_kontrollstrukturen_012.htm#mj42701038b17e1c01b0daef016a195d43
Deine Argumentationslinie ist, du versuchst ein Dogma aufzustellen
(niemals, nicht goto !!), während andere im Regelfall goto für abwegig
erklären, weil mans nicht braucht, aber dennoch die Ausnahme zulassen
bzw. anerkennen.
Takao K. (takao_k) schrieb:
> Vielleicht siehst du es ein dass der Compiler aus dem C Source ein> Assembler programm erzeugt, und dass ist voll mit GOTOs.
Diese Argumentation ist natürlich auch etwas fragwürdig, weil du damit
gewissermaßen das Compilat dem Quellcode gleichstellst, nach dem Motto,
im Endeffekt ist alles Assemblercode (oder Maschinencode). Das hieße
dann aber auch, man könnte sich die ganze OOP mit dem ganzen
"Klassengedöns" schenken, weil am Ende wird eh alles in einfachste
Assembleranweisungen aufgelöst und von den Klassen bleibt nichts übrig.
;-)
Visualdingens schrieb:> Takao K. (takao_k) schrieb:>>> Vielleicht siehst du es ein dass der Compiler aus dem C Source ein>> Assembler programm erzeugt, und dass ist voll mit GOTOs.>> Diese Argumentation ist natürlich auch etwas fragwürdig, weil du damit> gewissermaßen das Compilat dem Quellcode gleichstellst, nach dem Motto,> im Endeffekt ist alles Assemblercode (oder Maschinencode). Das hieße> dann aber auch, man könnte sich die ganze OOP mit dem ganzen> "Klassengedöns" schenken, weil am Ende wird eh alles in einfachste> Assembleranweisungen aufgelöst und von den Klassen bleibt nichts übrig.>> ;-)
Wieso denn? Es ist auch in Assembler moeglich, OOP zu verwenden, wurde
sogar mal gemacht.
C ist schon mit Assembler zu vergleichen, der Vorteil ist halt weniger
Schreibarbeit, und es ist nicht von Befehlssatz abhaengig.
Wenn ich einen Pointer dereferenziere, und einen Index hinzufuege, und
dann noch inkrementiere, errinert dies schon sehr an bestimmte Assembler
Addressierungsarten.
In BASIC gehts dies nicht ausser man arbeitet mit einem Array und es ist
dann sehr umstaendlich.
In PASCAL geht es irgenwie so ein bisschen aber es ist ein Krampf (typ
cast nach Integer, inkrementieren, typ cast nach pointer).
In C wird Pointer Arithmetik halt direkt unterstuetzt, es ist ein
Merkmal dieser Sprache.
Modernes C++ arbeitet nicht mehr soviel mit Pointer Arithmetik. Hier
werden (z.B. unter Windows) oft spezielle Spracherweiterungen verwendet
(z.B. gibt es Array Lists, und den new operator). Da Windows aber so
stark verbreitet ist, quasi ist es ein Standard.
Ein modernes Windows programm laesst sich nict mehr gut mit Assembler
vergleichen- teilweise wird es sogar zuerst in MSIL uebersetzt. Also
nicht mehr vom Befehlssatz abhaengig.
GOTO- Ich wuerde sagen +- 50 Zeilen ist in Ordnung. Viel laenger als
einige Seiten sollte eine Funktion ohnehin nicht sein.
Aus einer Funktion herausspringen ist nicht so gut, wegen des Stacks,
wenn es ueberhaupt geht.
In 95% aller Faelle wenn GOTO verwendet wird sind es vielleicht 10
Zeilen, und es kann die Lesbarkeit in bestimmten Faellen erhoehen.
Insbesondere fuer Fehlerabfrage ist es einfach praktisch, nicht break zu
verwenden, und dann eine Unmenge von Flags zu verwalten, sondern GOTO zu
verwenden.
In Windows C++ gibt es aber schon catch/try...
Also wer ueber GOTO lamentiert dass es total schlimm ist es auch nur ein
paar mal zu verwenden, dass ist halt kein richtiger Programmierer.
Ich verwende GOTO so oft wie moeglich, immer dann wenn es Sinn macht,
und gut oder "besser" aussieht.
Warum denn eine Schleife verkrampfen, rueckwaerts laufen lassen und
komplizierte tests einbauen, wenn es mit 2 GOTOs viel einfacher geht?
z.B. denk mal ueber den Fall, wenn du Daten hast in einer Struktur,
allerdings brauchen diese nicht alle 8 bits, also verwendest du im 1.
Feld noch die 3 oberen bits fuer etwas anderes.
Warum denn eine komplizierte Strukturdefinition, und umstaendliche
Konstrukte? Der Sonderfall wird halt einfach einmal direkt abgefragt.
OOP mag es hingegen nicht so sehr, weitgehend nur char* zu verwenden.
Also auch wenn es eigentlich keine 8 bit chars sind, wird trotzdem ein
char* pointer verwendet. Wozu dieser Datentyp Krampf wie in PASCAL, wenn
es nicht wirklich zu irgendetwas nuetze ist, ausser um sicherzustellen,
der Lehrer hat Recht, und der Student nicht.
Warum also ist goto so verpönt? Aus Performance-Gründen! Durch goto wird
der normale Ablauf des Programms einfach unterbrochen.
http://openbook.galileocomputing.de/c_von_a_bis_z/008_c_kontrollstrukturen_012.htm
Ist ja totaler Unsinn, das GOTO wird verwendet, weil der Progrmmablauf
in einer bestimmten Art und Weise unterbrochen werden soll.
Das ist einfach nur total falsch.
Jörg Wunsch schrieb:> Michael Reinelt schrieb:>> Und, stell dir vor, ich hab mein ganzes Leben lang (leider) nie FORTRAN>> programmiert>> Hast du nichts verpasst. :-)
Doch - ich könnte in FORTRAN-Diskussionen besser mitreden ;-)
Takao K. schrieb:> Hier> werden (z.B. unter Windows) oft spezielle Spracherweiterungen verwendet> (z.B. gibt es Array Lists, und den new operator). Da Windows aber so> stark verbreitet ist, quasi ist es ein Standard.Takao K. schrieb:> In Windows C++ gibt es aber schon catch/try...
Wat? Alle diese Dinge sind im C++ Standard definiert und funktionierem
damit in allen konformen Implementationen, wie zB GCC unter Linux - da
ist überhaupt nix windows-spezifisch dran...
Dr. Sommer schrieb:> Takao K. schrieb:>> Hier>> werden (z.B. unter Windows) oft spezielle Spracherweiterungen verwendet>> (z.B. gibt es Array Lists, und den new operator). Da Windows aber so>> stark verbreitet ist, quasi ist es ein Standard.>> Takao K. schrieb:>> In Windows C++ gibt es aber schon catch/try...> Wat? Alle diese Dinge sind im C++ Standard definiert und funktionierem> damit in allen konformen Implementationen, wie zB GCC unter Linux - da> ist überhaupt nix windows-spezifisch dran...
Gibts da auch schon Array Lists?
Ich habe nicht behauptet das catch/try Windows spezifisch ist, eher so
zu verstehen dass es catch/try in C nicht gibt.
Takao K. schrieb:> also mit deinem Sprachgebrauch hast du wohl mal ein Beratungsgespraech> noetig.
Wenn 's fachlich nicht reicht werden wir persönlich?
Das kann ich auch:
Was bist du überhaupt für ein hässlicher Kasper? Deine Beiträge in
verschiedenen Threads deuten auf einen Azubi im ersten Jahr. Und dann
hier so 'ne dicke Hose? Weiss noch nicht mal wie man 'nen PAL anpackt,
aber hier rumunken!
Das goto habe ich mit Basic unter CP/M abgelegt. Weil man es nicht
braucht, weil es nur verwirrt.
Und du Takao hast mit Sicherheit noch nie eine Prolemstellung gehabt,
die ein goto erfodern könnte.
Takao K. (takao_k) schrieb:
> Warum also ist goto so verpönt? Aus Performance-Gründen! Durch goto wird> der normale Ablauf des Programms einfach unterbrochen.> http://openbook.galileocomputing.de/c_von_a_bis_z/...> Ist ja totaler Unsinn, das GOTO wird verwendet, weil der Progrmmablauf> in einer bestimmten Art und Weise unterbrochen werden soll.> Das ist einfach nur total falsch.
Du hast dich hier auf einen Nebensatz des Autors eingschossen, den du im
übrigen nicht mal als Zitat wiedergegeben hast. Die Schlussfolgerung des
Autors finde ich auch missglückt und unzutreffend. Aber das Beispiel um
das es ging ist genau das Beispiel aus dem Kernighan/Ritchie. Der Autor
hat im übrigen klar herausgestellt, dass ein goto in C für ihn im
Regelfall wohl keinen guten Programmierstil darstellt.
Wenn du dem Autor Ungenauigkeit vorwirfst, nun die hast du auch. Dein
Satz hier
> Vielleicht siehst du es ein dass der Compiler aus dem C Source ein> Assembler programm erzeugt, und dass ist voll mit GOTOs.
ist jedenfalls kein Argument für ein goto. Stell dir vor, du hast eine
Programmiersprache in der es kein goto gibt. Dennoch wird das Compilat
immer auch Sprungbefehle ("goto"'s) aufweisen. Ganz einfach, weil
Prozessoren nun mal ohne Sprungbefehle nicht auskommen bzw. es im
Regelfall keine Prozessoren ohne Sprungbefehle gibt. Oder stell dir vor,
das goto wird in einer Neudefinition von C mal abgeschafft (nicht zu
erwarten). Dann sticht dein Argument auch nicht mehr.
Oder das Beispiel auf das dich Dr. Sommer (Gast) hingewiesen hat
(catch/try). Auch da warst du reichlich ungenau.
Aber es ist müßig sich am goto abzuarbeiten. Wer es nutzen möchte soll
es tun und wer nicht, wird seine Gründe dafür haben.
Takao K. schrieb:> Gibts da auch schon Array Lists?
Kommt drauf an was du damit meinst. Array List ist irgendwie ein
Widerspruch in sich - was denn jetzt, Array oder Liste? Es gibt
std::vector - quasi ein intelligentes Array, std::list - eine doppelt
verkettete Liste, std::deque - eine Doppel-Queue die als blockweise
verkettete Liste implementiert werden kann.
Und was heißt hier "schon", Windows/Microsoft ist jetzt nicht gerade
ganz vorne bei der C++ Entwicklung. GCC und Clang sind da weiter...
Takao K. schrieb:> Viel laenger als> einige Seiten sollte eine Funktion ohnehin nicht sein.
Hier wird nicht über den 25 Zeilen Textmodus geschrieben.
Takao K. schrieb:> Aus einer Funktion herausspringen ist nicht so gut, wegen des Stacks,> wenn es ueberhaupt geht.
Er weiss, wie goto funktioniert???
Takao K. schrieb:> Ich verwende GOTO so oft wie moeglich, immer dann wenn es Sinn macht,> und gut oder "besser" aussieht.
1. Lehrjahr und nicht E-Technik, oder er nutzt ROM-Basic. ;-)
Takao K. schrieb:> Warum denn eine Schleife verkrampfen, rueckwaerts laufen lassen
Jetzt aber so richtig ... :-(((
anti c schrieb:> Ich spreche aus Erfahrung.>> Und wie schon geschrieben: Es gibt keinen Fall, der nicht ohne goto für> die Nachwelt besser verständlich und nachvollziehbar ist.>> Natürlich kann man mit einem goto aus einer for Schleife springen. Das> ist einfach und überschaubar. Aber das geht mit einem break genauso gut.
Es sei denn, es ist mehr als eine Schleifen-Ebene.
Was sieht für dich eleganter aus?
1
intx,y;
2
3
for(y=0;y<size_y;++y)
4
{
5
for(x=0;x<size_x;++x)
6
{
7
if(data[y][x].value==val;
8
gotofound;
9
}
10
}
11
found:
12
// do something
oder
1
intx,y;
2
3
boolfound=false;
4
for(y=0;y<size_y;++y)
5
{
6
for(x=0;x<size_x;++x)
7
{
8
if(data[y][x].value==val;
9
{
10
found=true;
11
break;
12
}
13
}
14
if(found)
15
break;
16
}
17
// do something
Ich finde das ohne diese umständliche Hilfsvariable besser lesbar.
> Goto ist mächtig und erlaubt Sprünge quer durchs Programm. Das ist> gefährlich und bei einer vernünftigen Programmstruktur völlig unnötig.
Ein Messer erlaubt es, Menschen zu erstechen. Das ist auch gefährlich.
Dennoch sind Messer sehr nützlich, wenn man sie richtig verwendet.
Nur weil man mit einem Sprachkonstrukt etwas schlechtes machen könnte,
wird dieser dadurch nicht automatisch böse und muß zwingend vermieden
werden.
Rolf Magnus schrieb:> Ich finde das ohne diese umständliche Hilfsvariable besser lesbar.
Das sind auch ungefähr so die Sachen, die Knuth in seinem Aufsatz
damals angebracht hat.
anti c schrieb:> Takao K. schrieb:>> Viel laenger als>> einige Seiten sollte eine Funktion ohnehin nicht sein.> Hier wird nicht über den 25 Zeilen Textmodus geschrieben.>
Sondern 26 Zeilen.
> Takao K. schrieb:>> Aus einer Funktion herausspringen ist nicht so gut, wegen des Stacks,>> wenn es ueberhaupt geht.> Er weiss, wie goto funktioniert???>
Nicht so richtig aber es wird immer besser.
> Takao K. schrieb:>> Ich verwende GOTO so oft wie moeglich, immer dann wenn es Sinn macht,>> und gut oder "besser" aussieht.> 1. Lehrjahr und nicht E-Technik, oder er nutzt ROM-Basic. ;-)>
Klempnerlehre geschmissen.
> Takao K. schrieb:>> Warum denn eine Schleife verkrampfen, rueckwaerts laufen lassen> Jetzt aber so richtig ... :-(((
Warum eigentlich Schleife? Das sollte GOTO Konstrukt heissen.
> Ein Messer erlaubt es, Menschen zu erstechen. Das ist auch gefährlich.> Dennoch sind Messer sehr nützlich, wenn man sie richtig verwendet.> Nur weil man mit einem Sprachkonstrukt etwas schlechtes machen könnte,> wird dieser dadurch nicht automatisch böse und muß zwingend vermieden> werden.
Als Assemblerprogrammier weisst Du dass es verschachtelte Index garnicht
wirklich gibt:
i=0;
rl:;if(data[i++]!=value)if(i<[xs*ys])goto rl;
Behaupte ich nicht dass es guter Programmierstil ist aber aus FOR wird
am Ende halt immer GOTO.
Halt am Ende noch ein Dummy Element einbauen oder es muss nochmal
getestet werden.
Ich hätte aber auch noch Anwendungen, die von GOTO profitieren:
Du hast in einer Funktion viele Prüfungen und Rücksprungpunkte. So in
der Art:
1
a=hole_a()
2
if(a==NULL)returnNULL;
3
b=hole_b();
4
if(b==NULL)returnNULL;
5
c=hole_c();
6
if(c==NULL)returnNULL;
7
d=bereite_vor(a,b,c);
8
if(d==NULL)returnNULL;
9
result=tu_was(a,b,c,d);
10
returnresult;
Das ist die klassische Variante eines "getarnten goto"
Problem: wenn a,b,c allokierte Ressourcen sind, muss man die wieder
freigeben. Damit fällt das "einfache" return schon mal aus.
Man kann jetzt natürlich vor jedem return die bisher allokierten
Ressourcen freigeben. Unschön, weil ich das mehrmals machen muss.
natürlich kann man jetzt beliebig tiefe if's verschachteln:
1
result=NULL;
2
a=hole_a()
3
if(a){
4
b=hole_b();
5
if(b){
6
c=hole_c();
7
if(c){
8
d=bereite_vor(a,b,c);
9
if(d){
10
result=tu_was(a,b,c,d);
11
}
12
}
13
}
14
}
15
if(d)deallocate(d);
16
if(c)deallocate(c);
17
if(b)deallocate(b);
18
if(a)deallocate(a);
19
returnresult;
Das wird aber schnell extrem unübersichtlich. ich bevorzuge hier
durchaus die goto-Variante:
1
result=NULL;
2
a=hole_a()
3
if(a==NULL)gotoout;
4
b=hole_b();
5
if(b==NULL)gotoout;
6
c=hole_c();
7
if(c==NULL)gotoout;
8
d=bereite_vor(a,b,c);
9
if(d==NULL)gotoout;
10
result=tu_was(a,b,c,d);
11
out:
12
if(d)deallocate(d);
13
if(c)deallocate(c);
14
if(b)deallocate(b);
15
if(a)deallocate(a);
16
returnresult;
(nicht ganz korrekt, soll aber nur das Prinzip andeuten)
Dr. Sommer schrieb:> Daher wurde C++ erfunden, und eines seiner wichtigstes Features:> Destruktoren.
Korrekt. Aber gehen wir mal davon aus dass wir entweder keine
Destruktoren haben (C ohne ++) oder der Job nach dem "Out:" sich nciht
über Destruktoren abwickeln lässt...
> Wenn man dann noch exceptions verwendet, kann man sich die 3 if's sparen.
Wobei eine Exception auch nur wieder ein getarntes goto ist ;-)
Nebenbei: Exceptions werden meiner meinung nach auch viel zu inflationär
verwendet. ich habe zu viel Code gesehen, wo man vor lauter try/catch
dem code nicht mehr folgen kann...
Michael Reinelt schrieb:> Für mich sieht es falsch aus :-)
Das kann durchaus sein, das war nur so "dahingerotzt"...
> (increment in der while-Bedingung wird zu früh ausgeführt, du kommst nie> mit x=0 oder y=0 in die Schleife)
Das allerdings kann nicht sein...
Oliver
Michael Reinelt schrieb:> Dr. Sommer schrieb:>> Daher wurde C++ erfunden, und eines seiner wichtigstes Features:>> Destruktoren.>> Korrekt. Aber gehen wir mal davon aus dass wir entweder keine> Destruktoren haben (C ohne ++)
Einfach mit "g++" statt "gcc" kompilieren, dann hat man sie ;-)
> oder der Job nach dem "Out:" sich nciht> über Destruktoren abwickeln lässt...
Wie kann das denn? Destruktoren können beliebigen Code enthalten.
>> Wenn man dann noch exceptions verwendet, kann man sich die 3 if's sparen.> Wobei eine Exception auch nur wieder ein getarntes goto ist ;-)
So wie if, while, for, Funktionsaufrufe...
> Nebenbei: Exceptions werden meiner meinung nach auch viel zu inflationär> verwendet. ich habe zu viel Code gesehen, wo man vor lauter try/catch> dem code nicht mehr folgen kann...
Dann hat der Autor dieses Codes Exceptions nicht verstanden. Guter
Exception-sicherer Code enthält nur sehr wenige try/catch-Blöcke und
regelt das Aufräumen jeweils über... Destruktoren. In Java z.B. geht das
natürlich nicht weswegen man sich dort mit try/catch behfelfen muss -
einer der Gründe, warum C++ besser als Java ist.
Dr. Sommer schrieb:> Kurz, elegant, effizient und goto-frei...
Premature return ist doch nur ein verkapptes GOTO, und nach der
„reinen Lehre“ ebenfalls nicht zulässig. ;-)
Jörg Wunsch schrieb:> Premature return ist doch nur ein verkapptes GOTO, und nach der> „reinen Lehre“ ebenfalls nicht zulässig. ;-)
Deswegen ja Exceptions :-P Die hab ich im Original-Code zwecks
Verständlichkeit zunächst ausgeblendet...
muß man jetzt keine Exception auspacken, wenn NULL dort kein
fehlerhafter Wert des pointer ist, und es auch nichts per Destruktor
aufzuräumen gibt.
Oliver
Oliver S. schrieb:>> (increment in der while-Bedingung wird zu früh ausgeführt, du kommst nie>> mit x=0 oder y=0 in die Schleife)>> Das allerdings kann nicht sein...
Denke ich schon:
Oliver S. schrieb:> muß man jetzt keine Exception auspacken, wenn NULL dort kein> fehlerhafter Wert des pointer ist, und es auch nichts per Destruktor> aufzuräumen gibt.
ICH habe ja nichts gegen ein einfaches return gesagt ;-)
Michael Reinelt schrieb:> Oliver S. schrieb:>>> (increment in der while-Bedingung wird zu früh ausgeführt, du kommst nie>>> mit x=0 oder y=0 in die Schleife)>>>> Das allerdings kann nicht sein...>> Denke ich schon:>
1
>intx;
2
>while(x++<10){
3
>printf("x=%d\n",x);
4
>}
5
>
> zählt von 1 bis 10 (und nicht von 0 bis 9)
1
intx=-1;
2
while(++x<10)printf("x=%d\n",x);
sowas geht halt in BASIC oder PASCAL nicht.
Am besten noch so ein paar x und i global bereithalten.
Das sollte dann aber nur in kleineren Embedd C Programmen gemacht
werden.
Also nicht etwa dass ich es wirklich anrate.
vielleicht gehts ja garnicht richtig, nicht ausgetestet...
Michael Reinelt schrieb:> Wobei eine Exception auch nur wieder ein getarntes goto ist ;-)
Viel schlimmer noch: Das sind getarnte Longjumps. Und die sind an
Bösartigkeit wohl kaum noch zu übertreffen.
SCNR ;-)
Dr. Sommer schrieb:> Jörg Wunsch schrieb:>> Premature return ist doch nur ein verkapptes GOTO, und nach der>> „reinen Lehre“ ebenfalls nicht zulässig. ;-)> Deswegen ja Exceptions :-P
Das ist auch nur ein besser verstecktes "premature return". Die Idee
dieser "Lehre" ist ja, nur genau einen einzigen Punkt zu haben, an dem
die Funktion verlassen wird, nämlich am Ende. Das ist mit Exceptions
auch nicht gegeben, es sei denn, ich fange in jeder Funktion alle
Exceptions ab.
Yalu X. schrieb:> Michael Reinelt schrieb:>> Wobei eine Exception auch nur wieder ein getarntes goto ist ;-)>> Viel schlimmer noch: Das sind getarnte Longjumps. Und die sind an> Bösartigkeit wohl kaum noch zu übertreffen.
Früher waren beim GCC die Exceptions ja sogar über Longjump
implementiert. Heute wird das aber meines Wissens anders gehandhabt.
Rolf Magnus schrieb:> Heute wird das aber meines Wissens anders gehandhabt.
Die longjmp-Implementierung ist glaub' ich nach wie vor als Fallback
möglich, falls eine bestimmte Architektur nichts besseres zu bieten
hat. Die hat irgendwas mit "sjlj" im Namen, für "setjump/longjmp".
Yalu X. schrieb:> Viel schlimmer noch: Das sind getarnte Longjumps. Und die sind an> Bösartigkeit wohl kaum noch zu übertreffen.
Jo, aber Exceptions können nur aus Funktionen *raus*springen - am Stack
nach oben - und rufen auch "sauber" Destruktoren auf. Daher würde ich
sie als weit weniger bösartig als longjmp sehen, und auch sauberer als
manuelle (fehleranfällige) Fehlerbehandlung & Aufräumen. Wenn man
partout nur einen Exit-Punkt in einer Funktion haben will wird man wohl
zwangsläufig ziemlichen Spaghetticode (endlose if-else-Ketten)
produzieren?!
Dr. Sommer schrieb:> Wenn man partout nur einen Exit-Punkt in einer Funktion haben will wird> man wohl zwangsläufig ziemlichen Spaghetticode (endlose if-else-Ketten)> produzieren?!
Es sei denn, man benutzt goto ;-)
Rolf Magnus schrieb:> Es sei denn, man benutzt goto ;-)
Mit goto aus Schleifen und if's rauszuspringen um dann einen einzigen
Exit-Punkt in der Funktion zu haben ist irgendwie... inkonsequent?
Widersinnig? Bescheuert? :-D
Rolf Magnus schrieb:> Dr. Sommer schrieb:>> Wenn man partout nur einen Exit-Punkt in einer Funktion haben will wird>> man wohl zwangsläufig ziemlichen Spaghetticode (endlose if-else-Ketten)>> produzieren?!>> Es sei denn, man benutzt goto ;-)
Oder garkeine Fehlerbehandlung, muss halt der Reset Taster gedrueckt
werden, oder das FAT FFS ist kaputt... Lesen geht ja noch, aber wenn
Dateien geschrieben werden, sollte am besten die Versorgungsspannung
ueberwacht werden, und alle Fehler genau ausgetestet werden.
Muesste halt ganz konkret gegenueber gestellt werden wie es mit, und
ohne GOTOs aussieht (Ich gehe jetzt mal von embedded C aus).
Unter Windows kann man sich auch nicht total darauf verlassen dass eine
Allokierung von irgenetwas auch geklappt hat, koennte ja sein, der
Speicher ist knapp, oder ein Skrip laeuft gerade Irre.
Genaugenommen muss es immer ausgetestet werden, und im Fehlerfall muss
zu einem sinnvollen Punkt zurueckgefunden werden. Hier auch nie darauf
verlassen das ein Requester ueberhaupt geoeffnet werden kann.
Nach einigen Wochen ohne Reboot ist das System manchmal sosehr
zerschossen, dass es nicht mehr ohne reboot geht.
GOTO oder nicht ist da eher noch eine Nebensache, mal davon abgesehen ob
eine Fehlerbehandlung ueberhaupt durchgehend eingebaut wird, oder es
halt bestenfalls einen Requester mit einer krausen Message gibt, und
RETRY CANCEL ABORT.
Unter Windows sind Programme oft uebervorsichtig, es wird dann
abgebrochen, unter LINUX gibts jede Menge Fehlermeldungen in der
Konsole, macht aber nicht wirklich etwas, und dass Programm kann
trotzdem noch weitgehend genutzt werden.
Wenn es mehrere Threads gibt kann ohnehin nicht einfach so hin und
hergesprungen werden. Solche Software wird dann oft garnicht mehr mit
klassischen verschachtelten Schleifen, if und case Kontrukten aufgebaut,
sondern diese ist dann weitgehend mit Skripts realisiert. Diese koennen
an C angelehnt sein, es kann binaercode in Tabellen sein, oder eine
spezialisierte Skriptsprache mit richtigem Parser.
MPLABX verwendet z.B. nicht mehr soviel Windows, sondern Java, und
vielzaehlige Module. Wenn z.B. der Debugger spinnt, geht die IDE
trotzdem noch.
Unbedingt mal "Writing Secure Software" von Microsoft lesen.
Dr. Sommer schrieb:> Rolf Magnus schrieb:>> Es sei denn, man benutzt goto ;-)> Mit goto aus Schleifen und if's rauszuspringen um dann einen einzigen> Exit-Punkt in der Funktion zu haben ist irgendwie... inkonsequent?> Widersinnig? Bescheuert? :-D
Okay, noch ein Vorschlag:
1
constintA=initA();
2
if(A==0)gotodoneA;
3
// Arbeit hier
4
5
constintB=initB(A);
6
if(B==0)gotodoneB;
7
8
// Hauptarbeit hier
9
10
doneB:cleanUpB();
11
doneA:cleanUpA();
12
return..
Wie geht das sch"oner mit Exceptions / Destruktoren?? Ich hab sowas in
einem realen Programm drin ('mxli'), es geht hier nicht um graue
Theorie, sondern um stufenweise Initialisierung und eben auch passende
Aufraeumarbeiten im Fehlerfall.
Takao K. schrieb:
DAS ist halt der Vorteil von Exceptions - man kann seinen Code einfach
so schreiben als träten nie Fehler auf, und wenn doch stürzt das
Programm wenigstens "sauber" ab anstelle von irgendeinen potentiell
gefährlichen Unsinn zu machen...
Marc P. schrieb:> Wie geht das sch"oner mit Exceptions / Destruktoren?
So: http://ideone.com/3lNflM
Man programmiert sich EIN mal eine Klasse pro Resourcen-Typ inklusive
Destruktor zum Aufräumen, initialisiert im Konstruktor und wirft evtl.
eine Exception, und muss dann wie in tuwas() gezeigt einfach nur noch
Instanzen davon anlegen. Dort braucht man dann überhaupt keine explizite
Fehlerbehandlung mehr (kein goto, kein if) und kann so programmieren als
könnte nichts schief gehen. Sowohl Im Fehler (Exception) -Fall als auch
im Erfolgs-Fall wird dann ordentlich genau das aufgeräumt was aufgeräumt
werden muss.
Hier haben wir natürlich ein gewisses Missverhältnis zwischen
"Hilfs-Code" (die Klassen) und dem eigentlichen Algorithmus ("tuwas"),
aber typischerweise implementiert man sich einmal so eine Klasse (wie zB
std::ifstream für eine Datei) und verwendet sie dann in vielen großen
Algorithmen, die dadurch viel kürzer und einfacher werden.
PS.: Und mit den so definierten Klassen kann man dann viele Funktionen
im "tuwas"-Stil schreiben und erhält saubere Fehlerbehandlung mit nur
einem einzigen try-catch-Block im Programm - dank Destruktoren.
Dr. Sommer schrieb:> DAS ist halt der Vorteil von Exceptions
Nicht von Exceptions, sondern von RAII. Wenn ich zwischendrin ein return
machen würde (oder ein goto) statt eine Exception zu werfen, würde das
genauso funktionierten.
Auf der anderen Seite funktiniert es aber nicht in Sprachen, die zwar
Exceptions, aber keine vernünftigen Destruktoren haben, da im
Exception-Fall die Ressourcen eben nicht unbedingt automatisch
aufgeräumt werden. Lustigerweise fehlen (deterministische) Destruktoren
in einigen Sprachen gerade deshalb, weil sie einen Garbage Collector
haben, der ja eigentlich für das automatische Aufräumen da ist. Dies ist
aber leider inkonsequent umgesetzt, da ausschließlich Speicher und keine
anderen Ressourcen behandelt werden. Um die muß man sich dann wieder von
Hand kümmern.
Rolf Magnus schrieb:> Nicht von Exceptions, sondern von RAII.
Ohne Exceptions hätte man aber im o.g. Fall (= wenn man Fehler nicht
explizit behandelt) ein Problem. Also wenn schon dank RAII+Exceptions.
Michael Reinelt schrieb:> Denke ich schon:> int x;> while (x++ < 10) {> printf ("x=%d\n", x);> }> zählt von 1 bis 10 (und nicht von 0 bis 9)
Noe. x hat irgendeinen Wert, da x nicht initialisiert wurde. Damit
laeuft die schleife im schlechtesten falle endlos, wenn x zu beginn der
schleife >=10 (weil nicht initialisiert) ist und x nach dem overflow
wieder einen Wert bekommt der >= 10 ist. Das koennte passieren, da das
verhalten bei einem signed overflow ja nicht definiert ist.
anti c schrieb:> Das goto zerstört> den Programmfluss und macht die Software unübersichtlich. Im> Profibereich also ein no go.
Schon mal in einen Kernel(z.B. Linux) oder in Treiber geschaut? Oder ist
Kernel-/Treiberprogrammierung kein Profibereich?
Dr. Sommer schrieb:> Sowohl Im Fehler (Exception) -Fall als auch> im Erfolgs-Fall wird dann ordentlich genau das aufgeräumt was aufgeräumt> werden muss.
Verstanden. Interessant ist die Ausgabe (zuerst 'cleanup A' dann 'B
failed') aber natuerlich logisch.
> Hier haben wir natürlich ein gewisses Missverhältnis zwischen> "Hilfs-Code" (die Klassen) und dem eigentlichen Algorithmus ("tuwas"),
Leider gibt es aber auch Faelle, bei denen man weiss, dass man die
Klassen nicht wiederverwerten wird, weil das Problem zu speziell ist.
Ich verstehe meine Wahl des goto mittlerweile so: aufgrund diverser
Kompromisse die ich im Vorfeld einging (ich bin ein grosser Fan von
Speicher auf dem Stack, nicht auf dem Heap anzulegen; meine Variablen
sind immer so lokal wie moeglich und werden nicht dupliziert; die
Funktion parst die Kommandozeile, was vieles in der Reihenfolge
laufzeit-bestimmt macht; ...) war die Wahl des goto das geringere Uebel.
Es ist nicht das Konstrukt goto das ich so mag, sondern der Kontext, der
das goto als einzig einfachen = (kurzen) Ausweg uebrig liess.
Der heftigste Kompromiss meines Programms ist wohl der: es ist ein
C-Programm (ohne ++). Schade, dass ich nicht weiss, ob ich in einem
C++-Programm ebenso gehandelt haette.
Marc P. schrieb:> Verstanden. Interessant ist die Ausgabe (zuerst 'cleanup A' dann 'B> failed') aber natuerlich logisch.
Ja das muss natürlich so.
>>> Hier haben wir natürlich ein gewisses Missverhältnis zwischen>> "Hilfs-Code" (die Klassen) und dem eigentlichen Algorithmus ("tuwas"),>> Leider gibt es aber auch Faelle, bei denen man weiss, dass man die> Klassen nicht wiederverwerten wird, weil das Problem zu speziell ist.
Dann kann man sich so behelfen: http://ideone.com/5qJKch
Man schreibt pro durchzuführender Aufräum-Aktion ein
1
autoirgendeinFreierBezeichner=cleanup([&](){/* hier aufräumaktion */});
Die wird dann garantiert immer durchgeführt, wenn die Funktion
zurückkehrt - unabhängig ob per "return", Erreichen des "}", oder
Exception - allerdings nur, wenn die Ausführung zuvor eben diese Zeile
erreicht hat (wenn die Funktion zuvor zurückgekehrt ist, nicht).
> Ich verstehe meine Wahl des goto mittlerweile so: aufgrund diverser> Kompromisse die ich im Vorfeld einging (ich bin ein grosser Fan von> Speicher auf dem Stack, nicht auf dem Heap anzulegen;
Sollte man immer machen, da der Stack viel schneller ist...
> meine Variablen> sind immer so lokal wie moeglich und werden nicht dupliziert;
Auch sehr sinvoll, um klarzustellen was sie alles beeinflussen
> Der heftigste Kompromiss meines Programms ist wohl der: es ist ein> C-Programm (ohne ++). Schade, dass ich nicht weiss, ob ich in einem> C++-Programm ebenso gehandelt haette.
Du kannst ja wie gesagt einfach mit "g++" statt "gcc" kompilieren und
schon hast du ein C++ Programm in dem du alle o.g. Nettigkeiten anwenden
kannst.
Dr. Sommer schrieb:> auto irgendeinFreierBezeichner = cleanup ([&] () { /* hier aufräumaktion> */ });
Wow! Seit wann? 'Anonyme' Funktionen? Das werde ich sicher verwenden!
Danke fuer den Tip!!
Marc P. schrieb:> Wow! Seit wann? 'Anonyme' Funktionen? Das werde ich sicher verwenden!> Danke fuer den Tip!!
Seit 2011 (C++11) - neben eine Menge anderer toller Features. Ist in der
Tat äußerst praktisch ;-)