Bit als Variable definieren in C (STM32)

Gast #5524584
Lesenswert?

1
#include <stdbool.h>
2

3
int main () {
4
  bool x = true;
5
  x = false;
6
}
Tatsächlich wird "bool" aber immer 8 Bits Speicher belegen; richtige 
1-Bit-Variablen gibt es auf heutigen Prozessoren nicht.
#5524611
Lesenswert?

habichvergessen schrieb:
> Hallo,
>
> Wie kann ih in C für eclipse GCC eine Variable mit einem Bit Definieren?
> Selbes wie mache ich das bei einem Byte?
>

Nimm einfach unsigned char - für dein Byte und wenn Du mehrere „Bit - 
Variablen” hast,  kannst Du die auch in einem unsigned char unterbringen
C hat genügend Operatoren um bitweise vernünftig damit arbeiten zu 
können.
Gast #5524670
Lesenswert?

Volle schrieb:
> Dr. Sommer schrieb:
>> Tatsächlich wird "bool" aber immer 8 Bits Speicher belegen; richtige
>> 1-Bit-Variablen gibt es auf heutigen Prozessoren nicht.
>
> beides Falsch
>
> bool ist int    und damit meist 16 Bit
>

Auch falsch, Datentypen sind immer vom Compiler abhängig, auch bool

Soweit ich mich an Programmieren Vorlesung erinnere ist tatsächlich bei 
C nicht mal die 1 Byte Größe von char garantiert.

C Spezifikation garantiert mindestgrößen für Variablen:
char: mindestens 8 Bit
short: mindestens so groß wie char
int mindestens so groß wie short

Ich meine beim Microsoft Visual C Compiler mal die Einstellung gesehen 
zu haben: Char width: 1 oder 2 Byte.

will man die exakten Größen von Variablen wissen, dann muss man die 
Dokumentation des Compilers durchlesen. Dort sind die exakt 
spezifiziert.
Alternative: stdint.h verwenden.
Wobei eine Dokumentation eines Compilers finde ich persönlich ziemlich 
interessant.
Man möge mich steinigen falls ich falsch liege.
#5524691
Lesenswert?

Dr. Sommer schrieb:
> Tatsächlich wird "bool" aber immer 8 Bits Speicher belegen; richtige
> 1-Bit-Variablen gibt es auf heutigen Prozessoren nicht.

Es gibt Flags, die der Compiler (manchmal) dafür nutzen kann. Das T-Flag 
beim AVR ist im Prinzip ein 1-Bit-Register. Der SDCC nutzt sowas auf 
manchen Architekturen, wenn die Lebenszeit eines Bools hinreichend kurz 
ist.

Walter K. schrieb:
> Nimm einfach unsigned char

Das war mal ein sinnvoller Rat, ist es heutzutage nicht mehr. Wenn man 
genug Bits hat, dann ist "unsigned int" (in jedem Fall auf dem Target 
effizient, was für char nicht gelten muss) die bessere Wahl.

Echte 1-Bit-Variablen gibt es in C nur in Form von "bool" (bzw. "_Bool") 
und als Teil eines Bitfeldes.

Volle schrieb:
> bool ist int

Das ist schlichtweg falsch.
bool ist _Bool, und _Bool ist, was der Compiler draus macht.
Der darf auch mehrere bools in ein Byte packen.

Dr. Sommer schrieb:
> Ok, die lassen sich in C nicht standardkonform abbilden, da in C die
> Variablengröße immer ein Vielfaches von char ist, und char ist mind. 8
> bit.

Gilt das auch für bool? Denn das ist per Definition eine Variable, die 
nur genau zwei Zustände annehmen kann...

hl. Stephanus schrieb:
> Soweit ich mich an Programmieren Vorlesung erinnere ist tatsächlich bei
> C nicht mal die 1 Byte Größe von char garantiert.

In C gibt es überhaupt keine 8-Bit-Bytes. Ein char ist aber genau 
CHAR_BITS Bits groß, und CHAR_BITS muss nicht gleich 8 sein.

Im Gegensatz zu C erfordert POSIX allerdings, dass CHAR_BITS gleich 8 
ist, obwohl das m.W. nicht explizit aufgeschrieben ist.
#5524694
Lesenswert?

S. R. schrieb:
> In C gibt es überhaupt keine Bytes.

Im Standard gibt es diesen Begriff.

"byte
addressable unit of data storage large enough to hold any member of the 
basic character set of the execution environment"

> Im Gegensatz zu C erfordert POSIX allerdings, dass CHAR_BITS gleich 8
> ist, obwohl das m.W. nicht explizit aufgeschrieben ist.

