Socket-Programmierung (fast Anfänger)
Hallo, habe zwar schon einiges programmiert, doch lbis jetzt noch nicht in Sachen Netztwerk. Habe einige Tutorials im INet gelesen und konnte dabei auch gut folgen. Jetzt meine Frage: Wenn ich einen Server und einen Client programmiere also: Server: socket, bind, listen, accept Client: socket, connect bekomme ich immer eine Fehlermeldung beim "connecten" des clients. Ist es möglich ,dass ich auch nur mit einem Rechner einen Server und einen Client programmiere und dann connecten lasse? Muss ich dann bei beiden den selben Port einstellen? DIe IP natürlich ja, oder? Welche Ports verwende ich am besten? Danke für die Hilfe Holger -- Holger Macht - 91247 Vorra-Artelshofen mailto:holger.macht@web.de - http://www.sgt-hulder.de Homepage: Tabulaturarchiv, Vokabelprogramm, Tools
On Thu, 6 Feb 2003, Holger Macht wrote:
Hallo, habe zwar schon einiges programmiert, doch lbis jetzt noch nicht in Sachen Netztwerk. Habe einige Tutorials im INet gelesen und konnte dabei auch gut folgen. Jetzt meine Frage: Wenn ich einen Server und einen Client programmiere also:
Server: socket, bind, listen, accept Client: socket, connect
bekomme ich immer eine Fehlermeldung beim "connecten" des clients. Ist es möglich ,dass ich auch nur mit einem Rechner einen Server und einen Client programmiere und dann connecten lasse?
Ja.
Muss ich dann bei beiden den selben Port einstellen?
Ja.
DIe IP natürlich ja, oder?
Auch ja.
Welche Ports verwende ich am besten?
Fuer private Sachen die von 49152 bis 65535. Siehe /etc/services. ciao Arvin -- Dipl.-Phys. Arvin Schnell Research & Development email: arvin@suse.de
Hi, On Thu, 6 Feb 2003, Arvin Schnell wrote:
Server: socket, bind, listen, accept Client: socket, connect
Muss ich dann bei beiden den selben Port einstellen?
Ja.
Holger, hoere nicht auf Arvin, er ist verwirrt. Der Endpunkt einer TCP oder UDP Verbindung definiert sich _vollstaendig_ durch IP und Port. Ausserdem haben Endpunkte eindeutig zu sein. Wenn du also einen Rechner zum Testen von Server und Client benutzt (mithin also die IP schonmal gleich ist), muessen beide Endpunkte _unterschiedliche_ Ports haben. Allerdings: Der Port des Clients (also der Source-Port) wird automatisch alloziert, wenn du nichts weiter angibts, braucht dich also nicht weiter zu kuemmern. Was du natuerlich im Client angeben musst, ist die Zieladdresse deiner gewuenschten Verbindung, und die ist eben die IP:Port wo dein Server drauf horcht. Wenn dein Server also sowas macht, wie: socket() ... my_addr.sin_port = htons (portnumber); bind ( ..., &my_addr, ...) listen() ... Dann horcht er offenbar auf Port 'portnumber' (die IP wurde oben nicht festgelegt, er horcht also auf allen Interfaces). Der Client muss als Zieladdresse also diese ebenfalls angeben: socket() ... dest_addr.sin_port = htons (portnumber); inet_aton ("a.b.c.d", &dest_addr.sin_addr); connect (..., &dest_addr, ...) Dabei ist "a.b.c.d" also die IP des Servers, in dem Beispiel des lokalen Rechners also 127.0.0.1, oder jede andere Addresse irgendeines lokalen Netzwerk-Interfaces. Wie ersichtlich wird oben keine Addresse des lokalen Endpoints (also der Source) angegeben, sondern nur die der Destination. Das System wird sich also irgendeine freie aussuchen, die es tut (d.h. IP und Port des lokalen Endpoints werden vom System gewaehlt). Man beachte zusaetzlich, das Server nur auf Ports < 1024 horchen koennen, wenn sie als Root gestartet sind (oder die entsprechende Capability haben, aber das fuehrt zu weit). Du willst dir also einen Port > 49152 aussuchen. Ausserdem empfehle ich eine gruendliche Fehlerbehandlung, mit der kommt man trivialen Fehlern relativ schnell auf die Schliche. Also ala: int fd; if ((fd = socket (...)) < 0) { perror ("socket()"); return -1; } if (connect (fd, &dest_addr, ...) < 0) { perror ("connect()"); return -1; } Siehe auch die manpages (die man sich wirklich mal zu Gemuete fuehren sollte, da sie noch einiges mehr erklaeren) von ip(7), socket(2), connect(2), bind(2) und perror(3). Ciao, Micha.
Hallo, On Thu, 06 Feb 2003, Michael Matz wrote:
On Thu, 6 Feb 2003, Arvin Schnell wrote: [..] Holger, hoere nicht auf Arvin, er ist verwirrt. [..] Man beachte zusaetzlich, das Server nur auf Ports < 1024 horchen koennen,
"Holger, hoere nicht auf Michael, er ist verwirrt." *SCNR* Nein, abgesehen davon war alles wohl richtig (hab den Code jetzt nicht genau gelesen)... Natuerlich koennen auch Server, die von root gestartet werden auf Ports >= 1024 lauschen (_muessen_ aber nicht!). Es gibt ja auch einige gute Beispiele, z.B. IRC, Swat, webmin, u.a... Richtig ist: nur root-Prozesse duerfen Ports < 1024 verwenden (ohne groessere Verrenkungen). Das sind eben die "privileged" ports. Ob das jew. ein Server oder Client ist, ist dabei egal(!). Kurz: User-Prozesse duerfen nur Ports >= 1024, root-Prozesse alle Ports verwenden (das bezieht sich auf die "lokalen" Ports, vom jew. Prozess aus gesehen!). -dnh --
Yes, my brother monks, that explains the waterglass of vodka beside the keyboard tonight. Waterglass? Waterglass? You're obviously not suffering enough. Call us when you've got a whole distillery beside the keyboard. -- J.D. Weiner and S. Lamble in the Monastery
* Am Fre, 07 Feb 2003 schrieb David Haller:
On Thu, 06 Feb 2003, Michael Matz wrote:
On Thu, 6 Feb 2003, Arvin Schnell wrote: [..] Holger, hoere nicht auf Arvin, er ist verwirrt. [..] Man beachte zusaetzlich, das Server nur auf Ports < 1024 horchen koennen,
"Holger, hoere nicht auf Michael, er ist verwirrt." *SCNR*
Nein, abgesehen davon war alles wohl richtig (hab den Code jetzt nicht genau gelesen)...
Natuerlich koennen auch Server, die von root gestartet werden auf Ports >= 1024 lauschen (_muessen_ aber nicht!). Es gibt ja auch einige gute Beispiele, z.B. IRC, Swat, webmin, u.a...
Richtig ist: nur root-Prozesse duerfen Ports < 1024 verwenden (ohne groessere Verrenkungen). Das sind eben die "privileged" ports.
Genau das hat er doch geschrieben (man rafft es erst beim zweiten Lesen, das ging mir auch so). Gruß Christoph -- Christoph Maurer - 52072 Aachen - Tux#194235 mailto:christoph-maurer@gmx.de - http://www.christophmaurer.de Auf der Homepage u.a.: Installation von SuSE 7.0 auf Notebook Acer Travelmate 508 T, Elektrotechnik an der RWTH Aachen
Hi, On Fri, 7 Feb 2003, David Haller wrote:
[..]
Holger, hoere nicht auf Arvin, er ist verwirrt. [..] Man beachte zusaetzlich, das Server nur auf Ports < 1024 horchen koennen,
"Holger, hoere nicht auf Michael, er ist verwirrt." *SCNR*
Hah. Und das mir. ;-)))
Natuerlich koennen auch Server, die von root gestartet werden auf Ports >= 1024 lauschen (_muessen_ aber nicht!).
Nun, ich schrieb exakt diese Worte: "Man beachte zusaetzlich, das Server nur auf Ports < 1024 horchen koennen, wenn sie als Root gestartet sind (oder die entsprechende Capability haben, aber das fuehrt zu weit)." S kann nur P, wenn R. (S==server, P==port<1024, R==root-gestartet). Leider gibt es tatsache zwei Interpretationen des obigen Satzen, und zwar: wenn R --> S kann nur P welches aequivalent ist zu: wenn R --> S kann nichts anderes als P und nicht R --> S kann nicht P Das Wort "nur" ist also zweideutig. Liegt halt daran, das deutsch als natuerliche Sprache keine exakte Logik (Aussagenlogik oder eine beliebige andere hoehere Logik) implementiert. Ich meinte natuerlich die zweite Bedeutung. Ich werde aber trotz der Verwirrung auch in Zukunft davon absehen, ausschliesslich in Saetzen mathemetischer Logik zu sprechen. Das ist muehevoll und nicht unbedingt verstaendlicher ;-) Ciao, Micha.
Hallo, On Fri, 07 Feb 2003, Michael Matz wrote:
On Fri, 7 Feb 2003, David Haller wrote:
[..]
Holger, hoere nicht auf Arvin, er ist verwirrt. [..] Man beachte zusaetzlich, das Server nur auf Ports < 1024 horchen koennen,
"Holger, hoere nicht auf Michael, er ist verwirrt." *SCNR*
Hah. Und das mir. ;-)))
Tja. So kann's gehen ;)
Natuerlich koennen auch Server, die von root gestartet werden auf Ports >= 1024 lauschen (_muessen_ aber nicht!).
Nun, ich schrieb exakt diese Worte: "Man beachte zusaetzlich, das Server nur auf Ports < 1024 horchen koennen, wenn sie als Root gestartet sind (oder die entsprechende Capability haben, aber das fuehrt zu weit)."
ISC! *schaem*
Ich weiss jetzt auch nicht mehr, wieso ich da ein "Server, die
von root gestartet werden, koennen nur auf Ports < 1024 laufen"
hineingelesen habe... Naja, war auch schon etwas muede...
Naja, ich denke, zusammen haben wir alle Klarheiten beseitigt ;)
-dnh
PS: ist hier eigentlich grauslicher Code aus irgendwelcher SW OnTopic?
<minirant>
Hab heute mal versucht gift-0.1.9 zu kompilieren... *aua* u.a.:
ostream& operator<<(ostream& o, someclass& c) { o << c.foo << endl; }
(mehrfach)... Oder das hier:
====
string itoa (int val,int length) {
char *car = new char[length+1];
for(int i=0; i
Hi, On Fri, 7 Feb 2003, David Haller wrote:
Naja, ich denke, zusammen haben wir alle Klarheiten beseitigt ;)
Recht so. ;)
PS: ist hier eigentlich grauslicher Code aus irgendwelcher SW OnTopic?
Klar. Zumindest ich lache gern ;)
ostream& operator<<(ostream& o, someclass& c) { o << c.foo << endl; }
Ui. Da fehlt mindestens das "return o". Hmm, ansonsten ist es aber ok (jedenfalls, wenn someclass::foo irgendwas zurueckgibt oder ist, was man in einen ostream werfen kann).
string itoa (int val,int length) { char *car = new char[length+1]; for(int i=0; i
Mich schaudert. mem-leak, unnoetige 0-Setzung, grauenvolle sprintf() Verwendung. Und dieser cast... Ugh.
Was glaube ich weiss sogar, was das '%*2$d' sein soll... Was sagt ein gcc/g++ 3.x dazu?
Eigentlich nichts, nur ne Warnung ueber das "*2$" Konstrukt, die aber falsch ist.
char c[length+1];
Aber Vorsicht. Diese variable-sized-arrays sind nicht ISO-C++.
snprintf(c, length, "%i", val); return string(c);
==== inline CInitializedDouble operator=(const CInitializedDouble& in) {mDouble=(in.mDouble);}; };
Sieht aus, wie irgendwie automatisch erzeugter code. Wer wuerde denn sonst "{a=b;};" schreiben, anstatt "a=b;". Ciao, Micha.
Hallo, On Sat, 08 Feb 2003, Michael Matz wrote:
On Fri, 7 Feb 2003, David Haller wrote:
Naja, ich denke, zusammen haben wir alle Klarheiten beseitigt ;)
Recht so. ;)
*g*
PS: ist hier eigentlich grauslicher Code aus irgendwelcher SW OnTopic?
Klar. Zumindest ich lache gern ;)
ostream& operator<<(ostream& o, someclass& c) { o << c.foo << endl; }
Ui. Da fehlt mindestens das "return o".
Bingo.
string itoa (int val,int length) { char *car = new char[length+1]; for(int i=0; i
Mich schaudert. mem-leak, unnoetige 0-Setzung,
und v.a. so effizient, nicht?
grauenvolle sprintf() Verwendung. Und dieser cast... Ugh.
Was glaube ich weiss sogar, was das '%*2$d' sein soll... Was sagt ein gcc/g++ 3.x dazu?
Eigentlich nichts, nur ne Warnung ueber das "*2$" Konstrukt, die aber falsch ist.
Ist das '*2$' denn "legal"? Ich verstehe das so, dass dort "length" als Laengen-format ins "%0...d" eingebaut werden soll. Und zumindest mein gcc-2.95.2 + pgcc-2.95.3-patch + pgcc-2.95.3-athlon-patch faengt damit nix an ("invalid format specifier" oder so)... Und der Compiler hat sich bei mir IMO bewaehrt. U.a. hab ich meine Kernels seit ca. 2 Jahren damit kompiliert -- und die laufen "rock-stable"[1]... Ich hatte nicht einen kernelbedingten Haenger.
char c[length+1];
Aber Vorsicht. Diese variable-sized-arrays sind nicht ISO-C++.
Oh. Hm. Waere 'char * c = xmalloc(..); string s = string(c); free(c); return s;' besser/ok? Bin mir grad nicht sicher, ob das klappt (und zu muede um das noch testen zu wollen bzw. ich kenne C++ zu wenig um das verhalten des 'string s = string(c)' genau zu wissen)...
snprintf(c, length, "%i", val); return string(c);
Aber abgesehen davon scheint dieser "Quickhack" ja immerhin besser als das Original zu sein ;-) Naja, die Funktion wird nur an einer anderen Stelle deklariert (statt einen Header einzubinden!), aber nicht verwendet... Das hab ich aber erst rausgefunden, nachdem ich obiges schon hatte ;) Gedacht sind meine Aenderungen eh nur "fuer mich", mir reicht's also, wenn mein gcc das schluckt ;) Ich selbst wuerde einen int2string in C++ sowieso anders machen (hab ich auch schonmal[3] ;), wohl via str(ing)stream... Oder direkt in C nach K&R, was ich eh schon als "itoa.c" rumliegen habe. Fuer C++ waere das dann 'return string(itoa(i));' :)
==== inline CInitializedDouble operator=(const CInitializedDouble& in) {mDouble=(in.mDouble);}; };
Sieht aus, wie irgendwie automatisch erzeugter code.
Kann sein.
Wer wuerde denn sonst "{a=b;};" schreiben, anstatt "a=b;".
Ups, das war ein C&P Fehler von mir. Das zweite '};' ist das von 'class { };'. An der Stelle ist das {}; zwingend. Das ist aus nem Headerfile: ==== class CInitializedDouble{ /* ... */ inline CInitializedDouble operator=(const CInitializedDouble& in) {mDouble=(in.mDouble);} }; ==== Worauf ich hinauswollte, bzw. wo ich den Fehler sehe, ist dass es wiederum kein return gibt (was g++ auch bemaengelt). Mein Fix ist ein ==== inline CInitializedDouble& operator=(const CInitializedDouble& in) {mDouble=(in.mDouble); return *this;}; ==== Aber die ganze Klasse ist eh Schwachfug: ==== /** A class of doubles which are initialized with a zero (unnecessary, it seems) */ ==== Tja. Wenn man seine doubles (Variablen allgemein) generell initialisieren wuerde, dann braeuchte man so eine Murks erst gar nicht... Schlamperei/Faulheit durch Murks ausbessern... "Interessant"... Wie erwaehnt, der Code ist, aehm, abenteuerlich (und ein paar Fehler kamen mir recht bekannt vor, von '0.1.6pre3'[2])... Mich wundert, dass das Teil ueberhaupt zu laufen scheint, die muessen da mit sehr toleranten Compilern (und ohne jede Warning-Optionen) arbeiten... Ah, meine Version von vorhin laeuft noch nicht -- muss mal den Perl-Einbau weglassen: ==== libGIFTAcInvertedFile.so contains a sane GIFT Accessor plugin: inverted_file /opt/GIFT-0.1.9/lib/libGIFTAcPerl.so.0: undefined symbol: libGIFTAcPerl_getClassName Could not open library: /opt/GIFT-0.1.9/lib/libGIFTAcDistanceMatrix.so: undefined symbol: __ti10CAcURL2FTS Aborted (core dumped) ==== *hrumpf* Da fehlt wohl ein -llibAcURL2FTS irgendwo... Wer sich's (auch) antun moechte: ftp://ftp.gnu.org/gnu/gift/gift-0.1.9.tar.gz http://www.mrml.net http://viper.unige.ch/demo/php/demo.php Apropos: "MRML", der XML-Dialekt der von GIFT verwendet wird, ist IMO auch "interessant"... ==== <algorithm algorithm-id="sub4" algorithm-type="sub4" algorithm-name="sub4" cui-block-color-histogram="yes" cui-block-color-blocks="yes" cui-block-texture-histogram="yes" cui-base-type="inverted_file" /> ==== Achso, warum die ganze Muehe? Naja, GIFT versucht u.a. Bilder anhand von Aehnlichkeiten zu finden... Klasse Idee eigentlich (und wurde in der c't schon beschrieben) und die Algorithmen sind wohl auch recht gut, theoretisch kann man damit eine geniale Bilddatenbank implementieren -- nur die Umsetzung... *seufz* -dnh [1] hatte Glueck mit den Kernelversionen: zuerst 2.4.0-test1 und -test4, dann gut 1 Jahr spaeter als naechsten 2.4.16... :) [2] die spaetestens vom 6.3.02 ist. Nein, ich hab da keine "Bugreports" gemacht... Zu konfus... [3] will's aber grad nicht raussuchen, ist lange her... -- "Wir werden knapp aber deutlich vor der SPD liegen" -- Ede Stoiber, 21.09.02 Ja watten nu? Knapp _oder_ deutlich? -- ich dazu
Ausserdem empfehle ich eine gruendliche Fehlerbehandlung, mit der kommt man trivialen Fehlern relativ schnell auf die Schliche. Also ala:
bei meinem Client steht folgendes: if (connect(my_socket, (sockaddr *) &serveradresse, sizeof(sockaddr)==-1)) { perror ("connect()"); return -1; } Dann bekomme ich folgende Fehlermeldung: connect(): Invalid argument Blos was ist das "invalid argument"? Also der Server denke ich funktioniert, da die Ausgabe von socklist folgendes liefert: type port inode uid pid fd name tcp 901 2741 0 0 0 tcp 139 2743 0 0 0 tcp 111 950 0 0 0 tcp 50000 12434 500 1256 3 server tcp 6000 6048 0 0 0 tcp 631 1468 0 0 0 udp 137 2745 0 0 0 udp 111 851 0 0 0 udp 631 1469 0 0 0 Also lauscht mein Server auf Port 50000, oder? Danke Holger -- Holger Macht - 91247 Vorra-Artelshofen mailto:holger.macht@web.de - http://www.sgt-hulder.de Homepage: Tabulaturarchiv, Vokabelprogramm, Tools
Hi, On Fri, 7 Feb 2003, Holger Macht wrote:
bei meinem Client steht folgendes: if (connect(my_socket, (sockaddr *) &serveradresse, sizeof(sockaddr)==-1)) { perror ("connect()"); return -1; } Dann bekomme ich folgende Fehlermeldung: connect(): Invalid argument
Also, dass du perror benutzt ist jetzt gut, da du dann einen Hinweis erhaelst auf:
Blos was ist das "invalid argument"?
Nun, eigentlich schrieb David schon alles noetige, aber nochmal: Zuerst die Signatur von connect(): int connect (int sockfd, const struct sockaddr *dest, socklen_t len); Da Ding erwartet also drei Argument, und das dritte sollte ein "socklen_t" sein (es gibt die Laenge der Addresse an). Und connect gibt einen int zurueck. Nun wie du die Funktion benutzt: if (connect (f, (sockaddr*) &dest, sizeof (dest) == -1 ) ) Siehst du's? Dein drittes Arguement an connect() ist "sizeof(dest)==-1", mithin wird es 0 sein, wenn ausgewertet, da die Groesse von "dest" nun mal nicht -1 ist. Fuer connect() uebergibst du also als Addresslaenge 0, was keiner gueltigen Addresse entsprechen kann, mithin eine ungueltige ist, was eben zu "invalid argument" fuehrt. Du wolltest natuerlich den Rueckgabewert von connect() auf -1 testen, aber dazu hast du die falsche Klammerung. Richtig waere: if (connect (f, (struct sockaddr*) &dest, sizeof (dest)) == -1) Lies es dir solang durch, bis du den Unterschied bemerkst. Er ist wirklich da ;-) Nochwas: der Typ der Addresse ist "struct sockaddr*", nicht "sockaddr *". In C++ ist das kein Unterschied, aber in C doch. Wenn du also castest, dann wie in meinem Beispiel.
Also der Server denke ich funktioniert, da die Ausgabe von socklist folgendes liefert:
Jau, sieht gut aus. Ciao, Michael.
Habe den Client jetzt auch zum connecten gebracht, nur das send und
receive funktioniert jetzt net. Jetzt mal mein server:
int main() {
int my_socket, neu_socket, nachricht;
sockaddr_in lokaleadresse,remote_host;
my_socket = socket(AF_INET, SOCK_STREAM, 0);
if (socket<0) perror("socket()");
lokaleadresse.sin_family =AF_INET;
lokaleadresse.sin_port= htons(50000);
lokaleadresse.sin_addr.s_addr = inet_addr("127.0.0.1");
if (bind(my_socket, (sockaddr *)&lokaleadresse, sizeof(sockaddr))
==-1) perror ("bind()");
if (listen(my_socket, 3) <0) perror("listen()");
socklen_t sin_size=sizeof(sockaddr_in);
if (neu_socket=accept( my_socket, (sockaddr *) &remote_host,
&sin_size)==-1)
perror("accept()");
else;
cout <<"CONNECTION!"<
Hi, On Sun, 9 Feb 2003, Holger Macht wrote:
int main() { int my_socket, neu_socket, nachricht; sockaddr_in lokaleadresse,remote_host;
if (bind(my_socket, (sockaddr *)&lokaleadresse, sizeof(sockaddr))
Du willst "struct sockaddr" nicht "sockaddr".
if (neu_socket=accept( my_socket, (sockaddr *) &remote_host, &sin_size)==-1)
Du hast hier (verkuerzt): "if (a=accept (...) == -1)". Dies vergleicht zuerst Rueckgabe von accept() mit -1 und weiss das Ergebnis (0 oder 1) dann 'a' zu. Deine Klammerung ist also wieder mal kaputt, du willst: if ( (neu_socket = accept (....)) == -1) ... der besseren Lesbarkeit wegen empfehle ich aber dringend: neu_socket = accept (....); if (neu_socket == -1) { ... } Das ist auch der Fehler, der das Nichtarbeiten deines Beispieles ausloest.
perror("accept()"); else; cout <<"CONNECTION!"<
Ui. Hast du da wirklich "else;" drinstehen? D.h. dann naemlich, das das "cout << "connection" nicht im else-Zweig steht, sondern als ganz normales toplevel-statement. Du willst: perror ("accept()"); else cout << ...;
char *msg="Ich habs geschafft!!"; int len=strlen (msg); cout <
Man beachte, das du hiermit den ganzen String, allerdings _ohne_ die abschliessende '\0' sendest. Der Empfaenger hat damit keine Moeglichkeit, das Stringende zu erkennen, und wird wohl komische Sachen mit diesem String machen. Du willst: char *msg = ...; int len = 1 + strlen (msg); ....
Ich weiss soweit, dass das irgendwas mit dem "Accept-Socket" zu tun haben muss. Nur in einem Tutorial steht es halt exakt so drin.
Glaub ich nicht. Ciao, Micha. P.S: du machst viele C-Anfaenger Fehler. Vielleicht solltest du nochmal irgendein Buch lesen, was an die Sprache heranfuehrt.
Michael Matz
P.S: du machst viele C-Anfaenger Fehler. Vielleicht solltest du nochmal irgendein Buch lesen, was an die Sprache heranfuehrt.
Er schreibt C++ Programme, daher wäre ein Buch für C++ Anfänger evtl. die bessere Wahl. An Holger: für Standard C++ ist 'int main()' nicht zulässig, die einzig gültige Form ist 'int main(int argc, char **argv)'. Sollte main die Argumente nicht benötigen, lässt man einfach die Namen weg und signalisiert dem Compiler so, dass man die Argumente nicht verwendet. Philipp -- Philipp Thomas Arbeit: pthomas@suse.de Entwicklung, SuSE Linux AG Privat: pth@t-link.de
Hi, On Sun, 9 Feb 2003, Philipp Thomas wrote:
Er schreibt C++ Programme, daher wäre ein Buch für C++ Anfänger evtl. die bessere Wahl.
Hmm, vielleicht, C koennte aber auch nicht schaden, da alle Fehler mehr mit Klammerung, Prioritaet, und grundlegenden C (und C++) Statements zu tun hatten.
An Holger: für Standard C++ ist 'int main()' nicht zulässig, die einzig gültige Form ist 'int main(int argc, char **argv)'.
Nein, falsch, alle weghoeren. Was C++ von main() verlangt, ist return type 'int' zu haben. _Nichts_ weiter. Was zusaetzlich noch verlangt wird, ist, dass alle Implementationen von C++ folgende beiden Definitionen von main erlauben muessen: int main () {....} und int main (int argc, char* argv[]) {....} (siehe 3.6.1.2)
Sollte main die Argumente nicht benötigen, lässt man einfach die Namen weg und signalisiert dem Compiler so, dass man die Argumente nicht verwendet.
Wie gesagt, die erste Form ist voellig OK. Ciao, Micha.
Hallo, On Sun, 09 Feb 2003, Michael Matz wrote:
On Sun, 9 Feb 2003, Philipp Thomas wrote:
Er schreibt C++ Programme, daher wäre ein Buch für C++ Anfänger evtl. die bessere Wahl.
Hmm, vielleicht, C koennte aber auch nicht schaden, da alle Fehler mehr mit Klammerung, Prioritaet, und grundlegenden C (und C++) Statements zu tun hatten.
Ack! V.a. weil er hier mit C-Funktionen hantiert (dem ganzen Socket-Kram z.B.)... Ich wuerde den K&R empfehlen, und den Stroustrup fuer C++. Die fand ich recht leserlich...
An Holger: für Standard C++ ist 'int main()' nicht zulässig, die einzig gültige Form ist 'int main(int argc, char **argv)'.
Nein, falsch, alle weghoeren. Was C++ von main() verlangt, ist return type 'int' zu haben. _Nichts_ weiter. Was zusaetzlich noch verlangt wird, ist, dass alle Implementationen von C++ folgende beiden Definitionen von main erlauben muessen:
int main () {....} und int main (int argc, char* argv[]) {....}
(siehe 3.6.1.2)
Und int main(void) { /* ... */ } Oder? -dnh --
I've gone through over-stressed to physical exhaustion... what's next? Tuesday -- Simon Burr & Kyle Hearn
Hi, On Sun, 9 Feb 2003, David Haller wrote:
Ich wuerde den K&R empfehlen, und den Stroustrup fuer C++. Die fand ich recht leserlich...
Also K&R ... ich weiss nicht. Der K&R Stil ist schon recht obsolet ;) Ich kann allerdings keine Alternativen empfehlen, da ich keine kenne.
int main () {....} und int main (int argc, char* argv[]) {....}
(siehe 3.6.1.2)
Und
int main(void) { /* ... */ }
Oder?
In C++ sind "main()" und "main(void)" exakt dasselbe (also ja zu deiner Frage). Man beachte aber, das C dies anders sieht: dort gilt "main()" als "Anzahl und Type von Parametern unbekannt", und "main(void)" als "exakt 0 Parameter". Fuer C sind also die beiden zu akzeptierenden Deklarationen: int main(void) {...} und int main(int argc, char *argv[]) {...} Ciao, Micha.
Hallo, On Sun, 09 Feb 2003, Michael Matz wrote:
On Sun, 9 Feb 2003, David Haller wrote:
Ich wuerde den K&R empfehlen, und den Stroustrup fuer C++. Die fand ich recht leserlich...
Also K&R ... ich weiss nicht. Der K&R Stil ist schon recht obsolet ;)
NACK! "obsolet" (in einer Art "veraltet", dass es nicht mehr verwendbar ist) ist das Buch garantiert nicht. Auf was beziehst du den "Stil"? (ich hab hier die 2nd Edition mit dem "ANSI C" auf dem Cover im Regal.) [ ] auf die "Sprachebene"? Bis auf ein paar Details vielleicht, die seit der 2ten Auflage geaendert wurden (C'99) ist alles gueltig. Insbesondere sind die Grundlagen (um die's hier ja v.a. geht(!)) nach wie vor aktuell. [ ] auf die Formatierung? Die mag ich sogar, da konsistent, logisch und gut lesbar. In der Art habe ich meine Quelltexte schon immer formatiert, auch wenn's nichtmal C war... [ ] anderes, naemlich: ________________ Argh! Wie war das mit den Prototypen noch? Jedenfalls: in der 2nd Ed. werden Funktionen konsequent in folgendem Stil typisiert: blubb foo(int bar, bla * baz);
Ich kann allerdings keine Alternativen empfehlen, da ich keine kenne.
"Dann schweige er" *scnr*
int main () {....} und int main (int argc, char* argv[]) {....}
(siehe 3.6.1.2)
Und
int main(void) { /* ... */ }
Oder?
In C++ sind "main()" und "main(void)" exakt dasselbe (also ja zu deiner Frage).
Jep. AFAIR ist 'foo()' implizit ein 'foo(void)'. Und ich denke, die explizite Version ist vorzuziehen. Und was den Rueckgabetyp angeht sollte man sich ja sowieso nicht auf die defaults verlassen. Bin schon Quelltext begegnet, der von einem "void"-default ausging (was beim gcc eben nicht der Fall ist)...
Man beachte aber, das C dies anders sieht: dort gilt "main()" als "Anzahl und Type von Parametern unbekannt", und "main(void)" als "exakt 0 Parameter".
Und letzteres ist IMO deutlich vorzuziehen. s.o. Explizite Deklarationen und Initialisierungen sind IMO die einzig saubere Variante... -dnh -- 26: Plug & Play Die Gebrauchsanweisung ist nicht rechtzeitig fertiggeworden. (Peter Berlich)
Hi, On Mon, 10 Feb 2003, David Haller wrote:
Ich wuerde den K&R empfehlen, und den Stroustrup fuer C++. Die fand ich recht leserlich...
Also K&R ... ich weiss nicht. Der K&R Stil ist schon recht obsolet ;)
NACK! "obsolet" (in einer Art "veraltet", dass es nicht mehr verwendbar ist) ist das Buch garantiert nicht.
Auf was beziehst du den "Stil"? (ich hab hier die 2nd Edition mit dem "ANSI C" auf dem Cover im Regal.)
[ ] auf die "Sprachebene"? Bis auf ein paar Details vielleicht, die seit der 2ten Auflage geaendert wurden (C'99) ist alles gueltig. Insbesondere sind die Grundlagen (um die's hier ja v.a. geht(!)) nach wie vor aktuell.
Alles klar. Wie gesagt, ich kenne das Buch nicht, und wenn es ANSI C behandelt ist alles gut. Ich stiess mich aussschliesslich an dem "K&R", d.h. der traditionelle C-Stil, prototypen-los, mit etwas anderem promotion-Regeln als ANSI usw. Und der _ist_ obsolet.
Argh! Wie war das mit den Prototypen noch? Jedenfalls: in der 2nd Ed. werden Funktionen konsequent in folgendem Stil typisiert:
blubb foo(int bar, bla * baz);
Schoen. Und die Definitionen der Funktionen? blubb foo (bar, baz) int bar; bla *baz; { /* ... */ } oder blubb foo (int bar, bla *baz) { /* ... */ } ? (erstes ist K&R, zweites ANSI).
In C++ sind "main()" und "main(void)" exakt dasselbe (also ja zu deiner Frage).
Jep. AFAIR ist 'foo()' implizit ein 'foo(void)'.
Wie gesagt, nur in C++, nicht C.
Man beachte aber, das C dies anders sieht: dort gilt "main()" als "Anzahl und Type von Parametern unbekannt", und "main(void)" als "exakt 0 Parameter".
Und letzteres ist IMO deutlich vorzuziehen. s.o.
In C kann man das eine dem anderen nicht vorziehen, da beide _nicht_ aequivalent sind. Entweder braucht man das eine oder das andere, persoenliche Preferenzen aendern dies nicht.
Explizite Deklarationen und Initialisierungen sind IMO die einzig saubere Variante...
Hier wird nichts initialisiert. Ciao, Micha.
Hallo, On Mon, 10 Feb 2003, Michael Matz wrote:
On Mon, 10 Feb 2003, David Haller wrote:
Ich wuerde den K&R empfehlen, und den Stroustrup fuer C++. Die fand ich recht leserlich...
Also K&R ... ich weiss nicht. Der K&R Stil ist schon recht obsolet ;)
NACK! "obsolet" (in einer Art "veraltet", dass es nicht mehr verwendbar ist) ist das Buch garantiert nicht.
Auf was beziehst du den "Stil"? (ich hab hier die 2nd Edition mit dem "ANSI C" auf dem Cover im Regal.)
[ ] auf die "Sprachebene"? Bis auf ein paar Details vielleicht, die seit der 2ten Auflage geaendert wurden (C'99) ist alles gueltig. Insbesondere sind die Grundlagen (um die's hier ja v.a. geht(!)) nach wie vor aktuell.
Alles klar. Wie gesagt, ich kenne das Buch nicht, und wenn es ANSI C behandelt ist alles gut. Ich stiess mich aussschliesslich an dem "K&R", d.h. der traditionelle C-Stil, prototypen-los, mit etwas anderem promotion-Regeln als ANSI usw. Und der _ist_ obsolet.
Ok.
Argh! Wie war das mit den Prototypen noch? Jedenfalls: in der 2nd Ed. werden Funktionen konsequent in folgendem Stil typisiert:
blubb foo(int bar, bla * baz);
Schoen. Und die Definitionen der Funktionen? [..] ? (erstes ist K&R, zweites ANSI).
K&R, 2nd Ed. ISBN 0-13-110362-8, Seite 64: ==== void itoa(int n, char s[]) { int i, sign; /* ... */ } ==== Also ANSI. Leider gibt's aber folgendes: ==== main() { /* ... */ return 0; } ==== was ich fuer nicht gut halte, selbst wenn das vom Standard gedeckt wird. Hab vor ner Weile mal code kompilieren wollen, wo IIRC teilweise davon ausgeganten wurde, dass bei sowas der Rueckgabetyp int ist, z.T. aber auch davon, dass er void ist[1]. *argl*
Explizite Deklarationen und Initialisierungen sind IMO die einzig saubere Variante...
Hier wird nichts initialisiert.
Ja, hier nicht. Aber generell. Insbesondere Pointer... -dnh [1] zu erkennen an den Returns, mal war's: foo() { return; } und ein andermal bar() { return 0; } und das im gleichen Programm wohlgemerkt (wenn auch nicht in einer Datei). -- If you don't see why, please stay the fuck away from my code. -- Paul "Rusty" Russel, in /usr/src/linux/Documentation/DocBook/kernel-locking.tmpl
David Haller
==== main() { /* ... */ return 0; } ====
was ich fuer nicht gut halte, selbst wenn das vom Standard gedeckt wird.
Das wird selbst vom Standard nur zum Teil abgedeckt. Der sog. implizite int (alles was keinen expliziten Typ hat ist 'int') ist nach ISO C99 nicht zulässig. Philipp -- Philipp Thomas Arbeit: pthomas@suse.de Entwicklung, SuSE Linux AG Privat: pth@t-link.de
Hallo, On Mon, 10 Feb 2003, Philipp Thomas wrote:
David Haller
[10 Feb 2003 12:19:49 +0100]: ==== main() {/* ... */ return 0;} ==== was ich fuer nicht gut halte, selbst wenn das vom Standard gedeckt wird.
Das wird selbst vom Standard nur zum Teil abgedeckt. Der sog. implizite int (alles was keinen expliziten Typ hat ist 'int') ist nach ISO C99 nicht zulässig.
Ok. Ich bleibe also dabei, alles, das nicht explizit den richtigen return-type angibt, als "schlampig" zu betrachten :) -dnh -- 184: MP3 Kann von WinAMP abgespielt werden. (Felix von Leitner)
Am Die, 2003-02-11 um 00.29 schrieb David Haller:
Hallo,
On Mon, 10 Feb 2003, Philipp Thomas wrote:
David Haller
[10 Feb 2003 12:19:49 +0100]: ==== main() {/* ... */ return 0;} ==== was ich fuer nicht gut halte, selbst wenn das vom Standard gedeckt wird.
Das wird selbst vom Standard nur zum Teil abgedeckt. Der sog. implizite int (alles was keinen expliziten Typ hat ist 'int') ist nach ISO C99 nicht zulässig. c99 != c89 != knc.
Ok. Ich bleibe also dabei, alles, das nicht explizit den richtigen return-type angibt, als "schlampig" zu betrachten :) Nein, die Sprache hat sich geändert - implizite int's als schlampig zu betrachten ist Pedanterie.
Ralf
Hallo, On Tue, 11 Feb 2003, Ralf Corsepius wrote:
Am Die, 2003-02-11 um 00.29 schrieb David Haller:
On Mon, 10 Feb 2003, Philipp Thomas wrote:
David Haller
[10 Feb 2003 12:19:49 +0100]: ==== main() {/* ... */ return 0;} ==== was ich fuer nicht gut halte, selbst wenn das vom Standard gedeckt wird.
Das wird selbst vom Standard nur zum Teil abgedeckt. Der sog. implizite int (alles was keinen expliziten Typ hat ist 'int') ist nach ISO C99 nicht zulässig. c99 != c89 != knc.
s/c\./r/;
Ok. Ich bleibe also dabei, alles, das nicht explizit den richtigen return-type angibt, als "schlampig" zu betrachten :) Nein, die Sprache hat sich geändert - implizite int's als schlampig zu betrachten ist Pedanterie.
"So, I'm a pedant? So what?" Seit wann ist das beim Programmieren eine schlechte Eigenschaft? Nebenbei bemerkt: Wann ist's dir lieber, dass es "knallt"? Schon beim Kompilieren oder erst zu Laufzeit?[1] Letzteres, oder? Eben. -dnh [1] denk z.B. mal an den Kernel.. Willst du, dass der erst zur Laufzeit die "Panic" bekommt, oder eher, dass schon beim Kompilieren ein Fehler kommt? -- 147: Fortran Makrosprache für ein I/O-Verhinderungssystem (Arno Eigenwillig)
Am Die, 2003-02-11 um 04.35 schrieb David Haller:
Hallo,
On Tue, 11 Feb 2003, Ralf Corsepius wrote:
Am Die, 2003-02-11 um 00.29 schrieb David Haller:
On Mon, 10 Feb 2003, Philipp Thomas wrote:
David Haller
[10 Feb 2003 12:19:49 +0100]: ==== main() {/* ... */ return 0;} ==== was ich fuer nicht gut halte, selbst wenn das vom Standard gedeckt wird.
Das wird selbst vom Standard nur zum Teil abgedeckt. Der sog. implizite int (alles was keinen expliziten Typ hat ist 'int') ist nach ISO C99 nicht zulässig. c99 != c89 != knc.
s/c\./r/;
Ok. Ich bleibe also dabei, alles, das nicht explizit den richtigen return-type angibt, als "schlampig" zu betrachten :) Nein, die Sprache hat sich geändert - implizite int's als schlampig zu betrachten ist Pedanterie.
"So, I'm a pedant? So what?" Steht Dir frei zu denken, was Du willst ;)
Seit wann ist das beim Programmieren eine schlechte Eigenschaft?
Nebenbei bemerkt: Wann ist's dir lieber, dass es "knallt"? Schon beim Kompilieren oder erst zu Laufzeit? Es knallt eben nicht. Implizite int-Return-Decls sind syntaktisch korrektes C mit genau definiertem Verhalten und deshalb weder unsicher noch fehlerhaft.
Dass es c99 anders zu definieren scheint, wäre eine Inkompatibilität zwischen einem zukünftigen Standard [1] und seinen Vorgängern, mehr aber auch nicht.
[1] denk z.B. mal an den Kernel.. Willst du, dass der erst zur Laufzeit die "Panic" bekommt, oder eher, dass schon beim Kompilieren ein Fehler kommt? Schau dir mal genau an, was gcc mit impliziten int decls macht: Warnungen mit -Wall, keine Warnungen ohne -W-Flags, keine Errors!
Ralf [1] Selbst gcc-3.2.x implementiert c99 nur teilweise, gcc-2.9x praktisch gar nicht.
Ralf Corsepius
Warnungen mit -Wall, keine Warnungen ohne -W-Flags, keine Errors!
Schalte mal C99-Modus ein und schon wird's ein Fehler :) BTW, es gibt Maintainer, die erfolgreiches Kompilieren mit '-W -Wall -Wno-unused -Wstrict-prototypes -Werror' als Bedingung für das Akzeptieren von Code machen. Philipp -- Philipp Thomas Arbeit: pthomas@suse.de Entwicklung, SuSE Linux AG Privat: pth@t-link.de
Am Die, 2003-02-11 um 08.29 schrieb Philipp Thomas:
Ralf Corsepius
[11 Feb 2003 07:07:50 +0100]: Warnungen mit -Wall, keine Warnungen ohne -W-Flags, keine Errors!
Schalte mal C99-Modus ein und schon wird's ein Fehler :) Noch einmal: C99 ist ein NEUER C-Dialekt, mit anderen Worten, eine andere Sprache, die teilweise nicht kompatibel zu ihren Vorgängern ist.
Du erwartest doch nicht im Ernst, dass ein C99-Compiler eine andere Sprache akzeptiert und das Entwickler ihren Code im Vorgriff auf "mögliche zukünftige Standards" angepasst haben.
BTW, es gibt Maintainer, die erfolgreiches Kompilieren mit '-W -Wall -Wno-unused -Wstrict-prototypes -Werror' als Bedingung für das Akzeptieren von Code machen. Ja, gibt es, ...
... über den Sinn und Zweck kann man streiten, ... Ralf
Hallo, On Tue, 11 Feb 2003, Ralf Corsepius wrote:
Am Die, 2003-02-11 um 04.35 schrieb David Haller:
On Tue, 11 Feb 2003, Ralf Corsepius wrote:
Am Die, 2003-02-11 um 00.29 schrieb David Haller: [..]
Ok. Ich bleibe also dabei, alles, das nicht explizit den richtigen return-type angibt, als "schlampig" zu betrachten :) Nein, die Sprache hat sich geändert - implizite int's als schlampig zu betrachten ist Pedanterie. [..] Nebenbei bemerkt: Wann ist's dir lieber, dass es "knallt"? Schon beim Kompilieren oder erst zu Laufzeit? Es knallt eben nicht. Implizite int-Return-Decls sind syntaktisch korrektes C mit genau definiertem Verhalten und deshalb weder unsicher noch fehlerhaft.
Jaaa, vorausgesetzt, dass die Funktion einen int zurueckgibt! Darum geht's mir doch. blubb() { machwas(); return; } So, das ist implizit ein 'int blubb()'. Schoen. Denn kann man also int main(void) { return blubb(); } schreiben? Wie gesagt: ich hab ein Programm versucht zu kompilieren, in dem mal von einem impliziten void und mal von nem int ausgegangen wurde. Das ist natuerlich Mist. Und wenn man immer explizit hinschreibt, welchen return-type eine Funktion hat, dann gibt's dieses Problem eben nicht, egal was der Programmierer und der Compiler annehmen. Und nein, -Wall wird scheinbar von den Kandidaten nicht verwendet... -dnh -- "In My Egotistical Opinion, most people's C programs should be indented six feet downward and covered with dirt." -- Blair P. Houghton
Am Die, 2003-02-11 um 16.43 schrieb David Haller:
Hallo,
On Tue, 11 Feb 2003, Ralf Corsepius wrote:
Am Die, 2003-02-11 um 04.35 schrieb David Haller:
On Tue, 11 Feb 2003, Ralf Corsepius wrote:
Am Die, 2003-02-11 um 00.29 schrieb David Haller: [..]
Ok. Ich bleibe also dabei, alles, das nicht explizit den richtigen return-type angibt, als "schlampig" zu betrachten :) Nein, die Sprache hat sich geändert - implizite int's als schlampig zu betrachten ist Pedanterie. [..] Nebenbei bemerkt: Wann ist's dir lieber, dass es "knallt"? Schon beim Kompilieren oder erst zu Laufzeit? Es knallt eben nicht. Implizite int-Return-Decls sind syntaktisch korrektes C mit genau definiertem Verhalten und deshalb weder unsicher noch fehlerhaft.
Jaaa, vorausgesetzt, dass die Funktion einen int zurueckgibt! Das tun Funktionen ohne Return-Typ Deklaration _immer_.
Darum geht's mir doch.
blubb() { machwas(); return; } Ob das jetzt syntaktisch korrekt ist, bin ich mir nicht sicher.
blubb() { machwas(); } ist es jedenfalls und wird implizit zu int blubb( ) { return machwas(); }
So, das ist implizit ein 'int blubb()'. Schoen. Denn kann man also
int main(void) { return blubb(); }
schreiben? Ja.
Wie gesagt: ich hab ein Programm versucht zu kompilieren, in dem mal von einem impliziten void und mal von nem int ausgegangen wurde. Das ist natuerlich Mist. Ja, implizite voids gibt es nicht.
Ralf
Ralf Corsepius
implizite int's als schlampig zu betrachten ist Pedanterie.
Sorry, aber implizite ints waren IMNSHO schon vor 13 Jahren, als ANSI C frisch war und ich C lernte, schlampig, da Ausdruck der Faulheit des Programmierers. Ja, sie waren noch zulässig, aber das muss nicht viel heissen. Das ist ähnlich wie () statt (void) oder unvollständig deklarierten Funktionszeigern in Code, der ansonsten mit korrekten Prototypen arbeitet. Philipp -- Philipp Thomas Arbeit: pthomas@suse.de Entwicklung, SuSE Linux AG Privat: pth@t-link.de
Hi, "C" bot von Anfang an erheblich höhere Freiheitsgrade als die meisten anderen Programmiersprachen. Entsprechend war die Welt der "C" Programmierer eine tolerante, recht demokratische. Wer lieber ein striktes, nicht zu sagen "pedantisches", Konzept bevorzugt, und entsprechend Probleme mit dem amerikanischen Verständnis von Freiheit hat, der sollte besser zu einer anderen Programmiersprache wechseln. Sorry, aber wegen solchen stilistischen Details sollte man wirklich keine so weltbewegende Kontroverse machen, wie ihr es tut, und insbesondere nicht in der Pose des diktatorischen Zensors über- einander herfallen, denn das passt nun wirklich nicht zur Welt von "C". -Hans
On Tue, 11 Feb 2003 at 08:45 (+0100), Hans Larsen wrote:
"C" bot von Anfang an erheblich höhere Freiheitsgrade als die meisten anderen Programmiersprachen. Entsprechend war die Welt der "C" Programmierer eine tolerante, recht demokratische.
Wer lieber ein striktes, nicht zu sagen "pedantisches", Konzept bevorzugt, und entsprechend Probleme mit dem amerikanischen Verständnis von Freiheit hat, der sollte besser zu einer anderen Programmiersprache wechseln.
Was hat das jetzt mit einem "amerikanischen Verstaendnis von Freiheit" zu tun? Dass nichts festgelegt ist und jeder Compilerbauer die Dinge anders interpretiert.
Sorry, aber wegen solchen stilistischen Details sollte man wirklich keine so weltbewegende Kontroverse machen, wie ihr es tut, und insbesondere nicht in der Pose des diktatorischen Zensors über- einander herfallen, denn das passt nun wirklich nicht zur Welt von "C".
Man kann doch wie erwachsene Menschen vernuenfig diskutieren ohne gleich mit Worten wie Diktatur etc. zu kommen. Gruß, Bernhard -- Es gibt viel zu tun - schnell weg! -- Peter E. Schumacher
Am Die, 2003-02-11 um 08.23 schrieb Philipp Thomas:
Ralf Corsepius
[11 Feb 2003 02:23:42 +0100]: implizite int's als schlampig zu betrachten ist Pedanterie.
Sorry, aber implizite ints waren IMNSHO schon vor 13 Jahren, als ANSI C frisch war und ich C lernte, Vor 13 Jahren gab es praktisch keine ANSI Compiler ;)
Borland/Turbo-C gaben damals vor es zu sein, waren es aber nicht wirklich; ebenso wenig wie DEC's VMS-ANSI-C-Compiler, der Sun-C war ein reiner KnR-Compiler. Der gcc steckte noch ziemlich in den Kinderschuhen und wurde nur wenig ernstgenommen ... Aus dieser Zeit stammt auch die Masse des X11-Codes, der deshalb auch mit ANSI/KNR-Kompatibilitäts-Macros gespickt ist, ebenso wie die gcc __P()-Macros
schlampig, da Ausdruck der Faulheit des Programmierers. In neuem, heute zu schreibendem Code, ja.
Ja, sie waren noch zulässig, aber das muss nicht viel heissen. Es ist dann von Belang, wenn es sich um alten Code handelt.
IMNSHO, ist Suche nach impliziten int-Returns sinnentleerter Aktionismus (Man behebt dadurch keine Fehler), es sei denn, man ist der Maintainer/Entwickler eines Projektes und will seinen Quellcode auf neueste Standards anpassen. Das gleiche gilt für implizite Returns ( int foo() { function(); }. Anders schaut es mit derartigen, in KnR syntaktisch korrekten, aber nur maschinenabhängigen Konstrukten aus: int foo( int*) int foo( a ) short* a; { } Diese hochgefährliche Konstruktion wird von -W-Flags in gcc nicht detektiert, ist in KnR-C und älterem "möchtegern" ANSI-C-Code aber nicht selten anzutreffen. Ralf
Ralf Corsepius
Vor 13 Jahren gab es praktisch keine ANSI Compiler ;)
Borland/Turbo-C gaben damals vor es zu sein, waren es aber nicht wirklich;
Jo, es hat eine Weile gedauert, bis die Compiler nachgezogen sind. Zugegeben, am Anfang waren mir vor allem die Prototypen wichtig, während sich mir die Feinheiten erst sehr viel später erschlossen haben.
Aus dieser Zeit stammt auch die Masse des X11-Codes, der deshalb auch mit ANSI/KNR-Kompatibilitäts-Macros gespickt ist, ebenso wie die gcc __P()-Macros
Jepp, ich weiss (zu X11 unten mehr). Aber für den gcc gilt ja nur noch für die Teile, die in stage1 übersetzt werden, dass sie auch noch mit steinzeitlichen K&R Compilern übersetzbar sein müssen.
Anders schaut es mit derartigen, in KnR syntaktisch korrekten, aber nur maschinenabhängigen Konstrukten aus:
int foo( int*) int foo( a ) short* a; { }
Diese hochgefährliche Konstruktion wird von -W-Flags in gcc nicht detektiert, ist in KnR-C und älterem "möchtegern" ANSI-C-Code aber nicht selten anzutreffen.
Irrtum :) gcc 2.95.3 ohne jegliche Warnoption: int foo (int *); int foo (a) short *a; { return 0; } t.c: In function `foo': t.c:6: argument `a' doesn't match prototype t.c:1: prototype declaration Aber die implizite Aufweitung (default promotion) bzw. deren Fehlen kann einem richtig Kopfschmerzen bereiten, wenn man K&R Code nach ISO C portiert. Ich habe mich mal vor Jahren daran gemacht, den *internen* Code im XFree86 library Teil aufzuräumen (interne header statt extern Deklarationen in diversen .c, ANSI Prototypen in der Form, wie sie X11 verwendet etc.) und es war für mich doch erstaunlich, was so passieren kann, wenn in Gegenwart von Prototypen die Argumente eben genau so weiter gereicht werden, wie der Prototyp angibt. Bevor ich das aber auch nur halb fertig hatte, ereilte mich das Angebot, für SuSE zu arbeiten. Aber bei dieser Arbeit habe ich eine Menge dazu gelernt. Philipp -- Philipp Thomas Arbeit: pthomas@suse.de Entwicklung, SuSE Linux AG Privat: pth@t-link.de
int main() { int my_socket, neu_socket, nachricht; sockaddr_in lokaleadresse,remote_host;
if (bind(my_socket, (sockaddr *)&lokaleadresse, sizeof(sockaddr))
Du willst "struct sockaddr" nicht "sockaddr".
Warum brache ich strukt sockaddr? Geht auch ohne! Wenn ich es brauche, muss ich es dann auch bei accept(),usw benutzen?
if (neu_socket=accept( my_socket, (sockaddr *) &remote_host, &sin_size)==-1)
Du hast hier (verkuerzt): "if (a=accept (...) == -1)". Dies vergleicht zuerst Rueckgabe von accept() mit -1 und weiss das Ergebnis (0 oder 1) dann 'a' zu. Deine Klammerung ist also wieder mal kaputt, du willst:
if ( (neu_socket = accept (....)) == -1) ...
Vollkommen richtig. Habe 1000 mal mit dem TUtorial verglichen und den Fehler nicht gesehen.
perror("accept()"); else; cout <<"CONNECTION!"<
Ui. Hast du da wirklich "else;" drinstehen? D.h. dann naemlich, das das "cout << "connection" nicht im else-Zweig steht, sondern als ganz normales toplevel-statement. Du willst: perror ("accept()"); else cout << ...;
Auch richtig *g*!
char *msg="Ich habs geschafft!!"; int len=strlen (msg); cout <
Man beachte, das du hiermit den ganzen String, allerdings _ohne_ die abschliessende '\0' sendest. Der Empfaenger hat damit keine Moeglichkeit, das Stringende zu erkennen, und wird wohl komische Sachen mit diesem String machen. Du willst:
char *msg = ...; int len = 1 + strlen (msg); ....
Habe es halt gemäß dem Tutorial gemacht.
P.S: du machst viele C-Anfaenger Fehler. Vielleicht solltest du nochmal irgendein Buch lesen, was an die Sprache heranfuehrt.
Hab schon zwei gelesen. Doch dann habe ich wieder weiter Pascal programmiert und das verwirrt mich immer. Inzweichen kann ich's nämlich nicht mal mehr mit Pascal *g* Aus jeden fall funktioniert es jetzt. Wenn ich vielleicht noch einen kleinen TIpp abstauben dürfte, damit ich weiss wo ich weiter zu machen habe: Ich brauche ein par Stichworte, wie ich jetzt einen Befehl über die Scckets schicken kann, und die dann auf dem Zielrechner ausgeführt werden. Danke Holger -- Holger Macht - 91247 Vorra-Artelshofen mailto:holger.macht@web.de - http://www.sgt-hulder.de Homepage: Tabulaturarchiv, Vokabelprogramm, Tools
Am Donnerstag, 6. Februar 2003 21:23 schrieb Holger Macht:
Hallo, habe zwar schon einiges programmiert, doch lbis jetzt noch nicht in Sachen Netztwerk. Habe einige Tutorials im INet gelesen und konnte dabei auch gut folgen. Jetzt meine Frage: Wenn ich einen Server und einen Client programmiere also:
Server: socket, bind, listen, accept Client: socket, connect
bekomme ich immer eine Fehlermeldung beim "connecten" des clients. Ist es möglich ,dass ich auch nur mit einem Rechner einen Server und einen Client programmiere und dann connecten lasse? Muss ich dann bei beiden den selben Port einstellen? DIe IP natürlich ja, oder? Welche Ports verwende ich am besten?
Danke für die Hilfe Holger
Hallo Holger lies einmal Programmieren von Unix-Netzwerken von W. Richard Stevens Das Buch ist ungemein aufschlussreich Viele Gruesse Robert
participants (10)
-
Arvin Schnell
-
Bernhard Walle
-
Christoph Maurer
-
David Haller
-
Hans Larsen
-
Holger Macht
-
Michael Matz
-
Philipp Thomas
-
Ralf Corsepius
-
Robert Jenni