Kein Problem... Danke fuer Deine bisherige unterstuetzung!
Gruss, heinz
Kein Problem... Danke fuer Deine bisherige unterstuetzung!
Code: Alles auswählen
B-) make heinz01
cc heinz01.c -o heinz01
heinz01.c:15:6: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'Pipe_verbinden'
heinz01.c: In function 'main':
heinz01.c:37:2: error: 'for' loop initial declarations are only allowed in C99 mode
heinz01.c:37:2: note: use option -std=c99 or -std=gnu99 to compile your code
heinz01.c: At top level:
heinz01.c:71:6: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'Pipe_verbinden'
make: *** [heinz01] Error 1
Code: Alles auswählen
~$ which c++
/usr/bin/c++
~$ file /usr/bin/c++
/usr/bin/c++: symbolic link to `/etc/alternatives/c++'
~$ file /etc/alternatives/c++
/etc/alternatives/c++: symbolic link to `/usr/bin/g++'
Ja, C++, nicht C (wo der Compiler `cc' oder `gcc' heissen wuerde). Die Sache ist die, dass dein ganzer Code ganz C-artig ist und keine C++-Features verwendet ausser `bool'. Das ist so vollkommen erlaubt, es wundert mich nur, dass du eigentlich C programmierst, das aber in einer C++-Umgebung. Ist aber nicht so wichtig.heinz hat geschrieben:01.03.2019 04:01:21Vermutlich kompilierst du mit g++, der wirft keine Fehler.
Scheint so... Damit habe ich mich nie beschaeftigt...Code: Alles auswählen
~$ which c++ /usr/bin/c++ ~$ file /usr/bin/c++ /usr/bin/c++: symbolic link to `/etc/alternatives/c++' ~$ file /etc/alternatives/c++ /etc/alternatives/c++: symbolic link to `/usr/bin/g++'
Okay. Dazu in einem separaten Post etwas.- `pipeE' und `pipeK' sind wenig hilfreiche Bezeichner,
Das ist eine der Sachen die ich nicht so richtig verstehe, weshalb ich den Pipes estmal irgendeine Bezeichnung gab um sie, fuer mich, ueberhaupt unterscheiden zu koennen...
Da musst du zuerst fork/exec verstehen. Da geht es um Grundlagenwissen von Unix. Fork dupliziert den Prozess. Es ist eine exakte Kopie, ausser dass sich die Prozess-ID unterscheidet. Beide Prozesse arbeiten im gleichen Code an der gleichen Stelle weiter. Darum macht man normalerweise direkt hinter dem fork() eine Unterscheidung nach PID, damit die zwei Prozesse dann unterschiedlichen Dinge machen.- Code hinter einem exec(3) wird nicht ausgefuehrt ... ausser wenn exec() fehlschlaegt.
Aber auch wenn, wie in diesem falle, der bc durch "quit" beendet wird. Oder auch dann nicht?
Zumindest nach den close-Befehlen sollte aber direkt ein exit kommen da hast Du recht.
Wenn man nicht weiss warum es funktioniert, dann funktioniert es vielleicht nur zufaellig richtig, in anderen Szenarien aber nicht mehr.- Warum initialisierst du mit {""} und nicht mit ""? Ist das C++-Style?
Gewohnheit. Um den genauen Grund habe ich mich, ehrlich gesagt, nie gekuemmert...
Irgendwann, nach einem "Umzug" auf ein neues System, musste ich viele meiner Programme mit diesen >{}< "nachruesten" (Fehlermeldung: missing braces)
um sie wieder lauffaehig zu bekommen.
Seitdem mache ich es immer so...
Das klingt fuer Dich jetzt sicher fuerchterlich und stuemperhaft aber die wirklichen Unterschiede zwischen C und C++ kenne ich eigentlich kaum...
Ich verwende was funktioniert.
Code: Alles auswählen
char buf[4] = {'f', 'o', 'o', '\0'};
Code: Alles auswählen
char buf[4] = "foo";
Code: Alles auswählen
char buf[4] = {{'f', 'o', 'o', '\0'}};
Kein Problem. Ich kann dein Verhalten natuerlich schon verstehen. Das ist dann halt der Unterschied zwischen Programmierern die verstehen was sie tun und welchen, die irgendwie etwas produzieren das meistens vermutlich das tut was es soll. Das ist ein Qualitaetsunterschied. Ich will damit aber keinesfall sagen, dass du nicht so programmieren solltest wie du es tust, weil auch du nutzt Computer zu deinem Vorteil. Bloss Atomkraftwerksteuerungen und Fahrerassistenzsysteme und OpenSSL und alles wo personenbezogene Daten verarbeitet werden sollte man nicht auf diese Weise programmieren.Wenn beim Compilieren mit -Wall nichts "auftaucht", der Code ueber laengere Zeit tut was er soll und keine Fehler oder Abstuerze produziert ist er fuer mich OK.
Ich hoffe Du hilfst mir trotzdem noch ein wenig...
Verstehen ist das Entscheidende! Du musst sicherstellen, dass Strings terminiert sind. Dazu brauchst du Platz fuer ein Null-Byte und dieses muss eingefuegt werden ... auch welche Weise auch immer. Das zu pruefen und sicherzustellen ist in C deine Aufgabe als Programmierer. In C muss man bei jeder String-Operation an die Terminierung denken und sie pruefen.- Du darfst keine 32 Bytes lesen, sondern nur eines weniger, damit du den String null-terminieren kannst. Ausserdem solltest du keine solche Magic-Number verwenden sondern lieber ``sizeof(buf
Laenge minus 1. Werde ich beherzigen.
Allerdings habe ich etwas schlechte Erfahrung damit gemacht ein sizeof auf ein, an eine Funktion uebergebenes, Array anzuwenden...
(Irgendwie habe ich die moeglicherweise dumme Angewohnheit, solche "Dinge" dann immer zu vermeiden...)
Oder du duplizierst stdout auf stderr bevor du den exec() auf `bc' machst. Dann bekommst du stderr-Ausgaben auch auf stdout zum lesen. Alles was in der Shell geht kannst du natuerlich auch in C machen. (Grundsaetzlch kannst du alles was du ueberhaupt mit Unix machen kannst, auf Systemcall-Ebene machen, weil das das einzige Interface zum Kernel ist.)- read(2) und write(2) koennen fehlschlagen. Da fehlt die Fehlerbehandlung. (Das meinte ich mit dem vielen Overhead, wenn man so low-level programmiert.)
Da sprichst Du etwas interessantes an.
Wenn die Formel naemlich einen syntaktischen Fehler enthaelt, gibt bc nichts zurueck und der read wartet endlos auf die rueckgabe des Ergebnisses.
Wie ich gelesen habe (man read), scheint >timerfd_create< da der richtige "Angriffspunkt" fuer zu sein. Sieht nach der naechsten "Baustelle" aus...
Gibt es vlt. noch eine andere Moeglichkeit einen solchen Fehler abzufangen?
Eine weitere Pipe fuer stderr vielleicht?
Siehe hierzu diesen Thread: viewtopic.php?p=1182218#p1182218- Statt read(2) und write(2) kannst du aber auch printf(3) und fgets(3) verwenden.
Danke fuer den Hinweis. Einen Vorteil oder eine Vereinfachung kann ich darin allerdings nicht erkennen...
Statt mit dem Holzhammer solltest du besser genau das richtige machen, naemlich nur genau das Zeichen hinter dem letzten gelesenen auf '\0' setzen. Dabei wird dir dann vielleicht auch bewusst, dass du noch ein Zeichen Platz in deinem Puffer brauchst und darum ein Zeichen weniger lesen darfst als der Puffer gross ist.- Das memset(3) brauchst du nicht, wenn du dafuer sorgst, dass dein String terminiert ist.
Ich dachte halt, durch einen memset mit 0, koennte ich "egal was" in den String "kippen" und er waere immer null-terminiert...
Du machst:- dup2(2) schliesst den Ziel-FD automatisch. Das close(2) davor ist also unnoetig.
In >man dup< habe ich folgendes gelesen:
dup2() makes newfd be the copy of oldfd, closing newfd first if necessary...
aber vlt. falsch verstanden. (Mein Englisch ist nicht so toll...)
Du hast aber recht, ohne diese Zeilen laeuft der Code genauso...
Code: Alles auswählen
close(newfd);
dup2(oldfd, newfd);
Der Code, wie er jetzt ist, ist nur zum Testen der Funktion von pipes und exec. Wenn er funktioniert werde ich ihn in das Haupt-Projekt uebernehmen in dem ich anscheinend Code aus C und C++ mische...Die Sache ist die, dass dein ganzer Code ganz C-artig ist und keine C++-Features verwendet ausser `bool'. Das ist so vollkommen erlaubt, es wundert mich nur, dass du eigentlich C programmierst, das aber in einer C++-Umgebung.
Alles klar, jetzt habe ich es verstanden.Exec() ersetzt das Prozessimage. D.h. der Programmcode des Prozesses wird ersetzt/ueberschrieben. Der Prozess fuehrt dann nicht mehr dein Programm aus sondern in deinem Fall dann bc(1). Von deinem Programm ist in dem Prozess dann nichts mehr uebrig.
Es gibt dann keinen Code von dir mehr, der in dem Prozess noch ausgefuehrt werden koennte, der ist komplett ersetzt. Exec() ist wie exit(), bloss dass sich der Prozess nicht beendet sondern ein anderes Programm startet.
Da hast Du sicher recht...Wenn man nicht weiss warum es funktioniert, dann funktioniert es vielleicht nur zufaellig richtig, in anderen Szenarien aber nicht mehr.
Bei einzelnen Arrays bringt das natuerlich nichts aber bei komplexeren Strukturen ist es m.M.n. viel uebersichtlicher und vermeidet auch Fehler...Wenn man darum geschweifte Klammern macht, entspricht das ja:
char buf[4] = {{'f', 'o', 'o', '\0'}};
Was das bringen soll, verstehe ich nicht.
Ich hab mal in meinen aelteren Programmen etwas rumgesucht und wie es aussieht hast Du hier auch recht.Vielleicht haengt das mit diesem Phaenomen zusammen, ueber das ich mal gestoplert bin: http://marmaro.de/lue/txt/2015-11-06.txt
Code: Alles auswählen
struct dateN
{
char name[256];
int alter;
int telefon_nr[2];
};
dateN daten[2]={
{{"Fred"},44,{12345,67890}},
{{"Egon"},55,{12345,67890}}.
};
Code: Alles auswählen
char t[2][32]="hallo","test";
*lach* Keine Angst, ich habe nicht vor meinen Grusel-Code auf die Menschheit loszulassen...Kein Problem. Ich kann dein Verhalten natuerlich schon verstehen. Das ist dann halt der Unterschied zwischen Programmierern die verstehen was sie tun und welchen, die irgendwie etwas produzieren das meistens vermutlich das tut was es soll.
Das ist ein Qualitaetsunterschied. Ich will damit aber keinesfall sagen, dass du nicht so programmieren solltest wie du es tust, weil auch du nutzt Computer zu deinem Vorteil.
Bloss Atomkraftwerksteuerungen und Fahrerassistenzsysteme und OpenSSL und alles wo personenbezogene Daten verarbeitet werden sollte man nicht auf diese Weise programmieren.
Danke fuer die klaren Worte. Ich werde versuchen in Zukunft da etwas genauer hin zu sehen.Verstehen ist das Entscheidende! Du musst sicherstellen, dass Strings terminiert sind. Dazu brauchst du Platz fuer ein Null-Byte und dieses muss eingefuegt werden ... auch welche Weise auch immer.
Das zu pruefen und sicherzustellen ist in C deine Aufgabe als Programmierer. In C muss man bei jeder String-Operation an die Terminierung denken und sie pruefen.
OK. Werde daran denken es in Zukunft zu vermeiden...Nichts desto trotz sollte man Magic Numbers (also direkt hingeschriebene Zahlen im Code) vermeiden.
So habe ich es nach meinen "schlechten Erfahrungen" dann auch realisiert...Verwende `sizeof' und reiche den Wert falls noetig an die Funktionen weiter.
Das ist eine sehr gute Idee!Oder du duplizierst stdout auf stderr bevor du den exec() auf `bc' machst. Dann bekommst du stderr-Ausgaben auch auf stdout zum lesen.
Code: Alles auswählen
dup2(pipesK[PIPE_SCHREIBEN],PIPE_SCHREIBEN);
dup2(PIPE_SCHREIBEN,2);
Diesen Thread habe ich damals auch schon etwas verfolgt und er ist auch bei meiner Problem-Suche des oefteren aufgetaucht.-- Statt read(2) und write(2) kannst du aber auch printf(3) und fgets(3) verwenden.
-- Danke fuer den Hinweis. Einen Vorteil oder eine Vereinfachung kann ich darin allerdings nicht erkennen...
Siehe hierzu diesen Thread: viewtopic.php?p=1182218#p1182218
Da hast Du natuerlich recht.Statt mit dem Holzhammer solltest du besser genau das richtige machen, naemlich nur genau das Zeichen hinter dem letzten gelesenen auf '\0' setzen.
Dabei wird dir dann vielleicht auch bewusst, dass du noch ein Zeichen Platz in deinem Puffer brauchst und darum ein Zeichen weniger lesen darfst als der Puffer gross ist.
Wenn du deinen Puffer schoen ausnullst und dann soviele Zeichen reinschreibst wie der Puffer gross ist, dann ist der dort enthaltene String ja doch nicht null-terminiert.
So viel zu meinen "tollen" Englischkenntnissen...Die Manpage schreibst, dass dup2() dieses close(newfd) automatisch macht.
Bei C++ wuerde ich halt Objektorientierung erwarten und cout (oder wie das heisst) statt printf(). Aber natuerlich kann man in C++ auf das gesamte Subset von C zugreifen. Ehrlich gesagt habe ich keine Ahnung was in C++-Projekten ueblich ist. Ich selber programmiere nur C.heinz hat geschrieben:01.03.2019 21:06:18Der Code, wie er jetzt ist, ist nur zum Testen der Funktion von pipes und exec. Wenn er funktioniert werde ich ihn in das Haupt-Projekt uebernehmen in dem ich anscheinend Code aus C und C++ mische...Die Sache ist die, dass dein ganzer Code ganz C-artig ist und keine C++-Features verwendet ausser `bool'. Das ist so vollkommen erlaubt, es wundert mich nur, dass du eigentlich C programmierst, das aber in einer C++-Umgebung.
Ist nicht noetig, man hat ja int.Ich bin aber schon etwas ueberrascht, dass C kein bool kennt...
Ich wuerde hinter das exec() eine Fehlerausgabe mit fprintf() machen und dahinter ein exit() wie du vorgeschlagen hast.Alles klar, jetzt habe ich es verstanden.Exec() ersetzt das Prozessimage. D.h. der Programmcode des Prozesses wird ersetzt/ueberschrieben. Der Prozess fuehrt dann nicht mehr dein Programm aus sondern in deinem Fall dann bc(1). Von deinem Programm ist in dem Prozess dann nichts mehr uebrig.
Es gibt dann keinen Code von dir mehr, der in dem Prozess noch ausgefuehrt werden koennte, der ist komplett ersetzt. Exec() ist wie exit(), bloss dass sich der Prozess nicht beendet sondern ein anderes Programm startet.
Also sollte man hinter exec max. einen "speziellen" exit-Befehl setzen ( z.B. exit(255); ) an dem man erkennen kann, das exec gescheitert ist.
Ja genau. Den bekommst du bei dem wait() zurueck.Ich gehe davon aus das der Kind-Prozess nach dem beenden den exitcode von bc zurueck gibt. Stimmt das?
Kannst du erklaeren warum? Das wuerde mich interessieren.Bei einzelnen Arrays bringt das natuerlich nichts aber bei komplexeren Strukturen ist es m.M.n. viel uebersichtlicher und vermeidet auch Fehler...Wenn man darum geschweifte Klammern macht, entspricht das ja:
char buf[4] = {{'f', 'o', 'o', '\0'}};
Was das bringen soll, verstehe ich nicht.
Gutes Beispiel!Ich hab mal in meinen aelteren Programmen etwas rumgesucht und wie es aussieht hast Du hier auch recht.Vielleicht haengt das mit diesem Phaenomen zusammen, ueber das ich mal gestoplert bin: http://marmaro.de/lue/txt/2015-11-06.txt
Das waren konstruktionen wie sowas, wo der Compiler dann beim Initialisieren gemeckert hat wenn man nicht alle { } gesetzt hat:Code: Alles auswählen
struct dateN { char name[256]; int alter; int telefon_nr[2]; }; dateN daten[2]={ {{"Fred"},44,{12345,67890}}, {{"Egon"},55,{12345,67890}}. };
Zurecht. Das ist hier auf der rechten Seite naemlich ein Komma-Operator und keine zwei Elemente in einer Array-Initialisierung.Auch sowas mag er nicht:Code: Alles auswählen
char t[2][32]="hallo","test";
Mit 2 statt 3 (stderr ist 2):Das ist eine sehr gute Idee!Oder du duplizierst stdout auf stderr bevor du den exec() auf `bc' machst. Dann bekommst du stderr-Ausgaben auch auf stdout zum lesen.
Als Ergebnis kommt dann naemlich >(standard_in) 1: syntax error<. Das laesst sich sehr gut erkennen.
Wuerde das dann so aussehen?Code: Alles auswählen
dup2(pipesK[PIPE_SCHREIBEN],PIPE_SCHREIBEN); dup2(PIPE_SCHREIBEN,3);
Code: Alles auswählen
dup2(pipesK[PIPE_SCHREIBEN],PIPE_SCHREIBEN);
dup2(PIPE_SCHREIBEN,2);
Nichtverstehens der Vorteile?Diesen Thread habe ich damals auch schon etwas verfolgt und er ist auch bei meiner Problem-Suche des oefteren aufgetaucht.-- Statt read(2) und write(2) kannst du aber auch printf(3) und fgets(3) verwenden.
-- Danke fuer den Hinweis. Einen Vorteil oder eine Vereinfachung kann ich darin allerdings nicht erkennen...
Siehe hierzu diesen Thread: viewtopic.php?p=1182218#p1182218
Nach einigen Seiten des "nicht Verstehens" hatte ich allerdings aufgegeben... Werde es aber nochmal versuchen.
Darum geht es! Niemand schreibt perfekten Code. Jeder kann besser werden. Wichtig ist, dass man besser werden will! Es ist viel besser wenn dir bewusst ist, dass du keinen perfekten Code schreibst. Es gibt genug Programmierer, die schreiben auch keinen perfekten Code, meinen aber, dass sie es wuerden.Ich weiss, dass ich nicht der Super-Coder bin aber ich versuche besser zu werden.
Das hoert sich voll gut an! Ich habe noch nie Grafik- und Sound-Zeugs gemacht. Da bist du mir voraus.Das Programmieren habe ich mir halt selbst beigebracht. So nach dem Motto "Lernen durch tun".
Angefangen mit C habe ich so um 1994. Als Gelegenheits-Coder, damals noch komplett ohne Englischkenntnisse mit "Langenscheidts Taschenwoerterbuch Deutsch/Englisch".
Jetzt, nach etlichen Speicherzugriffsfehlern und sonstigen rueckschlaegen, kann ich mittlerweile schon (fuer meine Verhaeltnisse) groessere Projekte sogar mit Grafik und Sound (SDL) realisieren die auch problemlos laufen.
Keine Sorge. Das Gefuehl zu haben, dass meine Muehe dir hilft, ist Motivation und Dank genug fuer mich. Ich finde es auch nett, dass du mir Gelegenheiten bietest, mich mit C zu beschaeftigen. Ich tue das in letzter Zeit viel zu selten.Ich bin sehr Dankbar hier ein Forum mit netten Leuten gefunden zu haben die mir immer wieder helfen und mir, wie Du hier, sehr hilfreiche Tipps und Unterstuetzug geben...
Bitte nicht falsch verstehen, ich moechte mich hier nicht "einschleimen" aber ich weiss nicht wie ich Dir dafuer Danken kann, dass Du Dir so viel Zeit nimmst mir zu helfen...
Naja, Objekte nutze ich ja auch.Bei C++ wuerde ich halt Objektorientierung erwarten und cout (oder wie das heisst) statt printf().
Da hast Du natuerlich recht.--Ich bin aber schon etwas ueberrascht, dass C kein bool kennt...
Ist nicht noetig, man hat ja int.
Falls man meint, einen Boolean-Typ zu brauchen, kann man ihn sich mit enum und typedef selber definieren.
Guter Vorschlag! Umgesetzt.--Also sollte man hinter exec max. einen "speziellen" exit-Befehl setzen ( z.B. exit(255); ) an dem man erkennen kann, das exec gescheitert ist.
Ich wuerde hinter das exec() eine Fehlerausgabe mit fprintf() machen und dahinter ein exit() wie du vorgeschlagen hast.
Danke fuer den Tipp!--Ich gehe davon aus das der Kind-Prozess nach dem beenden den exitcode von bc zurueck gibt. Stimmt das?
Ja genau. Den bekommst du bei dem wait() zurueck.
Stimmt, die Klammern um die Strings sind nutzlos. Ist so auch besser lesbar.Gutes Beispiel!Code: Alles auswählen
struct dateN { char name[256]; int alter; int telefon_nr[2]; }; dateN daten[2]={ {"Fred",44,{12345,67890}}, {"Egon",55,{12345,67890}} };
Nur die Klammern um die Strings sollten IMO weg. Alle anderen Klammern in diesem Beispiel sind notwendig.
Hab es noch selbst gemerkt und korrigiert aber Du warst zu schnell...--dup2(pipesK[PIPE_SCHREIBEN],PIPE_SCHREIBEN);
--dup2(PIPE_SCHREIBEN,3);
Mit 2 statt 3 (stderr ist 2):
Habe ich gemacht und es funktioniert so auch sehr gut.Du solltest das aber testen, ich hab's nicht getan. Bei diesen Duplizierungsgeschichten muss ich mich immer erst 'ne Weile eindenken. Bin mir gerade nicht ganz sicher, aber teste es einfach.
Das klingt einleuchtend.Statt read(2) und write(2) kannst du aber auch printf(3) und fgets(3) verwenden.
Nichtverstehens der Vorteile?
Wenn du write(2) verwendest, dann liefert das die Anzahl der geschiebenen Bytes zurueck. Wenn du 10 Bytes schreiben willst, kann es sein, dass write() 6 zurueckliefert und du die restlichen 4 Bytes in einem zweiten Aufruf noch schreiben musst.
Wenn du printf(3) verwendest, musst du dich darum nicht kuemmern, weil sich printf(3) bei seinem internen Aufrauf von write(2) um diese Dinge kuemmert.
Naja, um es vollstaendig machen zu koennen, muss man die ganzen "Fallsticke" ja erstmal kennen...Auf Systemcall-Ebene ist es nur dann einfach und uebersichtlich, wenn man die Details ignoriert. Wenn man es exakt und vollstaendig machen will, hat man schnell 70% Fehlerbehandung.
Ich denke, ich bin jetzt alt genug um meine Faehigkeiten (wobei auch immer) nicht mehr so einfach zu ueberschaetzen...Darum geht es! Niemand schreibt perfekten Code. Jeder kann besser werden. Wichtig ist, dass man besser werden will! Es ist viel besser wenn dir bewusst ist, dass du keinen perfekten Code schreibst.
Es gibt genug Programmierer, die schreiben auch keinen perfekten Code, meinen aber, dass sie es wuerden.
Danke fuer die Blumen aber ich bin mir sicher Du koenntest mich darin binnen kuerzester Zeit weit ueberholen.--Das Programmieren habe ich mir halt selbst beigebracht.
Das hoert sich voll gut an! Ich habe noch nie Grafik- und Sound-Zeugs gemacht. Da bist du mir voraus.
Vielen Dank fuer die netten Worte!Keine Sorge. Das Gefuehl zu haben, dass meine Muehe dir hilft, ist Motivation und Dank genug fuer mich. Ich finde es auch nett, dass du mir Gelegenheiten bietest, mich mit C zu beschaeftigen. Ich tue das in letzter Zeit viel zu selten.
Absolut kein Problem. Ich wuensche Dir ein erholsames Wochenende.Zu den Pipes schreibe ich dir gerne auch noch, bloss nicht mehr heute. War ein langer Tag ...