Im C Standard sind es mindestens 8 Bits.
#5524727
Lesenswert?

Stefan schrieb:
> Dafür hat NXP die BitBanding Area.

Das ist eine herstellerunabhängige Eigenschaft von ARM Cores. Abgesehen 
vom M0 (und evtl M1) hat das m.W. jeder Cortex Mx.

Bei Bitbanding im RAM aber drauf achten, dass für den Compiler normale 
Bytes und darin enthaltene Bitbanding-Bits getrennte Objekte sind. Er 
weiss nicht, dass sie per Hardware gekoppelt sind. Zugriffsoptimierung 
kann ggf einen Streich spielen.
#5524760
Lesenswert?

S. R. schrieb:

>> Walter K. schrieb:
>> Nimm einfach unsigned char
>
> Das war mal ein sinnvoller Rat, ist es heutzutage nicht mehr. Wenn man
> genug Bits hat, dann ist "unsigned int" (in jedem Fall auf dem Target
> effizient, was für char nicht gelten muss) die bessere Wahl.

Weshalb sollte ein unsigned int heute effizienter als ein unsigned char 
sein?

Jetzt bitte keinen Fall konstruieren, bei dem man mehrere unsigned char 
- statt einem unsigned int braucht ;-)
#5524767
Lesenswert?

Walter K. schrieb:
> Weshalb sollte ein unsigned int heute effizienter als ein unsigned char
> sein?

Weil viele Prozessoren in Registern keine Bytes verarbeiten können. Das 
kann zu Anpassungsoperationen führen, die den Aufwand gegenüber "int" 
erhöhen. Deshalb gibt es Typen wie uint_fast8_t, die je nach Prozessor 
als Bytes oder grösser implementiert werden.
Gast #5524775
Lesenswert?

Es nennt sich Integer Promotion (s. ANSI Standard) und es bedeutet, dass 
jede mathematische oder logische Operation immer auf mindestens 
integer-breite durchgeführt werde, auf dem RISC wie Arm ist es immer so, 
auf dem x86 muss es nicht sein. Und wenn man Byte als Operand hat, wird 
es vor der Operation erst nach integer gecastet, was die Zeit kostet 
....
Beitrag #5524788 wurde von einem Moderator gelöscht.
#5524809
Lesenswert?

Mix schrieb:
> Es nennt sich Integer Promotion (s. ANSI Standard) und es bedeutet, dass
> jede mathematische oder logische Operation immer auf mindestens
> integer-breite durchgeführt werde,

Es bedeutet, dass das Ergebnis dem entsprechen muss. Die tatsächliche 
Operation muss nicht in dieser Form erfolgen, wenn das gleiche Ergebnis 
rauskommmt.

Nur muss der Compiler sich bei RISCs entscheiden, ob bei uchar Werten in 
Registern entweder der Rest des Registers immer 0 enthält, oder beliebig 
ist. Je nachdem kann es dann passieren, dass bei manchen Operationen 
vorher oder nachher maskiert werden muss.
Gast #5524812
Lesenswert?

Nimm einfach für beides den Datentyp Char. Wenn du char als "Bit" 
verwenden willst, dann heißt das in C im Umkehrschluss, dass eine null 
in der char-Variable FALSE bedeutet und alles, was ungleich null ist, 
bedeutet TRUE. Willst du irgendwo im Programm in dein "Bit" den Status 
TRUE speichern, dann schreib einfach fürs Verständnis eine 1 rein, bei 
FALSE eine null. Bei einer Abfrage auf 1 kannst du dann einfach:
if (variable) ...
schreiben. Bei einer Abfrage auf 0 dann
if (variable == 0)
Das doppelte Istgleich ist wichtig!
Gast #5525034
Lesenswert?

Ich finde es immer wieder geil, wenn ein Anfänger eine Anfängerfrage 
stellt, und darauf überhaupt nicht eingegangen wird, sondern die erste 
Antwort zu dem Thema auf akademischem Niveau zerpflückt wird...

Nutzen für den Fragesteller ist weniger als Null, denn der ist jetzt 
noch verwirrter und hat nun Angst vor dem Thema, weil sich ja schon die 
selbsternannten "Experten" nicht einig sind....
#5557676
Lesenswert?

fop schrieb:
> Na gut, noch ein Versuch zum ursprünglichen Thema zu kommen :
> einzelne Bits kann man in C innerhalb von Strukturen anordnen :
>
>
1
> struct {
2
>    unsigned int buhl:1;
3
> } lieblingsvariable;
4
>

Wobei die struct ganze Bytes belegt, man also nur bei Verwendung 
mehrerer solcher Bits wirklich Speicher spart:

