Hallo Nachdem ich bisher nur Assembler programmiert habe, mache ich grade meine ersten Versuche mit C. Mein Experimentier-System besteht aus einem AT90S8515 mit akkugepuffertem externem 32k-SRam. Das SRam liegt im Speicherbereich $8000-$FFFF und lässt sich über einen Zeiger ansprechen. Leider ist es so, das einige Speicherinhalte beim Ein- bzw. Ausschalten verändert werden. Um der sache auf den Grund zu gehen wollte ich mir zuerst mal eine Funktion erstellen, die den Inhalt des SRams überprüft und mir die fehlerhaften Adressen und deren Inhalte via RS232 zum PC sendet. Mein Problem ist nun folgendes. Ich möchte den Inhalt des Zeigers, also die Adresse auf die er grade zeigt via RS232 zum PC übertragen. Dazu muss ich diesen 2 Byte Zeiger aber auf 2 einzelne Bytes aufteilen um sie nacheinander übertragen zu können. Und genau daran bin ich bisher gescheitert. Ich bekomme entweder Warnungen wegen fehlendem Typecasting oder unterschiedlicher Variablenlängen. Mittlerweile habe ich da schon Stunden dran rumgetippt. Ohne Erfolg :( Wie kann ich den Inhalt dieses 2 Byte Zeigers auf 2 einzelne uint8_t Variablen aufteilen, so das ich Hi und Lo Byte der Adresse einzeln habe.
Gast
#3745552
uint16_t* p16; uint8_t* p8; uint8_t high, low; p16 = deine_speicheradresse; p8 = p16; // Bytezeiger zeigt auf gleiche Adresse wie Wordzeiger memcpy(p8, &high, 1); // ein Byte von der Adresse auf die p8 zeigt in die Variable high kopieren p8++; // Zeiger ein Byte weiter memcpy(p8, &low, 1);
Gast
#3745558
Thorsten schrieb: > p16 = deine_speicheradresse; > p8 = p16; // Bytezeiger zeigt auf gleiche Adresse wie Wordzeiger > > memcpy(p8, &high, 1); // ein Byte von der Adresse auf die p8 zeigt in > die Variable high kopieren > p8++; // Zeiger ein Byte weiter > memcpy(p8, &low, 1); naja nicht wirklich schön, dann ist es abhängig von der Platform in welcher Reihenfolge die Bytes kommen. p16 = deine_speicheradresse; uint8_t low = p16 & 0xff; uint8_t high = p16>>8 & 0xff;
Gast
#3745570
Der Atmel-Assembler hat dafür ein paar vordefinierte Schlüsselwörter.
Gast
#3745586
Hab mal nachgehen: http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_expressions.html#avrassembler.wb_expressions.Operands Am Ende der Seite.
Gast
#3745602
Amateur schrieb: > Der Atmel-Assembler hat dafür ein paar vordefinierte Schlüsselwörter. er will aber weg von ASM hin zu C.
Hans Imglück schrieb: > Wie kann ich den Inhalt dieses 2 Byte Zeigers auf 2 einzelne uint8_t > Variablen aufteilen, so das ich Hi und Lo Byte der Adresse einzeln habe.
1 | |
2 | |
3 | |
Oliver
Gast
#3746074
Oliver S. schrieb: > Hans Imglück schrieb: >> Wie kann ich den Inhalt dieses 2 Byte Zeigers auf 2 einzelne uint8_t >> Variablen aufteilen, so das ich Hi und Lo Byte der Adresse einzeln habe. > >
1 | |
2 | |
3 | |
4 | |
> > Oliver Wollen wir die Richtung der '<<' nochmal überdenken? ;-)
;) Oliver
Gast
#3746135
Das volatile ist auch unnötig.
1 | |
2 | |
3 | |
Gast
#3746142
Hans schrieb: > Das volatile ist auch unnötig. > >
1 | |
2 | |
3 | |
Wollen wir die casts noch einmal überdenken? ;-)
Norbert schrieb: > Hans schrieb: >> Das volatile ist auch unnötig. >> >>
1 | |
2 | |
3 | |
> > Wollen wir die casts noch einmal überdenken? ;-) Done. Sind in Ordnung, solange sizeof(void*) gleich 2 ist.
Gast
#3746191
norbert@Entwicklung:/tmp$ gcc -Wall -Wextra -Wconversion -o x x.c x.c: In function ‘main’: x.c:16:15: warning: conversion to ‘uint8_t’ from ‘long unsigned int’ may alter its value [-Wconversion] x.c:18:28: warning: conversion to ‘uint8_t’ from ‘long unsigned int’ may alter its value [-Wconversion] ‘long unsigned int’ nur weil ich's gerade auf 'nem 64bit System getrieben habe. Sonst wär's wahrscheinlich ‘unsigned int’. Bezgl. -Wconversion: Hat der gcc früher (seinerzeit, zu meiner Zeit also einer schlimmen Zeit) per default bei -Wall gemacht, heute muß man es explizit angeben. Würde mich interessieren welcher Weltmeister auf die Idee gekommen ist, die Warnungen in neueren Versionen schlapper zu machen. /* Kreuzzug für Warnungsfreie Compilerläufe ;-) */
Gast
#3746198
Ach so, so geht's ohne Schlag auf den Hinterkopf vom compiler:
lowbyte = (uint8_t)(uint64_t)p;
highbyte = (uint8_t)((uint64_t)p >> 8);
bzw. auf einem 16bit System (ungetestet):
lowbyte = (uint8_t)(uint16_t)p;
highbyte = (uint8_t)((uint16_t)p >> 8);
Gast
#3746223
Die Warnung dürfte auch weggehen, wenn man noch mit 0xFF verodert, oder? Das fände ich dann die schönere Variante, weils dann auch funktioniert, wenn der Datentyp auf der linken Seite mehr als 8 Bit hat.
1 | |
2 | |
3 | |
Hans schrieb: > Die Warnung dürfte auch weggehen, wenn man noch mit 0xFF verodert, oder? Nö. Nur weil du mit irgendwas veroderst wird aus einem 16 Bit Wert nicht irgendwie magisch ein 8 Bit Wert.
Gast
#3746255
Hans schrieb: > Die Warnung dürfte auch weggehen, wenn man noch mit 0xFF verodert, oder? > Das fände ich dann die schönere Variante, weils dann auch funktioniert, > wenn der Datentyp auf der linken Seite mehr als 8 Bit hat. > >
1 | |
2 | |
3 | |
Nö, das klappt nicht. Nach p and 0xff bleibt der Ausdruck uint16_t. Sauber ist es erst, wenn ein cast aus dem 16bit breiten Zeiger einen 16bit breiten uint16_t macht. Dann fummelt man sich das passende Byte heraus (das ist jetzt immer noch 16 bit breit) und castet das dann auf 8bit.
Gast
#3746303
Karl Heinz schrieb: > Nur weil du mit irgendwas veroderst wird aus einem 16 Bit Wert nicht > irgendwie magisch ein 8 Bit Wert. Das nicht, aber der Wert geht dann sicher in 8 Bit, daher kein "may alter its value" mehr. Gerade probiert:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
Compiliert ohne Warnungen:
1 | |
2 | |
3 | |
4 | |
P.S.: Es muss natürliche eine bitweise Verundung sein ...
Hans schrieb: > Karl Heinz schrieb: >> Nur weil du mit irgendwas veroderst wird aus einem 16 Bit Wert nicht >> irgendwie magisch ein 8 Bit Wert. > > Das nicht, aber der Wert geht dann sicher in 8 Bit, daher kein "may > alter its value" mehr. > > Gerade probiert: Interessant. Das hätte ich jetzt nicht gedacht, dass der gcc das bei der Generierung der Warnung ins Kalkül zieht. Wieder was gelernt. Danke.
Gast
#3746334
Fand ich auch interessant, jetzt geht's aber noch weiter:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
x.c:18:44: warning: conversion to ‘uint8_t’ from ‘long unsigned int’ may alter its value [-Wconversion] In Zeile 17 stellt der Compiler mit absoluter Sicherheit fest, das der Ausdruck auf der rechten Seite nur 8bit breit sein kann. KEINE Warnung. In Zeile 18 wird der gleiche Ausdruck (8bit) mit einem anderen 8bit Wert ODER verknüpft. Jetzt gibt's wieder die Warnung. Versteh's wer will...
Gast
#3746384
Norbert schrieb: > In Zeile 17 stellt der Compiler mit absoluter Sicherheit fest, das der > Ausdruck auf der rechten Seite nur 8bit breit sein kann. KEINE Warnung. > > In Zeile 18 wird der gleiche Ausdruck (8bit) mit einem anderen 8bit Wert > ODER verknüpft. Jetzt gibt's wieder die Warnung. > > Versteh's wer will... Finde ich jetzt nicht so merkwürdig. Er prüft halt innerhalb eines Ausdrucks, ob der Wertebereich überschritten wird, aber wenn Variablen hinzugezogen werden, geht er halt nicht deren ganze Entstehungsgeschiche zurück, um festzustellen, welchen Wertebereich die überhaupt haben können. An der Stelle ist lowbyte halt einfach ein uint64_t und damit potenziell zu groß.
Gast
#3746446
Rolf Magnus schrieb: > Finde ich jetzt nicht so merkwürdig. Er prüft halt innerhalb eines > Ausdrucks, ob der Wertebereich überschritten wird, aber wenn Variablen > hinzugezogen werden, geht er halt nicht deren ganze Entstehungsgeschiche > zurück, um festzustellen, welchen Wertebereich die überhaupt haben > können. > An der Stelle ist lowbyte halt einfach ein uint64_t und damit potenziell > zu groß. Ja, ok, ist jetzt kein Showstopper. Wenn man es wie gehabt ordentlich castet ist es ja auch einwandfrei. Ich wunderte mich auch nur über die etwas eigentümliche Generierung von Warnungen. Was meiner Meinung nach viel schlimmer ist:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
So etwas generiert beim gcc heutzutage trotz "-Wall -Wextra" keinerlei Warnungen, das ist doch nicht gesund. Ich weiss ja nicht wann man das beim gcc rausgenommen hat, aber vor einiger Zeit gab's für solch einen Sourcecode noch die Kelle vom Compiler.
Wenn einen die Warnungen stören kann man Casts dazu tun:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
Gast
#3746526
Johann L. schrieb: > Wenn einen die Warnungen stören kann man Casts dazu tun: Da waren wir aber schon um 18:49h ;-) Die Frage ist eher, warum generiert der Compiler keine Warnungen bei wirklich üblen Dingen? (siehe 21:48h) Früher tat er das jedoch. (Wenn ich mich recht erinnere)
Gast
#3746551
Norbert schrieb: > Die Frage ist eher, warum generiert der Compiler keine Warnungen bei > wirklich üblen Dingen? (siehe 21:48h) Wahrscheinlich weil es in normalem Code ständig vorkommt. Genau wie Zuweisungen und Vergleiche zwischen signed und unsigned. Da jedes Mal explizit casten zu müssen ist auch nicht optimal. Imo sollten Casts nur bei "ungewöhnlichen" Typumwandlungen wie hier zwischen Zeiger und Integer oder Zeigern verschiedenen Typs nötig sein und nicht bei impliziten Umwandlungen wie Integern verschiedener Breite. Denn wenn man sich deshalb notgedrungen angewöhnt, bei jeder Zuweisung zu casten, dann verliert irgendwann das Typsystem seine Wirkung, da man die wirklichen Fehler nicht mehr sieht. Klar, mit viel Disziplin kann man den Großteil vermeiden. Wenn man viel mit fremden Code zu tun hat, ists aber leider nicht immer so einfach machbar.
Hallo Das ging ja flott. Ich habs mal mit der Lösung von Peter II probiert. Hat auch fast auf Anhieb gefunzt. Aber ohne Typcasting gabs trotzdem noch ne Warnung. Mit den Zeilen unten gehts ohne Warnungen, und funtionieren tuts auch :) Danke an alle. //-------------------------------------------------------------------- #define EXRAM_START 0x8000 // Externes Ram. Anfangsadresse // Globale Variable uint8_t *ramadr = NULL; // Zeiger auf EX-Ram Adresse uint8_t high, low; ramadr = (uint8_t*) EXRAM_START; low = (uint16_t)ramadr & 0xff; high = (uint16_t)ramadr>>8 & 0xff;
Gast
#3746612
Hans schrieb: > Wahrscheinlich weil es in normalem Code ständig vorkommt. Genau wie > Zuweisungen und Vergleiche zwischen signed und unsigned. Da jedes Mal > explizit casten zu müssen ist auch nicht optimal. > > Imo sollten Casts nur bei "ungewöhnlichen" Typumwandlungen wie hier > zwischen Zeiger und Integer oder Zeigern verschiedenen Typs nötig sein > und nicht bei impliziten Umwandlungen wie Integern verschiedener Breite. > Denn wenn man sich deshalb notgedrungen angewöhnt, bei jeder Zuweisung > zu casten, dann verliert irgendwann das Typsystem seine Wirkung, da man > die wirklichen Fehler nicht mehr sieht. > > Klar, mit viel Disziplin kann man den Großteil vermeiden. Wenn man viel > mit fremden Code zu tun hat, ists aber leider nicht immer so einfach > machbar. OK, ich präzisiere noch einmal: Wenn ich dem gcc mit den Optionen -Wall -Wextra meinem Wunsch nach Warnungen bei schlampiger Programmierung Ausdruck verleihe, dann will ich bei Zuweisungen wie zB. int16_t -> uint16_t und ähnlichen fragwürdigen Konstrukten gewarnt werden. Sollte das hin- und herhüpfen zwischen verschiedenen Typen tatsächlich gewollt sein, dann caste ich. Wenn ich jedoch diese Art der Programmierung ohne explizite casts irrtümlicherweise für sauber und akzeptabel halte, so kann ich jederzeit die entsprechenden Warnungen abschalten. Aber -Wall -Wextra ist meines Erachtens nach ein ziemlich unmissverständlicher Wunsch nach Informationen. Wie gesagt, früher wurde man vom gcc bei so etwas gewarnt.
Norbert schrieb: > Johann L. schrieb: >> Wenn einen die Warnungen stören kann man Casts dazu tun: > > Da waren wir aber schon um 18:49h ;-) Ja, allerdings war Deine Version wesentlich "unportabler". Du hattest noch den Code unterschieden, ob er für ein 64- oder 16-Bit-System zu compilieren ist. Als ich das eben las, schoss mir direkt in den Kopf, dass Dein uint64_t- bzw. uint16_t-Cast ja genau die "natürliche Breite" des Zielsystems trifft. Genau dort wäre ein uint-Pointer-Cast ohne Angabe der Bitbreite das einzig sinnvolle gewesen... was dann Johann auch gemacht hat. ;-)
Gast
#3746842
Frank M. schrieb: > Ja, allerdings war Deine Version wesentlich "unportabler". Allerdings ging es bei der Fragestellung nicht im Geringsten um Portabilität, sondern um Warnungen wenn keine casts eingesetzt werden. ...und darauf bezogen sich alle von den verschiedenen Postern bisher geschriebenen Beispiele. Der Portabilitätsaspekt ist erst viel später eingeführt worden um das Thema zu verwässern und vom eigentlichen Problem abzulenken. ;-)
Gast
#3746853
Um es vielleicht noch einmal von der 'anderen' Seite zu beleuchten: Die Einführung von (uintptr_t) um verschiedene Pointerbreiten zu unterstützen hilft bei der Aufgabenstellung des Themenerstellers nicht im Geringsten. Dann müsste nämlich auch noch eine Überprüfung der Pointerbreite stattfinden, die Aufteilung nicht nur in Lo/Hi Byte (16bit) sondern vielleicht in Lo/Hi/VeryHi/ExtremelyHi (32bit) sowie deren Äquivalente für alles >32bit Breite - das spar' ich mir hier mal - stattfinden. Darum ging es hier aber nicht!
Um Warnungen ging's ja auch nicht. -Wall -Wextra aktiviert nicht alle Warnungen, und manche Warnungen können vom Optimierungsgrad abhängen (selten) weil ohne diese die entsprechenden Analysen nicht durchgeführt werden weil die teuer sind. Ein Beispiel ist VRP. Eine Übersicht über GCC-Warnungen ewrhälst du mit gcc --help=warnings Eine Auflistung, was in Sammel-Optionen wie -Wall enthalten ist, kann dem Handbuch entnommen werden: GCC-Manual → GCC Command Options → Options to Request or Suppress Warnings
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.