Forum: Compiler & IDEs cast auf ein #define


von Bruno (Gast)


Lesenswert?

Hallo zusammen,

in meiner SW habe ich eine unsigned long Variable bei der jedes Bit 
einen gewissen Zustand speichert. ZB. bestimmte Eingänge, Fehler... . 
Ich habe den einzelnen Ereignissen defines zugewiesen die, wenn sie 
zutreffen ein bestimmtes Bit setzen. Wenn ein Ereignis nicht zutrifft 
maskiere ich das mit
1
 ulSpeicher &= ~FEHLER_XY;
aus.
Wenn der Bitwert jetzt z.B. 0x01 ist wird das als Integer gespeichert 
und mit der obigen maskierung werden die höheren Bits im Long (>Int) 
gelöscht.
Meine Frage ist jetzt, ob ich die defines casten kann, damit der mit dem 
vollen long maskiert?
Hoffe es ist so einigermaßen klar geworden was ich euch fragen möchte.

Gruß Bruno

: Verschoben durch User
von Εrnst B. (ernst)


Lesenswert?

Gegenfrage:

Warum definierst du dir "ulSpeicher" nicht einfach als Bitset, und lässt 
den Compiler das ganze Bitgefriemel machen?
1
 struct {
2
   unsigned flag1 :1,
3
   unsigned FEHLER_XY :1,
4
...
5
 } ulSpeicher;
6
7
...
8
9
ulSpeicher.FEHLER_XY=1;
10
...
11
12
13
if (ulSpeicher.FEHLER_XY)

von Bruno (Gast)


Lesenswert?

Berechtigte Frage. Sollte ich vllcht wirklich so machen. Danke für den 
Tipp.

von Karl H. (kbuchegg)


Lesenswert?

Bruno schrieb:

> Meine Frage ist jetzt, ob ich die defines casten kann, damit der mit dem
> vollen long maskiert?

Ein #define ist einfach nur eine Textersetzung.
Da steckt nichts Geheimnisvolles dahinter.

Das ist so, wie wenn du in deinem Editor die Anweisung gibst: Ersetze 
den Text ABC durch den Text XYZ

Nichts anderes macht ein
#define ABC XYZ

Nur dass dieses Texteditor-Ersetzungskommando praktischerweise in dem 
Text enthalten ist, den es verändert :-)

Was auch immer du im #define machst

#define  FEHLER_XY  ((unsigned long)1 << 15)

wirkt sich so aus, dass an der Quellcodestelle

   ulSpeicher &= ~FEHLER_XY;

der Text FEHLER_XY durch den Text ((unsigned long)1 << 15) ersetzt wird, 
noch ehe der eigentliche Compiler dein C Programm zu Gesicht bekommt.
Und wenn durch diese Textersetzung dann eben

   ulSpeicher &= ~((unsigned long)1 << 15);

entsteht und das das ist, was du vom Compiler compiliert haben willst, 
dann ist es doch gut.

von Imon (Gast)


Lesenswert?

Εrnst B✶ schrieb:
> Warum definierst du dir "ulSpeicher" nicht einfach als Bitset, und lässt
> den Compiler das ganze Bitgefriemel machen?
>  struct {
>    unsigned flag1 :1,
>    unsigned FEHLER_XY :1,
> ...
>  } ulSpeicher;

weil nirgends garantiert ist was hier der Compiler draus macht, 
vielleicht macht er das was du hoffst und legt die Bits wirklich so an 
wie du dir das wünscht, vielleicht auch nicht im Worst case kann der 
Compiler hier pro wert eine unsigned verbraten um sich vor der 
Bitschieberei zu drücken.Auch ist hierbei die Positionen der Bits nicht 
definiert und spezifiziert. kann also Kräftig durch gemischt werden.

Vielleicht geht es also bei dein  Compiler in der von dir verwendeten 
Version aber bei ein solchen Konstukt sollte man wenigsten noch das 
Arttibut packt oder ein entsprechendes nutzen, ich würde es jedenfalls 
nur mit Bauchschmerzen nutzen das es hoch grade Compiler spezifisch ist 
und sich auch abhänig von der eingestellen Optimierung ändern kann, dann 
doch lieber das Bit manipulieren von hand ( was mann durch Makro und Co 
auch gut Kapseln kann). da weiss man was man hat.

Was das define angeht ändere deine werte und häng UL rann dann weiss der 
Compiler das es sich um unsigned long handelt und du musst eine 
konstante nicht casten. denn wie schon gesagt ein define ist nicht las 
eine Text ersetzung.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Imon schrieb:
> im Worst case kann der
> Compiler hier pro wert eine unsigned verbraten um sich vor der
> Bitschieberei zu drücken

Nein, zumindest dürfte er sich dann nicht Compiler für die
Programmiersprache C nennen.  Es stimmt zwar, dass bei bitfields
so nahezu alles "implementation-defined" ist, aber ein bitfield
einfach platzfressend als int/unsigned int zu implementieren, ist
einem standardkonformen Compiler nicht gestattet.