struct s
{
 bool b1 : 1;
 bool b2 : 1;
 unsigned int i1 : 1;
 signed int s1 : 1;
 unsigned int i2 : 4;
}

würde wohl 1 Byte belegen.

Philipp
Gast #5557925
Lesenswert?

Philipp Klaus K. schrieb:
> Wobei die struct ganze Bytes belegt, man also nur bei Verwendung
> mehrerer solcher Bits wirklich Speicher spart:
>
> struct s
> {
>  bool b1 : 1;
>  bool b2 : 1;
>  unsigned int i1 : 1;
>  signed int s1 : 1;
>  unsigned int i2 : 4;
> }
>
> würde wohl 1 Byte belegen.

Allerdings ist der Zugriff darauf meistens weniger performant, als auf 
"normale" bool Variablen. Ich würde das nur machen, wenn das Sparen von 
Speicherplatz wirklich notwendig ist.
#5557966
Lesenswert?

Falls es ein STM32 sein sollte, der BitBanding unterstützt, dann könnte 
man damit jedes RAM-Bit ansprechen. In C wäre es ein uint32_t[], bei dem 
jedes Element 0 oder 1 wäre. Packt die bool's maximal und kommt ohne 
Bit-Schiebereien aus.
Wobei z.B. ein M3, der das z.B. hätte, auch Bitfield-Befehle hat. Damit 
braucht man dann jeweils gerade man einen Befehl mehr für einen Zugriff.
#5557980
Lesenswert?

Stefanus F. schrieb:
> Carl D. schrieb:
>> Falls es ein STM32 sein sollte, der BitBanding unterstützt, dann könnte
>> man damit jedes RAM-Bit ansprechen.
>
> Was muss man in C beachten, damit der gcc dieses Feature nutzt?

Man muß die BB-Adresse passend zur RAM-Adresse berechnen und darf nicht 
vergessen, daß der Compiler nichts davon weiß, daß die RAM-Variable nun 
volatile ist.
Nicht unbedingt Anfänger-geeignet, besonders wenn es nicht auf des 
letzten 1/72tel-μs-Befehl ankommt ;-)
Gast #5558107
Lesenswert?

Carl D. schrieb:
>>> Nicht unbedingt Anfänger-geeignet...
>> Danke für die Erklärung.
> Das ging nicht gegen dich.

Ich bin aber Anfänger. Abgesehen davon galt mein Dank der eigentlichen 
Erklärung. Nach der (und dem entsprechenden Artikel auf 
mikrocontroller.net) habe ich selbst schon beschlossen, es (vorläufig) 
nicht zu nutzen.
#5558161
Lesenswert?

Erwin D. schrieb:
>> Das T-Flag beim AVR ist im Prinzip ein 1-Bit-Register.
> Das ist falsch. Das T-Flag ist nur ein Bit im 8-Bit-Register 'sreg'.

Im Gegensatz zu allen anderen Bits in SREG ist es frei setz- und 
löschbar, hat keine Sonderbedeutung und ändert sich nicht als 
Nebeneffekt von Befehlen. Damit ist es für einen Compiler sinnvoll als 1 
Bit-Register nutzbar.

Darum "im Prinzip".
Gast #5558198
Lesenswert?

Philipp Klaus K. schrieb:
> , dass Compiler für Mikrocontroller hier üblicherweise nur ein Byte
> verwenden (zumindest der SDCC macht es so).

Ja, es gibt immer Compiler, die sich um C einen Dreck scheren und für 
den beschränkten Anwendungsbereich "offensichtliche Fehler" beheben. Ja, 
in deinem Beispiel geht ein Anfänger sicher davon aus, dass alles in ein 
Byte passt und freut sich, wenn es auch so ist.
#5558212
Lesenswert?

Achim S. schrieb:
> Ja, es gibt immer Compiler, die sich um C einen Dreck scheren und für
> den beschränkten Anwendungsbereich "offensichtliche Fehler" beheben. Ja,
> in deinem Beispiel geht ein Anfänger sicher davon aus, dass alles in ein
> Byte passt und freut sich, wenn es auch so ist.

Ich weiß immer noch nicht, was du meinst.

Das das Beispiel unvollständig ist (kein #include <stdbool.h>, kein 
Semikolon am Ende, es wird auch keine Variable angelegt), und so auch 
nicht von SDCC kompiliert würde? Wenn es für die Diskussion hilfreich 
ist, hier ein vollständiges, mit SDCC kompilierbares Beispiel, mit zwei 
Variablen (s1, s2), zu je einem Byte:
1
#include <stdbool.h>
2

