Eigene 4bit-Integerzahl erstellen mit Über-Unterlauf in C

Persönliche Seite #3629358
Lesenswert?

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_t i = 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?
#3629379
Lesenswert?

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_t i = 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:

1
struct four_four
2
{
3
    signed a : 4;
4
    signed b : 4;
5
    signed c : 4;
6
    signed d : 4;
7
};  
8

9
int main(void)
10
{
11
    struct four_four tst = {0};
12
    
13
    tst.a = 2;
14
    tst.b = tst.a + 3;
15
    tst.c = 5 * tst.a;
16
    tst.d = tst.a + 6;
17
}
18

19
Die einzelnen Felder verhalten sich so, wie man das von einer anständigen 4-Bit Zahl erwarten würde.
#3629428
Lesenswert?

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.
Persönliche Seite #3629460
Lesenswert?

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
         else if(bs[i - 3] < 123) {//hier kann ein Unterlauf passieren
8
             //tu was anderes
9
         }
10
         //...
11
    }
12
}
13
//...
Gast #3629483
Lesenswert?

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
Gast #3629594
Lesenswert?

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
class uint4_t {
2
  public:
3
    uint4_t (uint8_t r) : m_raw (r) {}
4
    uint8_t getRaw () { return m_raw; }
5
  private:
6
    uint8_t m_raw;
7
};
8
uint4_t operator + (uint4_t a, uint4_t b) {
9
  return (a + b) & 0xFF;
10
};
11
int main () {
12
  uint4_t a (5), b(13);
13
  uint4_t c = 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ß...
Persönliche Seite #3629601
Lesenswert?

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?
Gast #3629607
Lesenswert?

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.
Persönliche Seite #3630192
Lesenswert?

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.
#3630611
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren