[gelöst] C: return beendet Funktion nicht

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

[gelöst] C: return beendet Funktion nicht

Beitrag von RobertDebiannutzer » 23.04.2018 10:35:03

Hallo,

ich habe ein seltsames Problem. Eine Funktion soll unter einer bestimmten Bedingung beendet werden und ich weiß genau, dass die Bedingung erfüllt ist. Trotzdem beendet sie sich nicht.
Ich habe die fragliche Funktion mal nach nopaste hochgeladen: NoPaste-Eintrag40283 (http://nopaste.debianforum.de/40283)
Es ist ein Ausschnitt aus der Datei "main.c" des Texteditors Microemacs (uEmacs/PK), den ich gerade bearbeite.
Das Originalprojekt wird von Linus Torvalds maintained:
s. hier: https://git.kernel.org/pub/scm/editors/ ... uemacs.git
oder hier: https://github.com/torvalds/uemacs

Ich bin gerade dabei, verschiedene Betriebsmodi zu integrieren (so wie bei vi(m)). Klappt soweit auch schonmal ganz gut (wenn auch noch nicht ganz fertig), es gibt gerade "nur" ein Problem (das ich aber wenigstens ganz klar eingrenzen kann):
Ich bin also nicht im "Insert"-Modus, sondern im Normalmodus. Nun drücke ich im Editor die Pfeiltaste nach unten.
Jetzt kommt Zeile 13 ins Spiel: Die Funktion "getbind" schaut in der Tastenkombinations-Datenbank nach, ob die Taste "Pfeiltaste nach unten" an eine Funktion gebunden ist.
Das ist sie natürlich:

Code: Alles auswählen

	{SPEC | 'B', forwline}
	,
Drücke ich die Pfeiltaste nach unten, dann will ich eine Zeile weiter nach unten.
So, nun funktioniert das auch!
D.h., getbind findet die Funktion und "execfunc" ist nicht (!!!) Null (s. Zeile 13/14), sondern hat den Inhalt "forwline".
Dennoch erscheint die Warnung "key not bound" (Zeile 28). Und das, obwohl die Funktion "forwline" ausgeführt wurde und somit die Funktion "execute" mittels "return status" (Zeile 18) hätte beendet werden müssen.

Möchte mir jemand helfen? Wird wahrscheinlich wieder ein ganz einfaches Problem sein, das ein Profi auf den ersten Blick sieht... :oops:
Zuletzt geändert von RobertDebiannutzer am 24.04.2018 14:29:43, insgesamt 1-mal geändert.

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: C: return beendet Funktion nicht

Beitrag von Meillo » 23.04.2018 10:50:30

Tipp: Verwende einen Debugger (gdb) oder debugge mit printf()s. Das hilft dabei, Tatsachen zu schaffen und angenommene Tatsachen zu verifizieren. Evtl. wird die Funktion ja zweimal ausgefuehrt, das erste Mal so wie du denkst und das zweite Mal anders. Lerne Debuggingtechniken, entweder indem du dir Anleitungen dafuer suchst, oder indem per Learning by doing.

Du kannst dir sicher sein, dass die Sprache korrekt funktionieren wird. Meistens helfen in diesen Faellen, wenn du dir sicher bist, dass die Sprache kaputt ist: Ein Spaziergang in der Natur, ein Tag Pause, oder der Satz ``Jetzt mal ganz langsam! Lass uns das mal runterbrechen und Schritt fuer Schritt im Kleinen pruefen!''.


Btw: Es gibt Gruende, warum man ``else if () {}'' so und nicht als ``else { if () {} }'' schreiben sollte, und die sind, dass es Fehler vermeidet.
Use ed once in a while!

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: C: return beendet Funktion nicht

Beitrag von RobertDebiannutzer » 23.04.2018 13:18:13

Vielen Dank für Deine Tipps. :)

Ich habe mal in, Zeile 17 "printf("%d", status);" eingeschoben. Dann kriege ich bei jedem Ausführen zusätzlich eine 1 auf den Bildschirm gezaubert.
Das beweist ja nochmal, dass die erste Bedingung zutrifft. Nur wie kann "execfunc" gleichzeitig Null und nicht Null sein?
Stoße ich jetzt in die Quantenphysik vor oder bin ich blöd - ich tippe auf letzteres... :wink:
Ich werd' mal versuchen, mehr Informationen mithilfe von gdb / printf zusammenzutragen.

Und das
Meillo hat geschrieben: ↑ zum Beitrag ↑
23.04.2018 10:50:30
Ein Spaziergang in der Natur, ein Tag Pause, oder der Satz ``Jetzt mal ganz langsam! Lass uns das mal runterbrechen und Schritt fuer Schritt im Kleinen pruefen!''.
werde ich auch beherzigen. :THX:

Meillo hat geschrieben: ↑ zum Beitrag ↑
23.04.2018 10:50:30
Btw: Es gibt Gruende, warum man ``else if () {}'' so und nicht als ``else { if () {} }'' schreiben sollte, und die sind, dass es Fehler vermeidet.
Ja, das hatte ich auch so, aber aus lauter Verzweifelung habe ich's dann eben mal anders probiert... :roll:

uname
Beiträge: 12046
Registriert: 03.06.2008 09:33:02

Re: C: return beendet Funktion nicht

Beitrag von uname » 23.04.2018 13:39:27

Vielleicht kannst du mal am Anfang der execute-Routine ein paar Debug-Werte ausgeben lassen. Vielleicht wird die Routine ja mehrfach ausgeführt.

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: C: return beendet Funktion nicht

Beitrag von RobertDebiannutzer » 23.04.2018 14:34:56

Danke, das war eine gute Idee!
Ich habe "printf("%d", c);" in Zeile 11 eingeschoben. Und tatsächlich werden bei allen Tasten, die mit einer Funktion belegt sind, zwei Zahlen ausgegeben, wobei die zweite immer die gleiche ist.
Jetzt muss ich also rausfinden, wie das zustande kommt.
Gut, dass ich Programme, die ich verändere, dauernd zwischendurch kompiliere und teste. Sonst würde ich am Schluss wahrscheinlich gar nicht mehr wissen, wo ich anfangen soll...

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

Re: C: return beendet Funktion nicht

Beitrag von RobertDebiannutzer » 23.04.2018 21:42:27

Kann man eigentlich mittels printf den Wert von "execfunc" ausgeben lassen?
Leider ist execfunc (logischerweise*) von folgendem Typ:

Code: Alles auswählen

typedef int (*fn_t)(int, int);
Oder wie mir gcc freundlicherweise auch mitteilte, als ich versuchte, execfunc mit printf auszulesen:

Code: Alles auswählen

but argument 2 has type ‘fn_t {aka int (*)(int,  int)}’
*Ist ja klar, schließlich steht execfunc ja für den Namen einer Funktion.

Das Blöde bei gdb ist, dass ich zwar dorthin komme, den Wert von exefunc ermitteln zu können, doch ohne Tastatur-Input ist der ja nicht von Wert.

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: C: return beendet Funktion nicht

Beitrag von Meillo » 24.04.2018 07:08:20

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
23.04.2018 21:42:27
Kann man eigentlich mittels printf den Wert von "execfunc" ausgeben lassen?
Leider ist execfunc (logischerweise*) von folgendem Typ:

Code: Alles auswählen

typedef int (*fn_t)(int, int);
Oder wie mir gcc freundlicherweise auch mitteilte, als ich versuchte, execfunc mit printf auszulesen:

Code: Alles auswählen

but argument 2 has type ‘fn_t {aka int (*)(int,  int)}’
`execfunc' ist ein Funktionszeiger, wie alle Zeiger kannst du dessen Wert, der eine Adresse im Speicher ist, mit `%p' ausgeben lassen. Was du damit anfaengst ist nochmal eine andere Frage. Wenn du mit Debugging-Symbolen kompiliert hast (-g), dann findest du externe Member mit nm(1). Und dann gibt's noch diesen Befehl, dessen Name mir gerade nicht einfaellt, der auflistet in welchen Speicherbereichen einer Executable der Code und wo die Variablen und so sind.
*Ist ja klar, schließlich steht execfunc ja für den Namen einer Funktion.
Um genau zu sein, steht es fuer die Adresse der Funktion. ;-)
Use ed once in a while!

RobertDebiannutzer
Beiträge: 385
Registriert: 16.06.2017 09:52:36

[gelöst] C: return beendet Funktion nicht

Beitrag von RobertDebiannutzer » 24.04.2018 14:29:20

Danke Meillo, aber jetzt habe ich endlich die Lösung gefunden... (*stöhn*)

Da ich wusste, dass das Problem an den Änderungen liegen muss, die ich vorgenommen habe, habe ich jetzt doch mal stur und systematisch Änderungen rückgängig gemacht und bin glücklicherweise schnell auf den Fehler gestoßen.

Das hier sind die Bösewichter:

Code: Alles auswählen

/* user function that does NOTHING */
int nullproc(int f, int n)
{
	return TRUE;
}

/* dummy function for binding to meta prefix */
int metafn(int f, int n)
{
	return TRUE;
}

