PROZESSOR = 18F87K90
Microchip C18 Compiler.
char i_help;
union reg
{
char data;
struct
{
char ek : 2; //Elektrodenkontrolle
char sprache : 1; //Sprachauswahl
char TK : 1;
char Temp_Sens : 1;
char rx_enable : 1;
char RT2025 : 1;
char calfail : 1;
};
};
union reg reg0;
reg0.ek = 0x00; // Geht
reg0.ek = 0x01; // Geht
reg0.ek = 0x02; // Geht nicht richtig
reg0.ek = 0x03; // Geht nicht richtig
switch (reg0.ek) {
case 0x00 : Do1; // Geht
break;
case 0x01 : Do2; // Get
break;
case 0x02 : Do3; // Get nicht
break;
case 0x03 : Do4; // Get nicht
break;
default : DoMist; // Hier lande ich bei 0x02 und 0x03
break;
}
So nun hab ich folgendes kleines Problem. Wieso geht das nicht ??
reg0.ek ist ja 2 Bit breit, womit es insgesammt 4 zustände annehmen
kann.
Ich kenn jedoch nur die zustände 0x00 und 0x01 auswerten, 0x02 und 0x03
bekomme ich nie ausgewertet.
Wenn ich reg0.ek einen anderen wert als 0x00 oder 0x01 zuweise, lnde ich
immer in DoMist.
Habe ich irgendwo einen Denkfehler?
Der Debugger meldet mir in reg0.ek immer den richtigen wert.
duck&wech schrieb:> Charakter mit Vorzeichen habe ich sowieso noch nie gesehen ...
Es kommt immer darauf an wie das der Compiler sieht.
Ich hatte mal das Problem das ein Microsoft Visual C++
Programm immer dann gecrasht ist, wenn aus einer Datei
ein ß gelesen und an isdigit gefüttert wurde.
char c = '▀'; // 0xDF
isdigit(c); // crash
Ursache: Übergabeparameter wird von signed char auf int erweitert.
Workaround:
isdigit((unsigned char)c);
Ich hatte auch bisher immer gedacht das ein Char kein vorzeichen hatt.
bei C18 ist das aber anscheinend anders.
http://www.sprut.de/electronic/pic/c/pic_c/pic_c20_variablen.html
Der post oben drüber bezieht sich darauf, dass ich i_help den wert von
reg0.ek zuweise. Danach dürfte i 0x00, 0x01, xFF oder 0xFE haben.
Jdelphi schrieb:> Der post oben drüber bezieht sich darauf, dass ich i_help den wert von> reg0.ek zuweise. Danach dürfte i 0x00, 0x01, xFF oder 0xFE haben.
Besser (anschaulicher) :
-2,-1,0 und 1.
Jdelphi schrieb:> Ich hatte auch bisher immer gedacht das ein Char kein vorzeichen hatt.
Das ist in C nicht festgelegt und wird der jeweiligen Implementierung
überlassen.
Darum ist es zb extrem wichtig, dass man sich die Sichtweisen aneignet:
char für Textverarbeitung
signed char für alle Berechnungen mit kleinen Zahlen
mit Vorzeichen
unsigned char für alle Berechnungen mit kleinen Zahlen
ohne Vorzeichen
Am besten fährt man, wenn man es sich zur Gewohnheit macht, zwischen
diesen 3(!) Datentypen streng zu unterscheiden. char ist ausschliesslich
für Zeichenverarbeitung reserviert und wenn man mit Bytes operiert, dann
ist unsigned char der richtige Datentyp. Alles andere führt über kurz
oder lang immer irgendwann zu Problemen. Und sei es nur bei
automatischen Datetyperweiterungen (Integer Promotions), wenn ein char
laut Standard-C-Regeln zu einem int aufgeblasen werden muss.
Karl Heinz Buchegger schrieb:> Am besten fährt man, wenn man es sich zur Gewohnheit macht, zwischen> diesen 3(!) Datentypen streng zu unterscheiden.
Blöd ist nur, wenn man Protokolle hat, die Text und Daten enthalten (was
in der Regel der Fall ist).
Bei unsigned char meckert der GCC, wenn man es als Text parst.
Bei char wird nicht gemeckert, aber dann geht das Daten auslesen schief,
da char nach signed int expandiert.
Wie kann man nur auf die blöde Idee kommen, daß es negativen Text gibt.
Die C-Entwickler haben einem damit ein ganz schönes Ei ins Nest gelegt,
das jeder Programmierer ausbaden muß und sich dumm und dämlich castet.
Ich bin darauf auch schon reingefallen.
Am saubersten wäre es, Datenströme immer als unsigned zu definieren und
dem GCC das Meckern darüber abschalten zu können.
Peter
Peter Dannegger schrieb:> Wie kann man nur auf die blöde Idee kommen, daß es negativen Text gibt.
Anno 1970 gab es nur positiven Text, weil der ASCII-Zeichensatz nur die
Werte 0-127 kennt. Umlaute hatten die Amerikaner nicht auf der Rechnung.
> Die C-Entwickler haben einem damit ein ganz schönes Ei ins Nest gelegt
Genau genommen waren es nicht die C-Entwickler, sondern DEC.
Damals brachte DEC die PDP-11 raus, deren Bytebefehle die Daten vor der
Rechnung vorzeichenbehaftet nach 16 Bits konvertiert und dann
verarbeitet. Wem da ein gewisser Zusammenhang mit der Definition von C
auffällt: Auf solchen Maschinen hat Unix seine Kindheit verbracht, und
damit auch C. Vorzeichenlos wäre Zeichenverarbeitung weniger effizient
gewesen.
Und weil viele sich daran gewöhnt hatten, dass "char" vorzeichenbehaftet
ist, hat man das so fortgesetzt und viele Compiler machen das auch heute
noch so. Nicht selten umschaltbar.
A. K. schrieb:>> Die C-Entwickler haben einem damit ein ganz schönes Ei ins Nest gelegt>> Genau genommen waren es nicht die C-Entwickler, sondern DEC.>> Damals brachte DEC die PDP-11 raus, deren Bytebefehle die Daten vor der> Rechnung vorzeichenbehaftet nach 16 Bits konvertiert und dann> verarbeitet. Wem da ein gewisser Zusammenhang mit der Definition von C> auffällt: Auf solchen Maschinen hat Unix seine Kindheit verbracht, und> damit auch C. Vorzeichenlos wäre Zeichenverarbeitung weniger effizient> gewesen.
Interessante Anekdote. Das wusste ich bisher gar nicht. Dank dafür.
Aber Peter hat schon recht. Da ist wohl jeder im Laufe seiner Laufbahn
ein paar mal reingefallen. Und aus Erfahrung weiß ich: Bei sowas suchst
du dich dumm und dämlich.
if( c == 212 )
der Debugger zeigt dir c in hex an, 0xD4 ist 212, und du denkst die
ganze Zeit: verdammt, das Bitmuster stimmt. Warum schlägt der Vergleich
nicht an!
DirkB schrieb:> Wie wird das denn bei IBM mit EBCDIC gelöst?
Bloss weil DEC bei der PDP-11 die Byteverarbeitung so implementierte,
dass man Reste davon noch heute in C wiederfindet, musste IBM das Jahre
zuvor ja nicht auch so machen.
Und ja, die IBMs 360/370er wurden nicht mit C behelligt, sondern
hauptsächlich mit Fortran, Cobol und viel Assembler. Oder PL/I. Die
Besonderheit an C ist die Einstufung von Einzelzeichen als Zahlenwerte,
also "char" als kleiner Integer. Das ist in anderen Sprachen
ungebräuchlich. Ohne dies hat man das Problem nicht.
Peter Dannegger schrieb:> Blöd ist nur, wenn man Protokolle hat, die Text und Daten enthalten (was> in der Regel der Fall ist).
Dafür haben die C-Götter den typecast erfunden.
Den muss man bei Texten dann typischerweise zweimal benutzen: jeweils
an der Import- und an der Export-Schnittstelle, also bspw.
marcus6100 schrieb:> Ich hatte mal das Problem das ein Microsoft Visual C++> Programm immer dann gecrasht ist, wenn aus einer Datei> ein ß gelesen und an isdigit gefüttert wurde.>>> char c = '▀'; // 0xDF> isdigit(c); // crash>> Ursache: Übergabeparameter wird von signed char auf int erweitert.>> Workaround:> isdigit((unsigned char)c);
Das ist kein Workarund, sondern der von C so vorgesehene Weg, auch wenn
das wirklich blöd ist.
Die ISO-Norm sagt zu allen Funktionen, die mit einzelnen Zeichen
arbeiten:
************************************************************************
******
The header <ctype.h> declares several functions useful for classifying
and mapping characters. In all cases the argument is an int, the value
of which shall
be representable as an unsigned char or shall equal the value of the
macro EOF. If
the argument has any other value, the behavior is undefined.
************************************************************************
******
Das Verhalten des Compilers ist also korrekt.
Jdelphi schrieb:> Ich hatte auch bisher immer gedacht das ein Char kein vorzeichen hatt.> bei C18 ist das aber anscheinend anders.
Eigentlich haben sie meistens eins. ISO C läßt dem Compiler hier die
Wahl, aber mit Vorzeichen ist eigentlich sinnvoller, da ja auch alle
anderen Integer-Typen ein Vorzeichen haben, wenn weder signed noch
unsigned davorsteht.
Peter Dannegger schrieb:> Wie kann man nur auf die blöde Idee kommen, daß es negativen Text gibt.
Aber positiven? Es gibt bei Text schlicht und ergreifend kein Konzept
"vorzeichenlos oder vorzeichenbehaftet". Es ist einfach Text, und da man
mit Text nicht rechnet, ist die "Vorzeichenbehaftetheit" des
dahinterstehenden Datentyps egal.
> Die C-Entwickler haben einem damit ein ganz schönes Ei ins Nest gelegt,> das jeder Programmierer ausbaden muß und sich dumm und dämlich castet.
Das ist aber doch in den meisten Sprachen so. In vielen anderen Sprachen
kann man mit dem Zeichentyp halt nur nicht direkt rechnen, aber wenn ich
rohe Bytes habe, muß ich die eigentlich in so gut wie jeder Sprache
erstmal konvertieren, um sie als Text nutzen zu können. Das mußt du in C
halt auch...