Im Anhang ist mein kläglicher Versuch, ankommende Daten(Strings) in ein
Array zu schreiben. Ich arbeite mit einem Wiznet 5300. Senden klappt,
nur das Reinschreiben der FIFO-Daten(Empfangen) scheitert daran die
Daten aus dem FIFO byteweise und sinnvoll ins interne Memory vom Wiznet
zu schreiben. Der FIFO muss immer 16-Bit-weise ausgelesen werden,
deswegen temp0 und temp1. Die n +16-Gesichte soll die Bytes
aneinanderschieben. Kann mir jemand einen Hinweis geben? (bitte keine
"hier ist ein tutorial"-links). Es hakt bei payload =
((temp0<<m)+((temp1)<<n));
Frischling schrieb:> Im Anhang ist mein kläglicher Versuch, ankommende Daten(Strings) in ein> Array zu schreiben.
Da ist schon mal das erste Problem.
Woher weißt du, wann der String zu Ende ist? *payload kann ja wohl nicht
die Steuerung der Schleife übernehmen, denn in payload kommt ja das
Ergebnis rein. Wie willst du daber das Ergebnis befragen, wenn du die
Werte noch gar nicht hast? Das kann also so nicht stimmen.
Zum zweiten ist payload ein Array. Man kann damit natürlich über
Pointer-Syntax zugreifen. Aber eigentlich ist das recht witzlos. WEnn
etwas ein Array ist, dann behandle es auch als Array - ok, nicht immer,
aber an dieser Stelle ist es ganz sicher die einfachste Variante. Mach
dir eine index-Variable, mit der indizierst du in das Array
payload[index] = ....
und erhöhst den index nach jedem Zeichen.
Man muss das nicht komplizierter machen als notwendig.
> Es hakt bei payload = ((temp0<<m)+((temp1)<<n));
Darüber breiten wir mal den Mantel des Schweigens. Das ist auf so vielen
Ebenen falsch, dass es mit dem Hinweis auf ein Tutorial nicht getan
wäre.
Benutze Array-Index-Syntax wenn du mit Pointern auf Kriegsfuss stehst
und das Problem ist keines mehr.
Quelltext als in einer PDF-Datei versteckten Screenshotausschnitt
unterzubringen ist eine ganz tolle Idee.
Im übrigen ist auch die Bestimmung der Größe von "payload"
1
datasize=(udphead&0xFF000000);
2
charpayload[datasize];
ganz sicher nicht das, was Du erreichen willst. Damit ist nämlich
payload entweder 0 oder aber mindestens 16 MBytes groß.
Wenn du ein goto brauchst, dann stimmt was mit deiner Programmstruktur
nicht!
Meiner Meinung nach gibt es nur drei Einsatzgebiete für goto:
1. Kernel-Programmierung (da ist es sogar erwünscht!)
2. Assembler
3. Windows Batch-Scripte
In allen sonstigen Anwendungsfällen hat goto nichts zu suchen, es sei
denn, du legst keinerlei Wert auf strukturierte Programmierung.
Grüße
Kaj schrieb:> Tu dir selbst einen Gefallen und streich dasgoto>> Wenn du ein goto brauchst, dann stimmt was mit deiner Programmstruktur> nicht!>> Meiner Meinung nach gibt es nur drei Einsatzgebiete für goto:> 1. Kernel-Programmierung (da ist es sogar erwünscht!)
Und was macht der Kernel so besonderes mit goto, das deiner Meinung nach
niemals je einem anderen C-Programm nützlich sein könnte?
> In allen sonstigen Anwendungsfällen hat goto nichts zu suchen, es sei> denn, du legst keinerlei Wert auf strukturierte Programmierung.
Es gibt schon sinnvolle Einsatzmöglichkeiten, gerade um den Code besser
zu strukturieren. Das sind aber nicht viele. Im Prinzip nur zwei:
Fehlerhandling und die Möglichkeit aus einer Schleife mehr als eine
Ebene rauszuspringen, da break leider immer nur eine Ebene weit geht.
Rolf Magnus schrieb:> gerade um den Code besser> zu strukturierenRolf Magnus schrieb:> die Möglichkeit aus einer Schleife mehr als eine> Ebene rauszuspringen
Und du kannst nicht nur über mehrere Schleifenebenen springen...
Mit goto hast du die absolut wunderbare Möglichkeit einen Mischmasch aus
PAP, NSD und sonstwas zu schaffen. Tolle strukturierung ;)
Rolf Magnus schrieb:> Und was macht der Kernel so besonderes mit goto, das deiner Meinung nach> niemals je einem anderen C-Programm nützlich sein könnte?
In der (Linux-) Kernel- und Treiberprogrammierung wird mehr Wert auf
performanten Code gelegt.
Beispiel:
Ein Treiber fordert Speicher für drei Variablen an. Wenn das alozieren
von Speicher für nur eine Variable scheitert, muss der Vorgang
abgebrochen und der bereits gewährte Speicher wieder freigegeben werden.
1
// ohne goto
2
if(register_chardev(...)notfailed)
3
{
4
if(request_region(...)failed)
5
{
6
unregister_chardevv(...);
7
return-EIO;
8
}
9
if(request_irq(...)failed)
10
{
11
free_region(...);
12
unregister_chardev(...);
13
return-EIO;
14
}
15
return0;//success
16
}
17
return-EIO;
18
19
//gleicher code mit goto
20
if(register_chardev(...)notfailed)
21
{
22
if(request_region(...)failed)
23
gotoout_region;
24
if(request_irq(...)failed)
25
gotoout_irq
26
return0;//success
27
}
28
else
29
{
30
gotoout;
31
}
32
out_irq:
33
free_region(...);
34
out_region:
35
unregister_chardev(...);
36
out:
37
return-EIO;
Das ist (abgesehen von den weggelassenen argumenten) orginal code aus
dem linux-kernel / linux-treibern.
Natürlich ist es wieder eine Frage der eigenen Überzeugung:
goto or not goto, thats the question.
Aber ich sehe es mal so:
Es gibt mind. einen verdammt guten Grund, weshalb goto so verrufen ist:
Spaghetti-Code lässt grüßen! ;)
Wer es schaft mit goto wirklich gut und sauber strukturierten code zu
schreiben, an dem dann auch mehrere andere Programmiere nichts
auszusetzen haben, vor dem ziehe ich meinen Hut! (Auch wenn ich mir dann
erst einen Hut kaufen muss :D )
Allerdings dürfte das auf die wenigsten Programmiere zutreffen.
Grüße
Kaj schrieb:> Rolf Magnus schrieb:>> die Möglichkeit aus einer Schleife mehr als eine>> Ebene rauszuspringen>> Und du kannst nicht nur über mehrere Schleifenebenen springen...> Mit goto hast du die absolut wunderbare Möglichkeit einen Mischmasch aus> PAP, NSD und sonstwas zu schaffen. Tolle strukturierung ;)
Daß man das kann habe ich nie bestritten. Mit vielen Sprachmitteln
kann man Unsinn treiben. Deshalb muß man sie aber nicht gleich komplett
verbannen. Man kann auch mit einem Hammer jemandem den Schädel
einschlagen, und trotzdem wird er gerne und erfolgreich genutzt, um
Nägel in Wände zu bekomnmen.
> Rolf Magnus schrieb:>> Und was macht der Kernel so besonderes mit goto, das deiner Meinung nach>> niemals je einem anderen C-Programm nützlich sein könnte?>> In der (Linux-) Kernel- und Treiberprogrammierung wird mehr Wert auf> performanten Code gelegt.>> Beispiel:> Ein Treiber fordert Speicher für drei Variablen an. Wenn das alozieren> von Speicher für nur eine Variable scheitert, muss der Vorgang> abgebrochen und der bereits gewährte Speicher wieder freigegeben werden.
Exakt das meinte ich mit der Fehlerbehandlung, bei der goto nützlich
ist. Das ist es aber auch außerhalb des Kernels, und zwar nicht primär
aus Gründen der Peformanz, sondern der Übersichtlichkeit.
Variante 1 deines Beispiels beinhaltet Code-Duplizierung, die sehr
fehleranfällig ist. Außerdem ist die Fehlerbehandlung kreuz und quer mit
dem Code vermischt, während sie bei der goto-Variante schön sauber
getrennt ist. Ich empfinde das durchaus als besser strukturiert.
> Wer es schaft mit goto wirklich gut und sauber strukturierten code zu> schreiben, an dem dann auch mehrere andere Programmiere nichts> auszusetzen haben, vor dem ziehe ich meinen Hut! (Auch wenn ich mir dann> erst einen Hut kaufen muss :D )> Allerdings dürfte das auf die wenigsten Programmiere zutreffen.
Eigentlich ist es gar nicht so schwer. Es ist halt nur noch leichter,
mit goto Spaghetti-Code zu schreiben. ;-)
Rolf Magnus schrieb:> Es ist halt nur noch leichter,> mit goto Spaghetti-Code zu schreiben. ;-)
Genau deswegen ist es ja auch so verrufen ;)
Ich lass aufjedenfall meine fingerchen von goto, weil es auch ohne sehr
gut geht... und weil mich jeder Programmierer den ich kenne für den
einsatz von goto verprügeln würde. :D
Wenn ich an einer Stelle bin, wo ich mir denke "ach, ein goto wäre
eigentlich ganz schön...", dann überdenk ich nochmal meine
Programmstruktur, baue um, und dann geht es auch ohne goto.
Spätestens wenn noch andere auf den Code gucken oder damit arbeiten
müssen, hat sich das schon so gut wie erledigt. Und da gibt es noch mehr
Beispiele an Programmierpraktiken (in C/C++) die zwar ganz toll sind,
aber nicht effektiv angewand werden können, weil mehr als nur eine
Person mit dem Code arbeiten muss.
Aber wie ich oben schon geschrieben habe:
> Natürlich ist es wieder eine Frage der eigenen Überzeugung:> goto or not goto, thats the question.
So schön die Vorzüge auch sind, das K.O.-Kriterium "Spaghetti-Code"
überwiegt meiner Meinung einfach.
An den TO:
Ein bisschen mehr code als nur der Screenshot-Schnipsel wäre schon
hilfreich.
In diesem Sinne, schönen Mittwoch
Grüße
Kaj schrieb:> Ich lass aufjedenfall meine fingerchen von goto, weil es auch ohne sehr> gut geht...
aber nur, weil die freundlichen Sprachdesigner die gotos per
setjmp/lonjmp oder im OOP per try/catch verstecken. Ohne geht es halt
nicht immer.
Oliver
Nichts desto trotz würde ich den Rat an einen Anfänger unterschreiben,
die Finger von goto zu lassen.
Das die Könner goto sinnvoll einsetzen können, wird wohl niemand
abstreiten. Ein Anfänger ist aber kein Könner. Dafür setzen Anfänger
einen goto für alles mögliche ein, wo ein goto sicher nicht sinnvoll
ist.
Kaj schrieb:> Meiner Meinung nach gibt es nur drei Einsatzgebiete für goto:> 1. Kernel-Programmierung (da ist es sogar erwünscht!)> 2. Assembler> 3. Windows Batch-Scripte
und
4. Generierter Code
Beispielsweise verwendet GCC goto in auto-generiertem C-Code, der
während des GCC-Builds aus Maschinenbeschreibungen (md) erzeugt wird.
Ansonsten sähe man da Verschachtelungstiefen von mehreren 100 oder gar
1000 if-then-else.
Hier ein Beispiel für eine solche Datei mit ca 70000 Zeilen:
http://www.open64.net/doc/d3/d30/kg_09_09fe_2gnu_2i386_2insn-recog_8c-source.html
Zudem macht goto die Wiederverwendung von Code-Blöcken einfacher,
beispielsweise in
1
if(a)
2
{
3
if(b)
4
BLOCK1;
5
else
6
BLOCK2;
7
}
8
elseif(c)
9
BLOCK2;
Zwar kann man das mehrfache Auftauchen von Blöcken (hier BLOCK2) durch
Umformulierung der if-Bedingungen vermeiden, dadurch werden aber die
if-Bedingungen komplizierter, und es müssen mehrfach ähnliche
Teilausdrücke in den if-Abfragen getätigt werden. Für das kleine
Beispiel ist die Umformulierung zwar einfach, für die große, verlinkte
Datei ist eine Umformulierung aber weder zielführend noch hilfreich.
goto ist dort eindeutig die beste und überlegen Lösung.
Karl Heinz schrieb:> Nichts desto trotz würde ich den Rat an einen Anfänger unterschreiben,> die Finger von goto zu lassen.>> Das die Könner goto sinnvoll einsetzen können, wird wohl niemand> abstreiten. Ein Anfänger ist aber kein Könner. Dafür setzen Anfänger> einen goto für alles mögliche ein, wo ein goto sicher nicht sinnvoll> ist.
Sehe ich auch so. So wird's aber meist nicht verkauft, sondern eher so:
Goto entstammt der Hölle und wurde vom Teufel geschickt, um deinen Code
zu zerstören, also setze es blos niemals im Leben ein.
Deshalb haben auch die meisten Könner panische Angst vor goto, wie man
ja hier ganz gut sehen kann.