Hallo, ich würde gerne die Werte aus einem char Array alle in eine char Variable speichern. Also: char test[6] = {9,8,7,6,5,4}; in eine Variable wie wenn ich diese mit char test="987654"; definiere. Wie stelle ich das am besten an? :)
Hans schrieb: > Man kann nicht 6 x 8 = 48 Bit in 8 Bit speichern. Für eine 6-stellige Zahl würden auch 20bit reichen, das sind aber immer noch mehr als 8bit.
:
Bearbeitet durch User
Paul schrieb: > in eine Variable wie wenn ich diese mit char test="987654"; definiere. Ich nehme mal an, dass die Programmiersprache C ist. Dann müsste es aber so lauten:
1 | char *test="987654"; |
Sonst gibt es nämlich eine "warning: initialization makes integer from pointer without a cast". Und womit? Mit Recht!
Programmiert wird mit den Arduino-Libarys. Nun ja es geht darum dass ich mit folgender Libary: https://github.com/tzikis/ArduinoMD5/ einen MD5-Hash aus einem Array erzeugen will. Der Hash lässt sich jedoch nur erzeugen wenn der Parameter(zu verschlüsselnde Zahl) mit char definiert sind...
MD5::make_hash erwartet genau einen String (char*) und den hast du ja schon, wozu willst du das Ganze noch in eine einzelne char packen?
:
Bearbeitet durch User
Ich würde gerne ein ganzes Array hashen welches von einem UDP-Packet ausgelesen wird.
char und char* sind 2 dinge. char ist ein 8-bit wert, char* ist ein pointer (eine Adresse im Speicher) ab der mehrere chars zu finden sind (ein String). Was du offenbar verwenden möchtest ist ein Pointer auf einen String (char*). Und da hat dir Mark Brandis verraten, wie man diesen definiert: char *test="987654"; "test" enhält dann also die Adresse vom ersten Byte ("9") von "987654".
Paul schrieb: > Ich würde gerne ein ganzes Array hashen welches von einem UDP-Packet > ausgelesen wird. dann mach das doch. Wenn es nicht geht zeigt wie du es machst.
Wenn die Daten als Array vorhanden sind, und du die Hash Funktion aufrufen sollst, indem du ihr dieses Array übergibst, dann geht das ganz einfach so:
1 | unsigned long meineHashFunktion(char* arg) { |
2 | ... |
3 | }; |
4 | |
5 | char buffer[100]; |
6 | |
7 | meineHashFunktion(buffer); |
Denn buffer kann wahlweise als array von chars oder als pointer auf chars verwendet werden. Die Hash Funktion könnte auch beide Varianten als Argument erwarten - letztendlich ist es das Selbe. Die folgende Code-Fragmente sinnd alle syntaktisch korrekt:
1 | void meineHashFunktion(char* buffer) { |
2 | while (*buffer != 0) { |
3 | char zeichen=*buffer; |
4 | // mach was mit dem zeichen |
5 | buffer++; |
6 | } |
7 | } |
8 | |
9 | void meineHashFunktion(char[] buffer) { |
10 | int i=0; |
11 | while (buffer[i] != 0) { |
12 | char zeichen=buffer[i]; |
13 | // mach was mit dem zeichen |
14 | i++; |
15 | } |
16 | } |
17 | |
18 | void meineHashFunktion(char[] buffer) { |
19 | while (*buffer != 0) { |
20 | char zeichen=*buffer; |
21 | // mach was mit dem zeichen |
22 | buffer++; |
23 | } |
24 | } |
25 | |
26 | void meineHashFunktion(char* buffer) { |
27 | int i=0; |
28 | while (buffer[i] != 0) { |
29 | char zeichen=buffer[i]; |
30 | // mach was mit dem zeichen |
31 | i++; |
32 | } |
33 | } |
Wobei die unteren beiden Beispiele natürlich nicht sehr elegant sind. Die Array Syntax (zeichen=buffer[i]) hat in der Wiederholschleife einen Vorteil: Sie weiß wie groß die Elemente des Arrays sind und verrechnet den Zeiger korrekt mit dem Index. Die Pointer Syntax (buffer++) geht stillschweigend davon aus, dass ein char ein byte groß ist und dass der Zeiger beim Incrementieren auf das nächste Byte Zeigt. Das sind gleich zwei Annahmen, die bei ungewöhnlicher Hardwarearchitektur nicht zutreffen könnten. Es könnte z.B. sein, dass der Speicher 32 Bit breit ist. Dann ergeben sich mehrere Möglichkeiten: a) Eine Speicherzelle kann 4 Zeichen speichern. Wenn das so genutzt wird, dann würde das Incrementieren des Zeigers nicht zum nächsten zeichen führen, sondern drei zeichen überspringen. b) Man könnte aber auch einfach nur 8 von den 32 Bit nutzen, dann klappt das Incrementieren wieder. c) Oder der Pointer zeigt beim Incrementieren gar nicht auf die nächste Reihe von 32 Bits, sondern bleibt in der gleichen Reihe und zeigt an, dass nun das zweite Bytes der Reihe gemeint ist. (Ich glaub' so läuft das auf PC's). d) Und was, wenn ein char gar nicht 8 bit Groß ist? Chinesen könnten 16 bit bevorzugen, selbst auf einem 8 bit Mikrocontroller. Dann müsste man den Pointer doppelt incrementieren. Da stellt sich mir die Frage, wie eigentlich mein Laptop Zeichen speichert. Viele Bits hat ein zeichen wirklich im Speicher, und hängt das vielleicht sogar von der Programmiersprache ab? Fragen über Fragen. Besser nutzt man die Array Syntax (zumindest innerhalb der Widerholschleifen), um Zeichenketten abzuarbeiten.
Stefan us schrieb: > Die Pointer Syntax (buffer++) geht stillschweigend davon aus, dass ein > char ein byte groß ist und dass der Zeiger beim Incrementieren auf das > nächste Byte Zeigt. Das sind gleich zwei Annahmen, die bei > ungewöhnlicher Hardwarearchitektur nicht zutreffen könnten. So ein quatsch! Auch in der Pointersyntax weiss der Compiler, wie gross ein char ist und ändert den Zeiger so dass er auf das nächste char zeigt.
Stefan us schrieb: > Viele Bits hat ein zeichen wirklich im Speicher Das lässt sich ganz leicht herausfinden:
1 | printf("%d bits", 8 * sizeof(char)); |
Stefan us schrieb: > Die Pointer Syntax (buffer++) geht stillschweigend davon aus, dass ein > char ein byte groß ist Komisch, bei double, int, stuct,... Arrays funktioniert das auch, sind die alle 8 bit groß?
:
Bearbeitet durch User
sizeof(char) ist per Definition 1 Allerdings sind 8 Bit nur die Mindestgröße für ein char. Wie groß ein char ist, kann man mit dem Makro CHAR_BIT feststellen.
1 | printf("%d bits", CHAR_BIT); |
Daher nutzt man Datentypen wie uint8_t um wirklich die Bitanzahl zu bekommen die man möchte.
Oh mein Gott! LERN GRUNDLAGEN! Mit UDP und MD5 rumspielen aber noch nicht mal die Grundlagen von Datentypen und Zuweisungen der Programmiersprache kennen. Das ist wie wenn man einem 6 Jährigen, der mit Sandförmchen spielt ein 6 Familien Haus bauen lassen will.
> Auch in der Pointersyntax weiss der Compiler, wie > gross ein char ist und ändert den Zeiger so dass er > auf das nächste char zeigt. Ich weiss, das das bei allen mir bekannten Mikrocontrollern und auch beim PC der Fall ist. Aber ist dieses verhalten auch wirklich standarisiert? Gilt es wirklich für jeden denkbaren Computer? Was passiert, wenn ein zeichen kleiner ist, als die kleinstmögliche Schrittweite der Pointer-Erhöhung (z.B. wenn das zeichen 8bit ist, die Speicherzellen jedoch 16bit)?
Stefan us schrieb: >> Auch in der Pointersyntax weiss der Compiler, wie >> gross ein char ist und ändert den Zeiger so dass er >> auf das nächste char zeigt. > > Ich weiss, das das bei allen mir bekannten Mikrocontrollern und auch > beim PC der Fall ist. > > Aber ist dieses verhalten auch wirklich standarisiert? Das sollte im C Standard so drin stehen. Ein größerer Schritt als nötig sollte nichts ausmachen, das merkt man nicht. Das verschwendet lediglich Speicher.
:
Bearbeitet durch User
Stefan us schrieb: > Aber ist dieses verhalten auch wirklich standarisiert? Ist es. > für jeden denkbaren Computer? Was passiert, wenn ein zeichen kleiner > ist, wäre denkbar. Nichts desto trotz muss dieses Zeichen ja im Speicher gespeichert werden können. Und dieser Speicher wird ja irgendwie ja adressiert. > als die kleinstmögliche Schrittweite der Pointer-Erhöhung (z.B. > wenn das zeichen 8bit ist, die Speicherzellen jedoch 16bit)? Dann muss sich der Compiler was einfallen lassen, wie er dieses Problem löst. Zum Beispiel indem er 16 Bit für ein char verschwendet. Zum Beispiel indem er 2 Zeichen in jede 16 Bit Speicherzelle packt und programmintern mit einer 8 Bit Adressierung rechnet, jeweils ein 16 Bit Wort aus dem Speicher holt und die nicht relevanten 8 Bits ausmaskiert und den Rest geeignet zurechtschiebt. Insbesondere letzteres muss ein Compiler sowieso können, der Code für eine Architektur produziert, bei der es Alignment-Restriktionen gibt von denen der Compilerbauer das Gefühl hat, dass er seinem Programmierer auch eine Möglichkeit anbieten will, sich davon zu befreien.
:
Bearbeitet durch User
Stefan us schrieb: > Die Pointer Syntax (buffer++) geht stillschweigend davon aus, dass ein > char ein byte groß ist und dass der Zeiger beim Incrementieren auf das > nächste Byte Zeigt. Das sind gleich zwei Annahmen, die bei > ungewöhnlicher Hardwarearchitektur nicht zutreffen könnten. Blödsinn. C setzt char mit Byte gleich. Es kann in C kein char geben, der nicht ein Byte groß ist. Definitionsgemäß.
Freddie schrieb: > Stefan us schrieb: >> Die Pointer Syntax (buffer++) geht stillschweigend davon aus, dass ein >> char ein byte groß ist und dass der Zeiger beim Incrementieren auf das >> nächste Byte Zeigt. Das sind gleich zwei Annahmen, die bei >> ungewöhnlicher Hardwarearchitektur nicht zutreffen könnten. > > Blödsinn. C setzt char mit Byte gleich. Es kann in C kein char geben, > der nicht ein Byte groß ist. Definitionsgemäß. Das ist Blödsinn. Ich hatte Prozessoren, da hatte jede Speicherzelle 16 Bit. Ein char hatte auch 16 Bit. Byteweise Adressierung gibt es da nicht. Alles 16 Bit. Schau die mal die TI 28xx Serie an. Wird hier öfter im DSP-Forum benutzt.
PittyJ schrieb: > Freddie schrieb: >> Stefan us schrieb: >>> Die Pointer Syntax (buffer++) geht stillschweigend davon aus, dass ein >>> char ein byte groß ist und dass der Zeiger beim Incrementieren auf das >>> nächste Byte Zeigt. Das sind gleich zwei Annahmen, die bei >>> ungewöhnlicher Hardwarearchitektur nicht zutreffen könnten. >> >> Blödsinn. C setzt char mit Byte gleich. Es kann in C kein char geben, >> der nicht ein Byte groß ist. Definitionsgemäß. > > Das ist Blödsinn. Ich hatte Prozessoren, da hatte jede Speicherzelle 16 > Bit. Ein char hatte auch 16 Bit. Byteweise Adressierung gibt es da > nicht. Alles 16 Bit. Vorsicht. Das was C unter einem Byte versteht ist nicht dasselbe was gemeinhin unter einem Byte verstanden wird. In C ist ein 'Byte' einfach nur die kleinste Einheit. Damit ist nicht gesagt, dass 1 Byte aus 8 Bit bestehen muss.
Okey danke für eure Antworten, allerdings reichte es die vergessene Null Termination für das char Array zu ergänzen. Nun hat sich schon das nächste Problem angekündigt:
1 | #include <SPI.h> |
2 | #include <Ethernet.h> |
3 | #include <EthernetUdp.h> |
4 | #include <MD5.h> |
5 | |
6 | |
7 | |
8 | //Variablen definieren:
|
9 | |
10 | int udppacket; |
11 | int packetbytes=0; |
12 | byte zahlhalter=0; |
13 | |
14 | |
15 | byte zaehler=0; |
16 | unsigned long clienttime=0; |
17 | |
18 | |
19 | //Verbindungseinstellungen
|
20 | |
21 | //Server
|
22 | byte servermac[] = { 0xDE, 0xAD, 0xCE, 0xEF, 0xFE, 0xEA }; //Generierte MAC-Adresse |
23 | IPAddress serverip(192, 168, 3, 1); //IP-Adresse |
24 | IPAddress serversubnet(255, 255, 255, 0); //Subnetzmaske |
25 | unsigned int serverport = 8001; //Serverport: Für alle weiteren Clientports gilt 800* |
26 | |
27 | |
28 | //Clients
|
29 | |
30 | IPAddress clientip(192, 168, 3, 2); //ClientIP |
31 | IPAddress clientsubnet(255, 255, 255, 0); //Subnetzmaske |
32 | unsigned int clientport=8002; //Clientport |
33 | |
34 | |
35 | char packetbuffer[UDP_TX_PACKET_MAX_SIZE]; //Bufferspeicher um Empfangene Pakete bis zur Bearbeitung zu speichern. |
36 | EthernetUDP Udp; //Beginnt eine UDP-Instanz |
37 | |
38 | |
39 | void setup() { |
40 | |
41 | //Starte Ethernet & UDP Libary
|
42 | Ethernet.begin(servermac,serverip,serversubnet); |
43 | Udp.begin(serverport); |
44 | Serial.begin(9600); |
45 | }
|
46 | |
47 | |
48 | void loop() { |
49 | |
50 | |
51 | int udppacket = Udp.parsePacket(); |
52 | if(udppacket){ |
53 | Serial.println(udppacket); |
54 | char zeitarray[udppacket+1]; //Die empfangenen Bytes werden in ein Array geschrieben, und dieses wird um 1 erhöht für die Null Terination. |
55 | Serial.println(udppacket+1); |
56 | |
57 | |
58 | |
59 | Udp.read(packetbuffer,UDP_TX_PACKET_MAX_SIZE); |
60 | Serial.println(packetbuffer); |
61 | |
62 | for(int i=0; i<udppacket; i++) { |
63 | |
64 | zeitarray[i]=packetbuffer[i]; |
65 | Serial.print("Empfangene Zeit:"); |
66 | Serial.println(packetbuffer[i]); |
67 | zaehler++; |
68 | }
|
69 | |
70 | |
71 | if(zaehler==udppacket){ |
72 | |
73 | |
74 | //generate the MD5 hash for our string
|
75 | unsigned char* hash=MD5::make_hash(zeitarray); |
76 | //generate the digest (hex encoding) of our hash
|
77 | char *md5str = MD5::make_digest(hash, 16); |
78 | free(hash); |
79 | Serial.println(md5str); |
80 | //Give the Memory back to the System if you run the md5 Hash generation in a loop
|
81 | free(md5str); |
82 | Serial.println(md5str); |
83 | zaehler=0; |
84 | }
|
85 | }
|
86 | }
|
Das empfangen etc. funktioniert problemlos es werden auch unterschiedliche Hashes generiert jedoch sind diese falsch. Ich nehme an es liegt an dieser Zeile:
1 | char zeitarray[udppacket+1]; //Die empfangenen Bytes werden in ein Array geschrieben, und dieses wird um 1 erhöht für die Null Terination. |
Hier wird das array definiert und als größe die empfangene Byteanzahl genommen, dann wird diese um 1 addiert um das Array zu terminieren..Stimmt daran etwas nicht?
An das Array wird ein Byte angehangen, um es zu terminieren. Das funktioniert nur, wenn in den Nutzdaten kein NULL Zeichen vorkommt. Außerdem darf die Hash Funktion dieses abschließende Zeichen natürlich nicht mit verrechnen. Ich fürchte, dass deine Nutzdaten ein Byte mit dem Wert 0 enthalten.
Ja, das stimmt in den übertragenen Daten (Millis-Zeit des Clients) kommen 0en vor. Was kann man dagegen tun?
Ich habe das gerade ausgetestet,in diesem Array ist keine 0 und es funktioniert trotzdem nicht.
1 | |
2 | #include <SPI.h> |
3 | #include <Ethernet.h> |
4 | #include <EthernetUdp.h> |
5 | #include <MD5.h> |
6 | |
7 | char zeitarray[6]={'1','2','3','4','5','6'}; |
8 | int test=6; |
9 | |
10 | void setup() { |
11 | |
12 | Serial.begin(9600); |
13 | char zeitarray[test+1]; |
14 | |
15 | |
16 | //generate the MD5 hash for our string
|
17 | unsigned char* hash=MD5::make_hash(zeitarray); |
18 | //generate the digest (hex encoding) of our hash
|
19 | char *md5str = MD5::make_digest(hash, 16); |
20 | free(hash); |
21 | //print it on our serial monitor
|
22 | Serial.println(md5str); |
23 | //Give the Memory back to the System if you run the md5 Hash generation in a loop
|
24 | free(md5str); |
25 | Serial.println(md5str); |
26 | |
27 | |
28 | |
29 | }
|
30 | |
31 | void loop() { |
32 | |
33 | }
|
Paul schrieb: > in diesem Array ist keine 0 und es > funktioniert trotzdem nicht. Vllt. weil in dem Array gar nichts ist, bzw. nur das was davor in den Speicherzellen stand steht. Wenn du eine globale Variable innerhalb einer Funktion noch mal deklarierst, wird diese neu auf dem Stack angelegt und die globale ist in der Funktion nicht sichtbar.
:
Bearbeitet durch User
Paul schrieb: > char zeitarray[test+1]; und dass lässt sich compilieren?? Wenn Du den dem Hinweis von Max beachtest wird danach der nächste Fehler auftauchen: du vorher erwähnt hast dass der String null-terminiert sein muss, es jetzt aber nicht ist Tipp: Grundlagen lernen
Walter S. schrieb: > Tipp: Grundlagen lernen Spinnst du? Ich habe mit den Noobduino gekauft weil ich das nicht will.
Paul schrieb: > Ich habe das gerade ausgetestet,in diesem Array ist keine 0 und es > funktioniert trotzdem nicht. > Das hier > char zeitarray[6]={'1','2','3','4','5','6'}; ist ja wieder nicht 0-terminiert! Sorry, wenn ich das so sage. Aber wenn diese Funktion hier > unsigned char* hash=MD5::make_hash(zeitarray); einen String haben will, dann musst du ihr auch einen String geben. Wenn in deinen zu verhashenden Daten ein Byte mit dem binären Wert 0 vorkommen kann, dann hast du eben keinen C-String mehr und du kannst diese Funktion nicht benutzen. So einfach ist das. Die Leute haben schon recht damit, wenn sie sagen, dass es ohne Grundlagen einfach nicht geht. Ein C-String hat genau definierte und bestimmte Eigenschaften. Kannst du die nicht erfüllen, dann hast du keinen C-String und kannst auch keine Funktionen benutzen, die von einem C-String ausgehen.
:
Bearbeitet durch User
Ok, ich habe mich mal eingelesen und übe die Grundlagen. Ein char-Dateityp ist also (meist?) mit 1 Byte Speichergröße definiert und hat einen Wertebereich von -128 bis 127 (also insgesamt 255 wie byte) und kann einen Buchstaben oder Zahlen von -128 bis 127 speichern. Ein String ist entweder eine eigener Dateityp oder eine Zeichenkette in einem Dateityp z.B. in einem char? Kann man einem char Array einfach eine Zahl mitgeben? Also:
1 | char test[1] |
2 | test[0]=1; |
Das Array test wurde mit der Größe zwei erstellt (0,1) wenn ich nur 0 befülle ist dieses Null-Terminiert. Liege ich richtig?
Paul schrieb: > Liege ich richtig? nein. Ein char[1] ist nur ein Array mit einem element. > Ein char-Dateityp ist also (meist?) mit 1 Byte Speichergröße definiert > und hat einen Wertebereich von -128 bis 127 (also insgesamt 255 wie > byte) und kann einen Buchstaben oder Zahlen von -128 bis 127 speichern. nein. ein char kann je Einstellung vom Compiler 0-255 oder -128 - 127 gehen.
Ich dachte Arrays sid generell zero-indexed, liege ich da falsch? Achso ok, danke.
Ah ok, Fehler bemerkt auch wenn das Array[1] ist, beginnt dieses bei 0.
Peter II schrieb: > nein. ein char kann je Einstellung vom Compiler 0-255 oder -128 - 127 > gehen. eben und das verstehe ich immer noch nicht weil -char keinen Sinn ergibt, manche Compiler auf unsigned char bestehen was aber Unsinn ist, besser verständlich finde ich uint8_ und int8_t und was ist mit dem ASCII Code der nur 7-bit kennt Paul schrieb: > Ah ok, Fehler bemerkt auch wenn das Array[1] ist, beginnt dieses bei 0. stimmt doch eine Var im Array Länge 1 Index 0
Joachim B. schrieb: > eben und das verstehe ich immer noch nicht weil -char keinen Sinn > ergibt, manche Compiler auf unsigned char bestehen was aber Unsinn ist, > besser verständlich finde ich uint8_ und int8_t und was ist mit dem > ASCII Code der nur 7-bit kennt es spielt doch keine rolle welche zahlen man ein char speichern kann. char ist für Buchstaben. char c = 'x' ob es nun unsigned oder signed ist spielt dafür kein rolle. Wenn man zahlen braucht, nimmt man kein char.
Peter II schrieb: > Wenn man zahlen braucht, nimmt man kein char. Wieso nicht? Ich verwende immer char wenn wenn ich nur kleine Zahlen brauche.
Max H. schrieb: >> Wenn man zahlen braucht, nimmt man kein char. > Wieso nicht? Ich verwende immer char wenn wenn ich nur kleine Zahlen > brauche. wenn die Zahlen < 128 sind ist es ja ok. Wenn du bis 256 brauchst dann ist char falsch denn es ist nicht festgelegt ob es signed oder unsigned ist.
Peter II schrieb: > ob es nun unsigned oder signed ist spielt dafür kein rolle. > > Wenn man zahlen braucht, nimmt man kein char. wo steht das denn? warum soll ich für Zahlen im Bereich 0-255 ein int oder uint reservieren, unter der Voraussetzung das die meisten int/uint als 16 Bit betrachten. Beim MC oder PC ist das sowas von Speicherplatzverschwendung. Nun kommt mir nicht mit Speicher ist egal, warum müssen denn die PC immer jedes Jahr um GHz oder Core wachsen wenn wir heute immer noch dieselben Briefe schreiben oder eine simple Tablle bearbeiten wie anno 1990. Wir sind doch mit dem üppigen Umgang von Speicher selbst Schuld wenn wir alle Nase lang neue Platten brauchen und uns DSL768 nicht mehr schnell genug ist, bzw. uns klicki bunti Browser mit animierter Werbung volllabern wo wir eigentlich nur im forum lesen wollen, OK ab und an mal ein Bild dazu aber was machen wir? ohne Denken mal eben 12MB aus dem Handy einstellen mit Informationsgehalt vom analog TV 320*240 Pix
Joachim B. schrieb: > wo steht das denn? > > warum soll ich für Zahlen im Bereich 0-255 ein int oder uint > reservieren, unter der Voraussetzung das die meisten int/uint als 16 Bit > betrachten. wer sagt das? für zahlen nimmt man unsigend char oder signed char für Text nimmt man char
Peter II schrieb: > nein. ein char kann je Einstellung vom Compiler 0-255 oder -128 - 127 > gehen. Der Standard verlangt mindestens 0-255 für unsigned char und -127 bis 127 für signed char. Es darf auch mehr sein. Auch mehr an Bits.
Dirk B. schrieb: > Der Standard verlangt mindestens 0-255 für unsigned char und -127 bis > 127 > für signed char. richtig, es hat auch niemand was anders behauptet. Es geht um char und hier weiß man erst mal nicht ob es signed oder unsigned ist damit kann man nicht einfach 190 drin speichern.
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.