/* dummy function for binding to control-x prefix */
int cex(int f, int n)
{
	return TRUE;
}
Und ihre Einträge in ebind.h:

Code: Alles auswählen

	{SPEC | 'c', metafn}
	,
	{CONTROL | ']', metafn}
	,
	{SPEC | 'i', cex}
	,
	{CONTROL | 'X', cex}
	,
	{ SPEC | META | 'C', nullproc },	/*  every command input */
	{ SPEC | META | 'R', nullproc },	/*  on file read */
	{ SPEC | META | 'X', nullproc },	/*  on window change P.K. */
Im Modellbau gibt es so ungefähr die Aussage: Fräse nichts weg, von dem Du nicht weißt, ob Du es nicht doch brauchst...
:facepalm: :facepalm:
Aber gut, woher soll ich wissen, dass ich keine Funktion löschen darf, die nichts, nichts, nichts macht!??!?
OK, ich hätte mich natürlich fragen können, warum es diese Funktionen überhaupt gibt, wenn sie scheinbar nichts machen... Die Original-Autoren haben das ja sicher nicht zum Spaß da reingeschrieben...
Naja, was draus gelernt. Jetzt muss ich nur mal überlegen, zu welchem Zweck die Autoren diese Konstruktion genau geschaffen haben...

P.S.: Die Funktion, die ich in meinem ersten Beitrag von nopaste verlinkt habe, stammt nicht aus der Datei "bind.c", sondern aus "main.c". Da hatte ich mich in der Aufregung verdusselt. Hab's noch korrigiert.

Benutzeravatar
Meillo
Moderator
Beiträge: 8782
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: [gelöst] C: return beendet Funktion nicht

Beitrag von Meillo » 24.04.2018 16:29:29

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
24.04.2018 14:29:20
Danke Meillo, aber jetzt habe ich endlich die Lösung gefunden... (*stöhn*)

Da ich wusste, dass das Problem an den Änderungen liegen muss, die ich vorgenommen habe, habe ich jetzt doch mal stur und systematisch Änderungen rückgängig gemacht und bin glücklicherweise schnell auf den Fehler gestoßen.
Wie du selber erkennst, hast auch Debuggingtechniken geuebt und Erfahrung gewonnen. Dafuer darf man sich schon mal anstrengen. ;-)

Code: Alles auswählen

/* user function that does NOTHING */
int nullproc(int f, int n)
{
	return TRUE;
}

/* dummy function for binding to meta prefix */
int metafn(int f, int n)
{
	return TRUE;
}

/* dummy function for binding to control-x prefix */
int cex(int f, int n)
{
	return TRUE;
}
Und ihre Einträge in ebind.h:

Code: Alles auswählen

	{SPEC | 'c', metafn}
	,
	{CONTROL | ']', metafn}
	,
	{SPEC | 'i', cex}
	,
	{CONTROL | 'X', cex}
	,
	{ SPEC | META | 'C', nullproc },	/*  every command input */
	{ SPEC | META | 'R', nullproc },	/*  on file read */
	{ SPEC | META | 'X', nullproc },	/*  on window change P.K. */
Im Modellbau gibt es so ungefähr die Aussage: Fräse nichts weg, von dem Du nicht weißt, ob Du es nicht doch brauchst...
:facepalm: :facepalm:
Aber gut, woher soll ich wissen, dass ich keine Funktion löschen darf, die nichts, nichts, nichts macht!??!?
Nichts zu machen und eine Funktion zu erfuellen sind zwei verschiedene Dinge. ;-)

Wenn die Funktion nicht genutzt werden wuerde, dann braeuchtest du sie auch nicht, aber scheinbar wird sie irgendwie genutzt, bloss siehst oder verstehst du nicht wie.
OK, ich hätte mich natürlich fragen können, warum es diese Funktionen überhaupt gibt, wenn sie scheinbar nichts machen... Die Original-Autoren haben das ja sicher nicht zum Spaß da reingeschrieben...
Eben! Erfreulicherweise kann man bei Suckless-Code meist davon ausgehen, dass jede Codezeile ihren Sinn hat ... was nicht bei jedem Code so der Fall ist.
Naja, was draus gelernt. Jetzt muss ich nur mal überlegen, zu welchem Zweck die Autoren diese Konstruktion genau geschaffen haben...
Und in dem Prozess wirst du wieder etwas lernen ... und immer so weiter und am Ende uebernimmst du dann hier meine Aufgabe und hilfst den Einsteigern bei ihren C-Problemen. :THX:
Use ed once in a while!

Antworten