Hallo liebe Forenuser, ich habe mir wegen einer Lehrveranstaltung C angeeignet, doch leider habe ich noch genug offene Fragen und hoffe, dass ihr mir weiterhelfen könnt. 1) Fehlerausgabe. Ich habe mittlerweile unzählige Funktionen zur Fehlerausgabe gesehen: fprintf(sterr,...), fatal, perror, ... doch welche soll man nun nutzen und wo sind ihre Vor/Nachteile? 2) Datentypen Ich habe gelesen, dass es eigentlich keine Bool-Variablen gibt und man auf int zurückgreifen soll. Aber int hat (ja nach PC) 32bit, aber ich brauche doch nur 1 Bit? Auch wenn es in der heutigen Zeit meist egal ist - wie könnte ich nur ein bit allozieren? Weiters muss ich für eine Übung einen Server schreiben, der ein eigenes Protokoll verwendet. Doch hier brauche ich nur 2 Byte, wobei ich auf jedes Bit zugreifen können muss - welchen Datentyp würdet ihr hier verwenden? Gibt es irgendwie eine Art bit-Array? danke!
inkrement schrieb: > 1) Fehlerausgabe. > Ich habe mittlerweile unzählige Funktionen zur Fehlerausgabe gesehen: > fprintf(sterr,...), fatal, perror, ... doch welche soll man nun nutzen > und wo sind ihre Vor/Nachteile? Solange nichts dagegen spricht, fprintf( stderrr... - das ist portabel und gibt aus. perror() gibt Text zum aktuellen Wert der errno-Variable aus, ist also nicht für allgemeine Ausgaben geeignet. > > 2) Datentypen > Ich habe gelesen, dass es eigentlich keine Bool-Variablen gibt und man > auf int zurückgreifen soll. Aber int hat (ja nach PC) 32bit, aber ich > brauche doch nur 1 Bit? Auch wenn es in der heutigen Zeit meist egal ist > - wie könnte ich nur ein bit allozieren? 1 Bit geht gar nicht. Auf Rechner mit knappem Speicher wird int auch keine 32 Bit haben, sondern nur 8 oder 16. Wenn man geizen will, kann man uint8_t nehmen, weniger geht nicht ohne Klimmzüge. Und den gesparten Speicher erkauft man sich gelegentlich mit langsamerem Programmlauf, je nach System.
(unknown) schrieb: > 1 Bit geht gar nicht. > Auf Rechner mit knappem Speicher wird int auch keine 32 Bit haben, > sondern nur 8 oder 16. > > Wenn man geizen will, kann man uint8_t nehmen, weniger geht nicht ohne > Klimmzüge. > Und den gesparten Speicher erkauft man sich gelegentlich mit langsamerem > Programmlauf, je nach System. Ok, Danke. Dann werde ich für die zwei Bytes uint16_t verwenden, aber wie könnte ich da auf jedes Byte einzeln zugreifen?
inkrement schrieb: > Ich habe gelesen, dass es eigentlich keine Bool-Variablen gibt und man _Bool existiert, ebenso stdbool.h. > auf int zurückgreifen soll. Aber int hat (ja nach PC) 32bit, aber ich > brauche doch nur 1 Bit? Auch wenn es in der heutigen Zeit meist egal ist > - wie könnte ich nur ein bit allozieren? Gar nicht. In C ist die Grundeinheit des Speicherzugriffs das Byte. Und das sind eben mindestens 8 Bit. Im übrigen wird das ganze nur ineffizienter, wenn du versuchst, unterhalb der "natürlichen" Zugriffsbreite des Prozessors rumzuwurschteln.
Da gibt es mehrere Möglichkeiten: 1. Mit Bitmaske
1 | -include <stdint.h> |
2 | ...
|
3 | uint16_t derWert = ...; |
4 | |
5 | /* Testen, ob Bit 3 (gezählt ab 0) gesetzt ist: */
|
6 | if( derWert & (1<<3) ) |
7 | {
|
8 | /* dann Bit 4 setzen: */
|
9 | derWert |= 1<<4; |
10 | }
|
Dazu steht auch mehr im gcc-Tutorial, siehe links oben. 2. Man kann sich Bitfelder definieren, z.B.
1 | typedef struct |
2 | {
|
3 | unsigned bit0: 1; |
4 | unsigned bit1: 1; |
5 | unsigned bit2: 1; |
6 | unsigned bit3: 1; |
7 | unsigned bit4: 1; |
8 | unsigned bit5: 1; |
9 | unsigned bit6: 1; |
10 | unsigned bit7: 1; |
11 | unsigned bit8: 1; |
12 | unsigned bit9: 1; |
13 | unsigned bit10: 1; |
14 | unsigned bit11: 1; |
15 | unsigned bit12: 1; |
16 | unsigned bit13: 1; |
17 | unsigned bit14: 1; |
18 | unsigned bit15: 1; |
19 | }
|
20 | zweiByte_bitweise_t; |
21 | ....
|
22 | |
23 | zweiByte_bitweise_t derwert; |
24 | /* Testen, ob Bit 3 (gezählt ab 0) gesetzt ist: */
|
25 | if( derWert.bit3 ) |
26 | {
|
27 | /* dann Bit 4 setzen: */
|
28 | derWert.bit4 = 1; |
29 | }
|
Martin schrieb: > _Bool existiert, ebenso stdbool.h. Dann musst du aber auch sagen, nach wessen Hausstandard du das sagst.
... 3. Man kann mit einer union verschiedene Sachen Typen an derselben Speicherstelle übereinander legen, z.B. eine uint16_t und ein Feld von 2 uint8_t. Nur in Grenzen empfehlenswert; man sollte sissen was man tut. 4. Mit Speicherakrobatik, dto..
Klaus Wachtler schrieb: > -include <stdint.h> soll heißen: #include <stdint.h> Klaus Wachtler schrieb: > zweiByte_bitweise_t derwert; Groß-/Kleinschreibung sollte man schon beachten, also lieber derWert...
Klaus Wachtler schrieb: > Martin schrieb: >> _Bool existiert, ebenso stdbool.h. > > Dann musst du aber auch sagen, nach wessen Hausstandard du das sagst. Was meinst du mit "Hausstandard"? Das ist C-Standard (C99). Aber natürlich belegt _Bool auch nicht nur ein Bit.
Danke für die vielen Antworten. Bis auf eine weitere Frage wurden alle Unklarheiten beseitigt :) Wenn ich jetzt 2 Bytes (in einem eigenem Protokoll) per TCP verschicken soll und der Server nun "pro zug" die 2 Bytes in einem uint16_t speichern soll, wie kann ich das machen? ... denn mit recv bekomme ich ja nur char für char oder ein chararray, doch ich will doch kein char. Muss ich das jetzt mit einem anderen Befehl machen, oder irgendwie casten? Also einen Buffer von 2 Chars empfangen und dann in einen uint16_t umwaldeln? Weiters wird es ja dann auch auf die Byte-Reihenfolge ankommen, da ich ja einen Intel x86 Prozessor verwende?!
recv() liest zwar Zeichen fpr Zeichen, bekommt aber sinnvollerweise einen Zeiger für den Puffer übergeben vom Typ void*. An dieser Stelle kann man auch die Adresse einer uint16_t übergeben, als Länge dann natürlich 2. Allerdings muß man hier aufpassen, ob die beiden Systeme die gleiche "Endianness" haben. Es gibt "big endian" und "little endian" Systeme. Bei LE (Intel bzw. AMD, AVR) liegen die 8 niederwertigen Bits an der niedrigeren der beiden belegten Adressen, die 8 höherwertigen an der höheren; bei BE (Motorola und alle anderen richtigen Systeme) genau umgekehrt. Wenn man ab &einerVariable in einem LE-System schreibt und mit recv() oder anderen entsprechend auf einem BE-System liest oder umgekehrt, dann sind die beiden Byte vertauscht. Also entweder auf einem BE-System immer tauschen beim Schreiben und Lesen oder immer auf einem LE-System, oder gar nicht binär übertragen, sondern in Text wandeln und den übertragen.
Ich habe wieder einiges weitergebracht, aber bei dem Empfang der zwei Bits mit recv weiß ich noch nicht ganz, was das Beste wäre. Die Funktion (recv) erhält ja nicht immer die geforderten 2 Bytes, sondern zwischen 1 und 2. Daher habe ich mir gedacht, dass ich einen uint8_t Buffer mit zwei Werten mache und solange recv mit jeweils 1 Byte aufrufe, bis dieser Buffer gefüllt ist. Damit sollte ja auch der Fall, dass ich nicht die zwei Bytes auf einmal bekomme, verhindert sein, oder? Doch nun habe ich ein Array mit zwei uint8_t Werten - wie kann ich die zu einem uint16_t konvertieren und dabei Little/Big Endian beherzigen? Ich habe schon versucht den array-"Pointer" zu casten, doch da wollte der Compiler nicht mitspielen. Gedacht hätte ich, dass ich in ein uint16_t konvertiere und dann mit ntohs Little/Big Endian Probleme beseitige. Durch TCP sollte ja auch die Reihenfolge der eintreffenden Bits richtig sein - oder wird der Plan nicht aufgehen?!
inkrement schrieb: > Gedacht hätte ich, dass ich in ein uint16_t konvertiere und dann mit > ntohs Little/Big Endian Probleme beseitige. Durch TCP sollte ja auch die > Reihenfolge der eintreffenden Bits richtig sein - oder wird der Plan > nicht aufgehen?! TCP direkt korrigiert gar nichts. ntohs() etc. würden gehen, die wirst du aber auf einem AVR gar ncht haben. Es hängt halt davon ab, um welche Systeme es überhaupt geht. - Systeme bekannt: also auch LE/BE bekannt, bei Bedarf manuell konvertieren - nicht bekannt/soll portabel sein: - ntohs() etc. nehmen, oder - gar nicht die uint16_t direkt aus dem Speicher schreiben/lesen, sondern gezielt erst das eine Byte senden, dann das andere ( (i&0xff) senden, dann ((i>>8)&0xFF) senden; beim Empfänger (erstesGelesenesByte|(zweitesGelesenesByte<<8)) bilden, oder umgekehrt ). Dadurch wird die Endianness egal. Oder: - Auf das ganze Binärgedöns verzichten und in Text wandeln, senden, beim Empfänger aus dem Text wieder zur Zahl wandeln.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.