Forum: Compiler & IDEs Eigene 4bit-Integerzahl erstellen mit Über-Unterlauf in C


von N. G. (newgeneration) Benutzerseite


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?

: Bearbeitet durch User
von Philipp (Gast)


Lesenswert?

Das einzige was mir einfällt, wäre ein Struct zu nehmen und die 
Feldlänge auf 4 bit zusetzten. Das müsste gehen.

[c]struct {
        uint8_t i:4;
    }l;[c]

von Markus F. (mfro)


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.

von Christopher B. (chrimbo) Benutzerseite


Lesenswert?

Hallo,

andernfalls müsstest du immer eine & 0x0f mitschleppen :-)

von Dr. Sommer (Gast)


Lesenswert?

C++ verwenden, eine Klasse uint4_t definieren und der Operatoren wie + - 
etc. verpassen die das & 0xFF entsprechend durchführen.

von N. G. (newgeneration) Benutzerseite


Lesenswert?

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 ;)

von Klaus W. (mfgkw)


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.

: Bearbeitet durch User
von mar IO (Gast)


Lesenswert?

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.

von N. G. (newgeneration) Benutzerseite


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
//...

: Bearbeitet durch User
von mar IO (Gast)


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

von N. G. (newgeneration) Benutzerseite


Lesenswert?

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

von TriHexagon (Gast)


Lesenswert?

Zumal diese Optimierung des Speicherverbrauches auf Lasten der 
Performance geht.

von Dr. Sommer (Gast)


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ß...

von N. G. (newgeneration) Benutzerseite


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?

: Bearbeitet durch User
von Dr. Sommer (Gast)


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.

von N. G. (newgeneration) Benutzerseite


Lesenswert?

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 ;)

von Peter D. (peda)


Lesenswert?

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.

von Takao K. (takao_k) Benutzerseite


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.

von Simon K. (simon) Benutzerseite


Lesenswert?

Vorausgesetzt der von dir genannnte Typ "uchar" ist 8 Bit groß.

von (prx) A. K. (prx)


Lesenswert?

Simon K. schrieb:
> Vorausgesetzt der von dir genannnte Typ "uchar" ist 8 Bit groß.

Kleiner ist nicht zulässig.

von Peter D. (peda)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.