3
struct s
4
 {
5
  bool b1 : 1;
6
  bool b2 : 1;
7
  unsigned int i1 : 1;
8
  signed int s1 : 1;
9
  unsigned int i2 : 4;
10
 };
11

12
struct s s1;
13
struct s s2;

Philipp
Gast #5558262
Lesenswert?

Ich hatte vor vielen Jahren mal einen Pascal Compiler für irgendeinen 
längst historischen µC, da konnte ma einzelne Bits so ansprechen:

PORTA.0=HIGH
PORTA.1=LOW

Mit Variablen ging das genau so. Das könnte man meinetwegen gerne als 
Erweiterung in den C Standard aufnehmen.
#5558332
Lesenswert?

Stefanus F. schrieb:
> Das könnte man meinetwegen gerne als
> Erweiterung in den C Standard aufnehmen.

Man kann heute schon eine Union mit einem Bitfeld machen und Einzelbits 
in Variablen mit "var.b0" ansprechbar machen.

Aber wie ich hier lernen durfte, ist das keine sinnvolle Lösung für 
Peripherieregister, weil damit immer ein RMW (read modify write)-Zugriff 
verbunden ist. "PORTA.0 = 1;" mag zwar schick sein, schreibt aber auch 
alle anderen Bits in "PORTA".
#5558358
Lesenswert?

Stefanus F. schrieb:
> Ich hatte vor vielen Jahren mal einen Pascal Compiler für irgendeinen
> längst historischen µC, da konnte ma einzelne Bits so ansprechen:
>
> PORTA.0=HIGH
> PORTA.1=LOW
>
> Mit Variablen ging das genau so. Das könnte man meinetwegen gerne als
> Erweiterung in den C Standard aufnehmen.

Das macht der SDCC z.B. für 8051 genau so. Es gibt das Keyword __bit, 
das den Typ "ein einziges Bit" repräsentiert. Mit "__bit __at 0x80 P0_0" 
kann man Bits auf auf bestimmte Adressen festlegen, z.B. hier P0.0 des 
8051.
#5558647
Lesenswert?

S. R. schrieb:
> Philipp Klaus K. schrieb:
>> Ich weiß immer noch nicht, was du meinst.
>
> Vermutlich, dass "implementation-defined" gleichbedeutend mit "da muss
> der Compiler aber einen Error werfen" bedeuten sollte. Was es nicht tut.

Wobei ich im Beispiel nur ein "implementation-defined" sehe: Ob und wie 
viele Padding Bytes es am Ende der struct gibt, und damit wie groß sie 
insgesamt ist. Insbesondere darf der Compiler tatsächlich die ganze 
struct in ein einziges Byte packen.

Aber korrektes C, das von einem C-Compiler akzeptiert werden sollte, ist 
es.

Philipp
Gast #5558764
Lesenswert?

Philipp Klaus K. schrieb:
> Ich weiß immer noch nicht, was du meinst.

Mea Culpa.

Ich dachte, C verlangt:
1) nur signed ODER unsigned innerhalb einer Struktur
2) Mindestgröße der Struktur = zugrundeliegender Basistyp (also 
2/4-Bytes wenn ein (un)signed int dabei ist.

Das ist aber wohl nur eine (erlaubte) Implementierung zweier Compiler 
hier. Jedenfalls finde ich nichts dazu im C-Standard.

Darum ist alles, was ich schrieb, falsch. Und ich bin der letzte, der 
etwas gegen "implementation defined" hat. Von wegen nicht portabel oder 
so (dafür gibt's ja static asserts).
#5559188
Lesenswert?

Achim S. schrieb:
> Mea Culpa.

;-)

Achim S. schrieb:
> 1) nur signed ODER unsigned innerhalb einer Struktur

Nein, das darf man beliebig mischen. Man darf auch andere Strukturen in 
einer Struktur haben, und da eine "struct" kein Vorzeichen hat, wäre so 
eine Forderung unsinnig.

Wenn du einen Compiler hast, der so abgefahren ist, dass der das nicht 
akzeptiert, dann ist das kein C-Compiler.

Achim S. schrieb:
> 2) Mindestgröße der Struktur = zugrundeliegender Basistyp (also
> 2/4-Bytes wenn ein (un)signed int dabei ist.

Wenn ich in einer Struktur einen "int" speichere, dann muss die Struktur 
auch mindestens einen "int" groß sein. Wenn ich nur einen "char" drin 
speichere, muss sie nur "char" groß sein. Darf aber auch größer.

Und ein Bitfeld mit 8 Einzelbits darf so groß sein wie ein Byte. Im 
(durchaus unportablen) Einsatz innerhalb einer Union macht man das ja 
absichtlich. :-)

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