Der Typ "int" kann nicht implizit in "byte" konvertiert werden. Es ist
bereits eine explizite Konvertierung vorhanden. (Möglicherweise fehlt
eine Umwandlung.) (CS0266) - \DIO_setzen.cs:20,47
Dieser Fehler kommt, wenn ich die MAske mit dem Modulstatus verknüpfen
möchte (sowohl | als auch &~)
Mit dem Convert-Befehl habe ich schon einiges probiert, aber leider
kommen da nur andere Fehler. Ein Byte sind doch 8 Bit und meine Maske
hat 32 Bit, also 4 Byte. Wieso kann man 4 Byte nicht mit einem Byte
maskieren?
Das liegt an c#. Normalerweise mag ich dir Sprache, aber hier wurde echt
Mist gebaut. Alle logischen Operatoren sind nur in Int definiert (glaub
ich aufjedenfall). Deswegen gibt er dir auch ein Int zurück. Um die das
Ergebnis nun nach byte zu konvertieren musst du den ganzen Block in eine
Klammer schreiben (hast du ja schon gemacht) und davor den Cast nach
byte setzen.
freundlicher gast schrieb:> Der Typ "int" kann nicht implizit in "byte" konvertiert werden. Es ist> bereits eine explizite Konvertierung vorhanden. (Möglicherweise fehlt> eine Umwandlung.) (CS0266) - \DIO_setzen.cs:20,47
Ich gehe mal davon aus Du redest hier von Code in C#?
> Dieser Fehler kommt, wenn ich die MAske mit dem Modulstatus verknüpfen> möchte (sowohl | als auch &~)
Tja, im Zweifel hat der Compiler bei sowas Recht.
"Modulstatus" ist vermutlich byte oder sowas?
> Mit dem Convert-Befehl habe ich schon einiges probiert, aber leider> kommen da nur andere Fehler. Ein Byte sind doch 8 Bit und meine Maske> hat 32 Bit, also 4 Byte. Wieso kann man 4 Byte nicht mit einem Byte> maskieren?
Weil dabei 24 Bits irgendwie übrigbleiben, überstehen, wie immer Du es
nennen willst? Die bitweisen Operatoren sind genau was der Name sagt,
Bit-weise, nicht anwendbar wenn die Anzahl Bits in den Operanden nicht
übereinstimmt.
>
1
[snip]
2
>
Wie man sowas machen könnte:
byte modulstatus;
int maske;
...
maske = /* something */;
modulstatus = modulstatus | (byte) maske;
Das ist natürlich ungetestet, so spät am Abend... Noch besser: wieso die
Maske als int definieren wenn man eh nur 8 Bits Maske braucht?
Uuhhh, habs nochmal nachgesehen...
Samuel K. schrieb:> Das liegt an c#. Normalerweise mag ich dir Sprache, aber hier wurde echt> Mist gebaut. Alle logischen Operatoren sind nur in Int definiert (glaub> ich aufjedenfall).
Das stimmt nicht ganz, man kann sie auf alle Integer-Type anwenden.
> Deswegen gibt er dir auch ein Int zurück. Um die das> Ergebnis nun nach byte zu konvertieren musst du den ganzen Block in eine> Klammer schreiben (hast du ja schon gemacht) und davor den Cast nach> byte setzen.
Ja, das muss man so machen, weil der Operator '|' seine Operanden
mindestens zu int (hoch-)konvertiert und so auch einen int zurückgibt.
Finde ich jetzt ja doof, andererseits ist C# nicht für µC gemacht
worden.
Samuel K. schrieb:> und davor den Cast nach> byte setzen.
und wie sieht das dann aus? Ist das sowas wie Convert?
Jasch schrieb:> Ich gehe mal davon aus Du redest hier von Code in C#?
richtig, ich rede von C#
Jasch schrieb:> Noch besser: wieso die> Maske als int definieren wenn man eh nur 8 Bits Maske braucht?
die Maske ist als Int, aber auch als Byte geht das nciht.
x = (byte)(y|z);
Alternativ kann man sich eine eigene Byte Klasse basteln. Wenn man dabei
den =operator überlädt ist das ganz flexibel.
PS: Ich hab das damals selbst rausgefunden in dem ich alle logisch
möglichen Klammerkombinationen probiert habe. Wenn man dann die korrekte
gefunden hat, weiß man meistens was der Fehler war.
Problem ist (byte)x|z konvertiert zwar x zu einem Byte, | gibt aber
wieder einen Int zurück. Genauso mit z. Deswegen um das ganze eine
Klammer und nur das Ergebnis wird gecastet.
Sowas ist natürlich ziemlich schrecklich.
Zunächst ist der Wertebereich der Schleife verdächtig, die wird hier
nämlich genau 7 mal durchlaufen ("bit" deckt dabei den Zahlenbereich von
1 bis 7 ab).
Dann ist der "Algorithmus" zur Bestimmung der Wertigkeit eines Bits
etwas, äh, ineffizient.
Das hier reicht:
1
maske=1<<bit;
Und abschließend noch: Was soll das ganze eigentlich?
Bevor es in der Funktion DIO_Setzen irgendwie weitergeht, wird diese
Schleife da sieben mal ausgeführt. Und in "maske" steht immer der
letzte so aufwendig "berechnete" Wert, nämlich 1 << 7 bzw. 2^7.
Warum aber wurden vorher die Werte 1 << 1 bis 1 << 6 resp. 2^1 bis 2^6
"berechnet"?
Und dann geht es weiter:
Wenn "tx_modulstatus_neu" nur deswegen eingeführt wurde, weil es
C#-Probleme mit den bitweisen Verknüpfungen gab, ließe sich die erste
Zeile nach dem switch/case-Statement entfernen, can_write ist
entsprechend dann tx_modulstatus anstelle von tx_modulstatus_neu zu
übergeben.
Wie wir weiter oben gesehen haben, geht es bei "maske" ausschließlich um
den Wert 0x80 bzw. 128, also lässt sich obiges switch/case auch so
ausdrücken:
1
switch(Status)
2
{
3
case1:
4
MainForm.tx_modulstatus[Modul,0]|=0x80;
5
break;
6
7
case0:
8
MainForm.tx_modulstatus[Modul,0]&=~0x80;
9
break;
10
}
Sofern "Status" nie andere Werte als 0 oder 1 annehmen kann, ist
natürlich ein switch/case hier völlig fehl am Platze:
1
if(Status==1)
2
MainForm.tx_modulstatus[Modul,0]|=0x80;
3
else
4
MainForm.tx_modulstatus[Modul,0]&=~0x80;
Ein Lobgesang auf die Vorzüge von C# ist diese Vorstellung hier
jedenfalls nicht. Just die Tage habe ich die gleichen
math.pow-Verrenkungen bei einem jungen (naja, noch nicht 30jährigen)
Java-Programmierer gesehen und musste schon schlucken.
Rufus Τ. Firefly schrieb:> Ein Lobgesang auf die Vorzüge von C# ist diese Vorstellung hier> jedenfalls nicht. Just die Tage habe ich die gleichen> math.pow-Verrenkungen bei einem jungen (naja, noch nicht 30jährigen)> Java-Programmierer gesehen und musste schon schlucken.
Weil das anscheinend nicht mehr richtig gelehrt wird und/oder nicht mehr
interessiert...
Hinzu kommt Javas Unsigned-Problem* (aber es gibt einen unsigned right
shift >>>).
Das es in C# wie auch in Java bei solchen Sachen keine impliziten
Typkonvertierungen gibt, sehe ich eher als Vorteil (die subtilen
Unterschiede mal außen vor... double to int ist in Java null wenn der
Wert NaN war, in C# int.MinValue, dafür kennt Java keinen checked
context wo es eine OverflowException geben würde)
* "Quiz any C developer about unsigned, and pretty soon you discover
that almost no C developers actually understand what goes on with
unsigned, what unsigned arithmetic is." Gosling in einem Interview
http://www.gotw.ca/publications/c_family_interview.htm
Arc Net schrieb:> Hinzu kommt Javas Unsigned-Problem
Java hat überhaupt kein Problem mit Unsigned, nur die Programmierer die
arithmetische und bitoperatione wild durcheinanderwürfeln ohne
nachzudenken und hoffen durch "unsigned" würden ihre Probleme
verschwinden ;)
Läubi .. schrieb:> Arc Net schrieb:>> Hinzu kommt Javas Unsigned-Problem>> Java hat überhaupt kein Problem mit Unsigned,
Stimmt es gibt keine unsigned integer
> nur die Programmierer die> arithmetische und bitoperatione wild durcheinanderwürfeln ohne> nachzudenken und hoffen durch "unsigned" würden ihre Probleme> verschwinden ;)
das ist eher das selbe Problem das die Befürworter von dynamisch
typisierten Sprachen nicht sehen wollen: Weniger Typen (d.h. bei
dynamisch typisierten Sprachen nur einer), sind keine Hilfe, sondern
schränken ein.
U.a. da zum einen auf alles mögliche geprüft werden muss, zum anderen
muss mehr annotiert werden, da man z.B. wie bei unsigned/signed nicht
von vornherein sehen kann, was die Funktion erwartet bzw. zurückliefert.
Arc Net schrieb:> Weniger Typen
Eine Vielzahl (primitiver) Typen ist da aber auch nicht gerade
förderlich und es macht das Maschinenmodell unötig komplex.
Arc Net schrieb:> U.a. da zum einen auf alles mögliche geprüft werden muss
Na man kann es auch übertreiben, bestenfalls muss man auf > -1 prüfen...
... hingegen hat sich noch niemand beschwert das es keinen Typen gibt,
welcher nur negativ sein kann, wieso also immer dieser ruf nach "nur
positiven"?
Arc Net schrieb:> nicht von vornherein sehen kann,> was die Funktion erwartet bzw. zurückliefert
Dann ist die Funktion ungenügend dokumentiert, einer
1
voidblub(unsignedint);
seh' ich auch nicht an, dass sie in Wirklichkeit nur Zahlen bis 60'000
verarbeiten kann.
Und wenn wirklich alle Stricke reißen kann man sich immer noch eine
Wrapper Klasse schreiben.
Außer zu Dokumentationszwecken hab ich auch noch nie "unsigned" Typen
vermisst noch ein Beispiel gesehen wo diese unumgänglich nötig wären.
@Rufus Τ. Firefly: Erstmal vielen Dank für Deine kritischen Blicke! Habe
ich es hier mit einem Profi-Programmierer zu tun? Oder Ist das "einfach
nur" Erfahrung? ;-)
Rufus Τ. Firefly schrieb:> Das hier reicht: maske = 1 << bit;
Was tut das genau?
Rufus Τ. Firefly schrieb:> Bevor es in der Funktion DIO_Setzen irgendwie weitergeht, wird diese> Schleife da sieben mal ausgeführt. Und in "maske" steht immer der> letzte so aufwendig "berechnete" Wert, nämlich 1 << 7 bzw. 2^7.
das habe ich auch gesehen, und die Schleife entfernt. Das war wirklich
grober Unfug was ich da getan habe...
Das ganze sah inzwischen so aus:
Wobei ich mir jetzt Deine Ratschläge nochmal zu Gemüt führen werde, und
den Rest auch verbessere.
Rufus Τ. Firefly schrieb:> ie wir weiter oben gesehen haben, geht es bei "maske" ausschließlich um> den Wert 0x80 bzw. 128, also lässt sich obiges switch/case auch so> ausdrücken:
Das ist nicht so, ich muss jedes Byte mit einem "Einheitsbyte" (so nenne
ich es einfach mal) maskieren. Also Prüfen, ob das entsprechende Bit 0
ist oder 1 ist.
Die Anwendung dahinter: Ich dende an ein CAN I/O-Modul ein Byte mit dem
Zustand der 8 Ausgänge. Und wenn ich ein Bit setze, soll der Rest
natürlich erhalten bleiben.
Danke nochmal für Deine Tipps, ich werde einiges korrigieren und dann
nach und nach wieder Fragen stellen, wenns nciht klappt. (Ist immer
schwer was zu verändern, wenn das Programm seine Funktion tut, aber ich
will es ja technisch auch korrekt haben ;-)