Hi Leute,
ich wollte fragen, ob es eine elegante Möglichkeit gibt, sich auf einem
mega2560 eine unsigned 4bit-Zahl zu erstellen.
Also ich will, dass wenn ich
1
//4bitzahl
2
uint4_ti=13;
3
//Addition mit Überlauf
4
i+=5;// i == 2
Das selbe soll mit einem Unterlauf(falls man das so sagen kann ;) )
passieren.
Das kleinste, das ich kenne ist ja ein uint8_t, kann man sich auch einen
Typ erstellen, der nur 4bit hat und Über-/Unterlauf unterstützt?
N. G. schrieb:> Hi Leute,>> ich wollte fragen, ob es eine elegante Möglichkeit gibt, sich auf einem> mega2560 eine unsigned 4bit-Zahl zu erstellen.> Also ich will, dass wenn ich>
1
>//4bitzahl
2
>uint4_ti=13;
3
>//Addition mit Überlauf
4
>i+=5;// i == 2
5
>
>> Das selbe soll mit einem Unterlauf(falls man das so sagen kann ;) )> passieren.> Das kleinste, das ich kenne ist ja ein uint8_t, kann man sich auch einen> Typ erstellen, der nur 4bit hat und Über-/Unterlauf unterstützt?
Elegant soll's auch noch sein? ;) Elegant ist wieder was anderes, aber
Du könntest es mal mit Bitfeldern probieren:
Dr. Sommer schrieb:> C++ verwenden, eine Klasse uint4_t definieren und der Operatoren wie + -> etc. verpassen die das & 0xFF entsprechend durchführen.
gcc kann ja durch die option -x c++ auch das compilieren, aber ich kann
kein c++.
Kannst du mir ein beispiel geben wie das geht?
Sonst muss ichs mit den structs machen
Aber schon mal danke ;)
Ob das alles sinnvoll funktionieren kann, hängt davon ab, wofür es
verwendet werden soll.
Weder mit den genannten Bitfeldern noch irgendeiner anderen
C-Konstruktion wird es gelingen einen echten Datentyp herzustellen,
durch den sich deine uint4_t wie jeder andere Typ verhalten.
Was zum Beispiel scheitern wird, ist Zeiger auf die einzelnen Zahlen zu
bilden, wenn mehrere über Bitfelder in einer struct liegen.
Denn Adressen kann man nur von ganzen Byte bilden nicht von Bitfeldern.
Dementsprechend gibt es auf sowas keinen indirekten Zugriff über Zeiger
oder Feldindizes.
Jede uint4_t dagegen auf eine Bytegrenze zu legen, macht sie wiederum
sinnlos - dann könnte man ja auch uint8_t nehmen und einfach den
Wertebereich nicht ausnutzen.
Was hast Du denn mit den übrigen vier Bit denn vor? - Wenn nichts, dann
musst Du einfach bei den Vergleich-Operatoren deine Zahl zuvor mit 0x0f
ver-und-en.
ich habe mit den übrigen Bits nichts vor, es würde sich ja anbieten,
zwei 4bit-Zahlen in einem uint8_t zu vereinen.
Die Zahl ist ein Index von einem Array aus Sensorwerten, bei denen es
nötig ist, immer verschiedene Sensoren abzufragen. Bsp:
1
//...
2
for(uint8_t/* oder uint4_t */i=0;i<16;i++){
3
if(bs[i]<123){
4
if(bs[i+5]<123){//hier kann ein Überlauf passieren
5
//tu was
6
}
7
elseif(bs[i-3]<123){//hier kann ein Unterlauf passieren
N. G. schrieb:> ich habe mit den übrigen Bits nichts vor, es würde sich ja anbieten,> zwei 4bit-Zahlen in einem uint8_t zu vereinen.
Ich würde auf diese Art der Optimierung verzichten und nur dann
anwenden, wenn mir der Speicher zu wenig wird und ich keine andere
Möglichkeit mehr finde, mir überflüssigen Speicher frei zu machen.
"We should forget about small efficiencies, say about 97% of the time:
premature optimization is the root of all evil" Donald Knuth
ich nutzte einen ATmega2560 und habe bisher bei meinen Projekten maximal
37% des Speichers belegt. Also muss diese Optimierung nicht sein, da
hast du recht. Aber jmd fragte, was ich mit den übrigen Bits vorhatte.
;) guter Spruch
N. G. schrieb:> gcc kann ja durch die option -x c++ auch das compilieren
Das geht aber spätestens beim Linken schief. Lieber direkt den "g++"
aufrufen.
> , aber ich kann> kein c++.> Kannst du mir ein beispiel geben wie das geht?
1
classuint4_t{
2
public:
3
uint4_t(uint8_tr):m_raw(r){}
4
uint8_tgetRaw(){returnm_raw;}
5
private:
6
uint8_tm_raw;
7
};
8
uint4_toperator+(uint4_ta,uint4_tb){
9
return(a+b)&0xFF;
10
};
11
intmain(){
12
uint4_ta(5),b(13);
13
uint4_tc=a+b;
14
}
Weitere Operationen dann nach diesem Schema.
Aber das optimiert natürlich gar nichts, denn jeder Datentyp in C(++)
muss mindestens 1 char groß sein, und auf AVR,ARM,x86 etc. ist 1 char 8
bits groß. d.h. 4bit-Datentypen gibts nicht. Du kannst so höchstens das
4bit-Overflow-Verhalten auf einem uint8_t "simulieren". Im Speicher ist
der uint4_t trotzdem immer mindestens 8 bit groß...
Dr. Sommer schrieb:> Aber das optimiert natürlich gar nichts, denn jeder Datentyp in C(++)> muss mindestens 1 char groß sein, und auf AVR,ARM,x86 etc. ist 1 char 8> bits groß. d.h. 4bit-Datentypen gibts nicht. Du kannst so höchstens das> 4bit-Overflow-Verhalten auf einem uint8_t "simulieren". Im Speicher ist> der uint4_t trotzdem immer mindestens 8 bit groß...
Das ist mir schon klar, aber es erleichtert mir einiges
Dr. Sommer schrieb:> N. G. schrieb:>> gcc kann ja durch die option -x c++ auch das compilieren> Das geht aber spätestens beim Linken schief. Lieber direkt den "g++"
kann man mir als AVR-Studio-4-Anhänger bitte noch erklären wie ich das
umändere. Ich hab davon keinen Plan ;)
Bisher hat die Option noch keine Fehler geworfen
Aber schon mal danke für dein Beispiel.
Müsste es nicht & 0x0f heißen?
N. G. schrieb:> kann man mir als AVR-Studio-4-Anhänger bitte noch erklären wie ich das> umändere. Ich hab davon keinen Plan ;)
Ich hab keine Ahnung von AVR Studio. Ich würde mal raten dass es reicht
der Datei die Endung .cpp zu verpassen damit sie als C++ erkannt wird.
> Bisher hat die Option noch keine Fehler geworfen
Das ändert sich spätestens wenn du C++ standard library funktionen
verwendest...
> Müsste es nicht & 0x0f heißen?
Upps, ja, natürlich.
Okay, danke für deine Erläuterungen.
Ich habe eigentlich nicht vor iwas in die Richtung C++ zu machen, da die
Sprache schon etas anders Aufgebaut ist als C. Aber Den Typ werde ich
verwenden und auch namespaces, die habens mir angetan ;)
Interessant wäre die Frage, wozu man sowas braucht.
Die RAM-Benutzung ist vielleicht etwas geringer. Dafür geht der Code-
und Zeit-Verbauch drastisch nach oben.
Es kann schon Sinn machen wenn viele 4 bit Werte uebertragen werden
sollen oder gespeichert werden sollen.
Zur Verarbeitung werden die 4 bit Werte expandiert (mit 0x0f als uchar).
Zum Abspeichern werden 2x 4 bit in ein uchar gepackt (um 4 bit
verschieben und OR verwenden).
sinngemaess auch fuer 1 bit, 2 bit, 3 bit, 5 bit...
Wenn eine Variable eingegrenzt werden soll auf 4 bit usw. einfach mit
AND die oberen bits loeschen.
Bitfield Arrays gibt es nicht, richtig.
Takao K. schrieb:> Es kann schon Sinn machen wenn viele 4 bit Werte uebertragen werden> sollen oder gespeichert werden sollen.
Ich würde trotzdem alle Rechnungen und Verarbeitungen intern normal
(binär) machen und erst zur Ausgabe an einer einzigen Stelle
konvertieren. Das erhöht deutlich die Übersicht.
Ein ähnliches Problem hat man bei externen RTC, die haben oft auch ein
total krudes Datenformat. Dann konvertiert man einmalig und kann danach
bequem damit rechnen.