Referenz popele ich dir raus, wenn du mir's nicht so glaubst.

von Bruno (Gast)


Lesenswert?

Aber einen Fehler bekomme ich bei der maskierung.
Bspl. leicht verkürzt.

YX &= ~YZ;
wenn (Bitwerte)
1000.0000.0000.0000 &=~ 1000.0000
gerechnet wird, löscht der mir das MSB bei YX.

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

Imon schrieb:
> weil nirgends garantiert ist was hier der Compiler draus macht,

Der C-Standard legt sich hier in der Tat nicht fest. Aber das nirgends 
schießt etwas über das Ziel hinaus. Es gibt für einige bekannte 
Prozessorarchitekturen ein entsprechendes ABI, das solche Dinge genau 
festlegt. In den header Dateien, in denen die Strukturen deklariert 
werden, kann man das für jede unterschiedliche Architektur ganz neutral 
durch #if/#else/#endif kapseln.

Nachdem man für den Einzelfall beurteilt hat, dass bit-fields das Mittel 
der Wahl sind, muss man sich im Code nicht mehr darum kümmern und vor 
allem nicht mehr mit Bit-Masken herumschlagen und kann sogar 
auto-completion seines Lieblingseditors verwenden.

--
Marcus

von Karl H. (kbuchegg)


Lesenswert?

Bruno schrieb:
> Aber einen Fehler bekomme ich bei der maskierung.
> Bspl. leicht verkürzt.

Nicht verkürzen!
Die Details sind wichtig!

Zeig alles. Die Makros, die Datentypen, die problematische Stelle.

Den Unterschied zwischen 1 und 1UL und wie sich der bei 
Schiebeoperationen auswirken kann, kennst du?

http://www.mikrocontroller.net/articles/FAQ#Welche_Datentypen_haben_Konstante.3F

von Bruno (Gast)


Lesenswert?

Das war ja nur ein Beispiel.

ein unsigned long &= ~ int

0b0000 0100 0000 0000 0000 0000 0000 0000 &= ~0b0100 0000 0000 0000
Da fällt die eins im uL weg. Zumindest bei meinem Compiler.
wollte mir die Nullen sparen. Und ja, das mit dem schieben ist mir 
bekannt.

Gruß Bruno

von Karl H. (kbuchegg)


Lesenswert?

Bruno schrieb:
> Das war ja nur ein Beispiel.

An einem Beispiel kann man dir aber nicht sagen, wo bei dir das Problem 
liegt, wenn du keine Details herzeigst.

> ein unsigned long &= ~ int
>
> 0b0000 0100 0000 0000 0000 0000 0000 0000 &= ~0b0100 0000 0000 0000
> Da fällt die eins im uL weg.

Logisch.

rechts steht ein int.
Der wird bitinvertiert, damit steht rechts

   0b1011 1111 1111 1111

dieses Ergebnis wird jetzt auf unsigned long aufgeblasen

   0b0000 0000 0000 0000 1011 1111 1111 1111

und mit

   0b0000 0100 0000 0000 0000 0000 0000 0000

verundet. Und schon ist die originale 1 im unsigned long weg.

von Bruno (Gast)


Lesenswert?

Das war ja auch das ganze Problem.
Ich dachte ich könnte das durch
1
#define XY 0x00000100
lösen. Aber blöd is der Compiler ja auch nicht. Nuch ich manchmal. 
Deshalb wollte ich ja casten. Aber das mit dem Bitfeld gefällt mir schon 
ganz gut. So wollte ch es auch von Anfang an machen, warum ich es nicht 
gemacht habe weiß ich nicht mehr.Habe es dann auch implementiert und 
nach viel stricken läuft es jetzt auch fast wieder. Aber der Rest kommt 
Montag. Danke für eure Hilfe.

Gruß Bruno

von Karl H. (kbuchegg)


Lesenswert?

Bruno schrieb:
> Das war ja auch das ganze Problem.
> Ich dachte ich könnte das durch
>
1
#define XY 0x00000100
> lösen. Aber blöd is der Compiler ja auch nicht.

Ne.
Aber dir fehlt C Wissen
1
#define XY 0b00000100UL

und schon ist das kein int mehr sondern ein unsigned long
demenstprechend sieht dann auch ~XY ein klein wenig anders aus.

Und wenn du um 14:05 bereits das hier gepostet hättest
1
#define XY 0b00000100
2
3
unsigned long value = 0x10000000;
4
value &= ~XY;

zusammen mit der Frage, warum dir da die 1 im unsigned long flöten geht, 
hättest du um 14:10 schon die Antwort dafür gehabt und nicht erst 4 
Stunden später :-)
Es sind immer die Details, wie zb Datentypen der beteiligten Operanden, 
die den Unterschied ausmachen!

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.