Forum: Compiler & IDEs Eine Kinderfrage bzg. Struct


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Maxim B. (max182)


Lesenswert?

Guten Tag!
Ich habe eine Frage, vielleicht könnte mir jemand helfen?

Irgendwo habe ich Code gesehen:
1
struct bits {
2
  u8 b0:1;
3
  u8 b1:1;
4
  u8 b2:1;
5
  u8 b3:1;
6
  u8 b4:1;
7
  u8 b5:1;
8
  u8 b6:1;
9
  u8 b7:1;
10
} __attribute__((__packed__));
11
12
#define SBIT_(port,pin) ((*(volatile struct bits*)&port).b##pin)
13
#define  SBIT(x,y)  SBIT_(x,y)
Funktioniert gut. Aber nur 8 bit-Variable.
Ich habe versucht, ähnlich für 16 bit zu schreiben:
1
struct wbits {
2
  u16 b0:1;
3
  u16 b1:1;
4
  u16 b2:1;
5
  u16 b3:1;
6
  u16 b4:1;
7
  u16 b5:1;
8
  u16 b6:1;
9
  u16 b7:1;
10
  u16 b8:1;
11
  u16 b9:1;
12
  u16 b10:1;
13
  u16 b11:1;
14
  u16 b12:1;
15
  u16 b13:1;
16
  u16 b14:1;
17
  u16 b15:1;
18
} __attribute__((__packed__));
19
20
#define WBIT_(port,pin) ((*(volatile struct wbits*)&port).b##pin)
21
#define  WBIT(x,y)  WBIT_(x,y)
und dann als Test
1
u16 meinvar = 0;
2
3
#define MW0 WBIT(meinvar,0)
4
#define MW1 WBIT(meinvar,1)
5
#define MW2 WBIT(meinvar,15)
6
...
7
MW0 = 1;
8
MW1 = 1;
9
MW2 = 1;
10
MW0 = 0;
11
MW1 = 0;
12
MW2 = 0;
Das wurde kompiliert, und das arbeitet sogar wie gewünscht. Aber für 
diese sechs Zeilen bekomme ich auch sechs Warnings:
../meindefs.h:67:45: warning: dereferencing type-punned pointer will 
break strict-aliasing rules [-Wstrict-aliasing]
../meindefs.h:68:19: note: in expansion of macro 'WBIT_'
../main.c:20:13: note: in expansion of macro 'WBIT'
 #define MW2 WBIT(meinvar,15)

D.h. etwas stimmt nicht. Ich möchte gerne so machen, daß keine Warnings 
kommen (sonst kann ich später auch andere Warnings nicht merken, die 
noch wichtiger sind).
Wie kann ich das korrekt machen? Ich habe avr-gcc-5.4.0 benutzt und 
ATMega644PA.
Vielen Dank im voraus!

von Hugo H. (hugohurtig1)


Lesenswert?

Maxim B. schrieb:
> Wie kann ich das korrekt machen?

Hat der ATMega644PA nicht 8 Bit "breite" Ports? Dann wird es schwierig 
mit PIN15 zu einem Port ... :-)

: Bearbeitet durch User
von Maxim B. (max182)


Lesenswert?

Hugo H. schrieb:
> Hat der ATMega644PA nicht 8 Bit "breite" Ports?

Habe ich geschrieben über Ports? Dann habe ich falsch gesagt.
Mir geht es um Bitvar.

von Hugo H. (hugohurtig1)


Lesenswert?

Maxim B. schrieb:
> #define WBIT_(port,pin)

Maxim B. schrieb:
> Habe ich geschrieben über Ports?

Ja.

von Maxim B. (max182)


Lesenswert?

Mir geht es um Bitvariablen. Ob das Port ist oder Speicherstück, ist mir 
hier egal. Ich möchte wissen, wie ich das schreibe ohne daß Compiler 
schimpft.

Was möchte ich genau:
ich habe z.B. eine Variable, 16bit oder 32 oder 64 bit. Ich möchte für 
ein Bit dieser Variablen Name geben und darüber dieses Bit setzen, 
löschen oder prüfen. Ich möchte das wie ober gezeigt machen, MYBITVAR0 = 
1; MYBITVAR0 = 0; if(MYBITVAR0){...

Ich kann auf andere Weise ein Wort mit einer Handlung verbinden, z.B.
1
#define SETBIT(reg, bit)   reg |= (1<<(bit))
2
#define MW0_1 SETBIT(meinvar,0)
aber ich möchte gerne schreiben können:
1
MW0 = 1;

: Bearbeitet durch User
von Maxim B. (max182)


Lesenswert?

Außerdem: in diesem Fall muß ich Variable als volatile nennen. Dann bei 
16bit werden immer beide Bytes gelesen und geschrieben.
Wenn ich das mit struct mache wie oben, wied immer nur entsprechende 
bytes gelesen und geschrieben, d.h. Code ist besser. Aber diese 
Warnings...
Wie kann ich ohne diesen (nur diesen) Warnings schreiben und trotzdem 
optimale Code bekommen?

: Bearbeitet durch User
von Dr. MCU (Gast)


Lesenswert?


von Maxim B. (max182)


Lesenswert?

Danke!

Ich verstehe, daß meine Frage vielleicht dumm klingt...
Also: wenn ich so schreibe, bekomme ich das Gewünschte:
1
volatile union {
2
  u16 var;
3
  struct{
4
    u8 b0:1;
5
    u8 b1:1;
6
    u8 b2:1;
7
    u8 b3:1;
8
    u8 b4:1;
9
    u8 b5:1;
10
    u8 b6:1;
11
    u8 b7:1;
12
  u8 b8:1;
13
    u8 b9:1;
14
    u8 b10:1;
15
    u8 b11:1;
16
    u8 b12:1;
17
    u8 b13:1;
18
    u8 b14:1;
19
    u8 b15:1;
20
  } bit;
21
} meinvar;
22
#define MV0  meinvar.bit.b0
23
#define MV1  meinvar.bit.b1
24
#define MV15  meinvar.bit.b15
25
26
...
27
MV0 = 1;
28
MV1 = 1;
29
MV15 = 1;
Wie kann ich das einfacher schreiben? Mit Zeiger auf Union usw.? Damit 
ich nicht für jede Variable Union einzeln schreibe.

von A. S. (achs)


Lesenswert?

Das Problem ist, dass bitfelder.und type-punning 
implementierungsabhängig oder undefiniert sind. Zumindest bei was 
anderem als chars oder void.

Die Warnung ist also gerechtfertigt.

Alternativen: setzen/löschen per Masken (in defines versteckt) oder Cast 
über Char bzw void.

von Maxim B. (max182)


Lesenswert?

Ich habe noch mit Union ausprobiert:
1
union {
2
  u16 var16;
3
  struct{
4
    u8 var81;
5
    u8 var82;
6
  };
7
}meinvar;
8
9
#define MV0  SBIT(meinvar.var81,0)
10
#define MV1  SBIT(meinvar.var81,1)
11
12
#define MV15  SBIT(meinvar.var82,7)
und auch so:
1
union {
2
  u16 var16;
3
  u8 var8[2];
4
}meinvar;
5
6
#define MV0  SBIT(meinvar.var8[0],0)
7
#define MV1  SBIT(meinvar.var8[0],1)
8
9
#define MV15  SBIT(meinvar.var8[1],7)

Ergebnis genau so wie mit WBIT: nach ersten Compilen nach Änderung 
kommen x Warnings, bei wiederholten Compilen keine Warnings...

Vielleicht sollte ich Variante mit WBIT wählen und somit leben. Einfach 
zweimal compilen, um nur die "echten" Warnings zu sehen.

: Bearbeitet durch User
von A. S. (achs)


Lesenswert?

Maxim B. schrieb:
> nach ersten Compilen nach Änderung kommen x Warnings,
Welche? Z.b. dass Du unbenannte Strukturen verwendest? Dann bekam sie 
einfach.

> bei wiederholten
> Compilen keine Warnings...
Die sind nicht weg:
Der compiliert nicht, wenn keine Fehler da sind.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

warum der anschließende Wechsel von struct auf define? Man kann doch 
wunderbar auf das struct zugreifen. Warum dann nochmal ein define? Was 
sowieso nicht geht.
1
struct Bitfield
2
{
3
    uint8_t b0:1;
4
    uint8_t b1:1;
5
    uint8_t b2:1;
6
    uint8_t b3:1;
7
    uint8_t b4:1;
8
    uint8_t b5:1;
9
    uint8_t b6:1;
10
    uint8_t b7:1;
11
    uint8_t b8:1;
12
    uint8_t b9:1;
13
    uint8_t b10:1;
14
    uint8_t b11:1;
15
    uint8_t b12:1;
16
    uint8_t b13:1;
17
    uint8_t b14:1;
18
    uint8_t b15:1;
19
} myBit;
20
21
int main(void)
22
{
23
    myBit.b0 = 0;
24
    myBit.b1 = 1;

Oder ganz anders, leg dir ein Array an. Hätte den Vorteil du kannst mit 
for Schleifen drüber gehen.
1
struct Field
2
{
3
  uint8_t bit:1;  
4
}; 
5
6
struct Field field[15];
7
8
int main(void)
9
{    
10
    field[0].bit = 1;
11
    field[14].bit = 1;

Du kannst dir auch einfach nur eine 16Bit Variable nehmen und eine Maske 
verschieben und dann das Bit an entsprechender Stelle setzen oder 
löschen. Wie es beliebt.

: Bearbeitet durch User
von Maxim B. (max182)


Lesenswert?

Das ist nicht das Problem.
Ich möchte nur mein Leben eifacher machen.

Was möchte ich:
1. es gibt Variable. 2-3-4-8 Bytes.
2. Ich möchte in meindefs.h so etwas haben, was ermöglicht zu schreiben:
#define MYBIT0   WBIT(Variable, Bitnummer)
und somit in *.c :
MYBIT0 = 0;
MYBIT0 = 1;
if(MYBIT0){...}

Das funktioniert wunderschön mit 1-Byte-Variablen. Ich glaube, diese 
Konstruktion habe ich bei Peter Dannegger in seinem "Sniffer" gesehen. 
Da ein Mensch seiner Natur wegen immer Bessere sucht, möchte ich gerne 
eine Möglichkeit finden, mit einer ähnlichen Schreibweise nicht nur 
1-Byte-Variablen sondern auch Mehrbytesvariablen bitweise manipulieren.

A. S. schrieb:
>> bei wiederholten
>> Compilen keine Warnings...
> Die sind nicht weg:
> Der compiliert nicht, wenn keine Fehler da sind.

Ich meine hier, daß wenn ich in AVR Studio 4.19 nach einer Änderung im 
Programm auf Strg+F7 drucke, bekomme ich genau so viele Warnings wie oft 
ich Mehrbytes-Zuweisungen in *.c-File habe (bei 1-Byte-Variablen ist 
alles fehlerfrei).
Wenn ich aber auf "Stop Gebugging" drucke und noch mal auf Strg+F7 (ohne 
etwas in Zwischenzeit nochmal zu ändern), sind alle Warnings weg.
Das passiert bei allen Mehrbytes-Varianten: mit
1
struct wbits {
2
  u8 b0:1;
3
  u8 b1:1;
4
  u8 b2:1;
5
  u8 b3:1;
6
  u8 b4:1;
7
  u8 b5:1;
8
  u8 b6:1;
9
  u8 b7:1;
10
  u8 b8:1;
11
  u8 b9:1;
12
  u8 b10:1;
13
  u8 b11:1;
14
  u8 b12:1;
15
  u8 b13:1;
16
  u8 b14:1;
17
  u8 b15:1;
18
} __attribute__((__packed__));
19
20
#define WBIT_(port,pin) ((*(volatile struct wbits*)&port).b##pin)
21
#define  WBIT(x,y)  WBIT_(x,y)
 ,
mit
1
union {
2
  u16 var16;
3
  struct{
4
    u8 var81;
5
    u8 var82;
6
  };
7
}meinvar;
8
#define MV0  SBIT(meinvar.var81,0)
9
#define MV1  SBIT(meinvar.var81,1)
10
#define MV15  SBIT(meinvar.var82,7)
 und auch mit
1
union {
2
  u16 var16;
3
  u8 var8[2];
4
}meinvar;
5
#define MV0  SBIT(meinvar.var8[0],0)
6
#define MV1  SBIT(meinvar.var8[0],1)
7
#define MV15  SBIT(meinvar.var8[1],7)
.
Die erste Variante ist, was ich eigentlich möchte: ohne Tricks mit union 
einfach eine Bitvariable als Teil schon längst vorhandener Variable 
definieren können.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

auch wenn ich mich wiederhole. Wozu benötigst du ein define dafür? Du 
hast doch mit dem struct etc. schon eine ganz klare Variablendefinition 
die du verwenden kannst und auch solltest. Schreibe dir eine ganz 
normale WBIT Funktion zum manipulieren. Und falls du das einfacher haben 
möchtest, nimm das array Bsp. Du hast dich irgendwie auf das define 
versteift und hängst jetzt gedanklich darin fest, so meine Vermutung.

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


Lesenswert?

Am Ende ist die Frage, was man damit überhaupt anstellen will. Bits 
sparen? Ist dein RAM wirklich schon bis auf die letzten paar Bits 
ausgereizt, dass das lohnt? Der generierte Code wird für Daten im RAM 
auf jeden Fall umständlich. Pro gespartem RAM-Byte verplemperst du damit 
einige Flash-Worte.

Wirklich lohnen tun sich Bitvariablen eigentlich nur auf solchen 
IO-Ports, die sich direkt per SBI oder CBI zugreifen lassen. Beim 
ATmega644 kommt dafür eigentlich nur GPIOR0 in Frage – es sei denn, man 
benutzt von Port A bis D irgendwas nicht und kann deren Steuerregister 
missbrauchen.

Falls es tasächlich Bitfelder in Strukturen sind, dann stimme ich völlig 
zu: verkneif dir die Makro-Orgien dafür.

von mh (Gast)


Lesenswert?

Veit D. schrieb:
> Oder ganz anders, leg dir ein Array an. Hätte den Vorteil du kannst mit
> for Schleifen drüber gehen.

Und den Nachteil, dass es 16 statt 2 Byte benötigt.

von A. S. (achs)


Lesenswert?

Maxim B. schrieb:
> #define MV0  SBIT(meinvar.var81,0)

Welche Fehlermeldung kommt denn damit? Wenn es nur darum geht, dass die 
Struktur keinen Namen hat, dann gib ihr einen.

Schöner/einfacher machen kannst Du später.

von A. S. (achs)


Lesenswert?

Versuch Mal
1
#define SBIT(var, idx, pin) ((struct bits*)  ((u8*)&port)))[idx].b##pin)
2
...
3
#define MV0 SBIT(myvar, 0, 0)
4
...
5
#define MV15 SBIT(myvar, 1, 7)

: Bearbeitet durch User
von mh (Gast)


Lesenswert?

A. S. schrieb:
> Versuch Mal

Das sieht nicht so aus, als könnte es funktionieren. port soll 
vermutlich var sein und das sieht nach UB aus.

von A. S. (achs)


Lesenswert?

mh schrieb:
> port soll vermutlich var sein und das sieht nach UB aus.

Ja, var.

Aber nicht mehr UB als jede andere Version. Funktional das gleiche wie 
im Eingangsthread, nur (vermutlich) ohne die Warnung. Das war ja das 
Ziel.

von mh (Gast)


Lesenswert?

A. S. schrieb:
> Funktional das gleiche wie
> im Eingangsthread, nur (vermutlich) ohne die Warnung. Das war ja das
> Ziel.

Du möchtest das UB verstecken? In diesem Fall hast du es vermutlich 
geschafft. Ich hab zumindest keine Ahnung was das Makro machen soll. Und 
das hat nur zum Teil mit den fehlerhaften Klammern zu tun.

von Maxim B. (max182)


Lesenswert?

Jörg W. schrieb:
> Der generierte Code wird für Daten im RAM
> auf jeden Fall umständlich.

Was ich jetzt bekomme, ist in Ordnung:
1
struct wbits {
2
  u8 b0:1;
3
  u8 b1:1;
4
  u8 b2:1;
5
  u8 b3:1;
6
  u8 b4:1;
7
  u8 b5:1;
8
  u8 b6:1;
9
  u8 b7:1;
10
  u8 b8:1;
11
  u8 b9:1;
12
  u8 b10:1;
13
  u8 b11:1;
14
  u8 b12:1;
15
  u8 b13:1;
16
  u8 b14:1;
17
  u8 b15:1;
18
} __attribute__((__packed__));
19
20
#define WBIT_(port,pin) ((*(volatile struct wbits*)&port).b##pin)
21
#define  WBIT(x,y)  WBIT_(x,y)
22
23
u16 mvar = 0;
24
#define MVB9  WBIT(mvar,9)
25
26
MVB9 = 1;
27
MVB9 = 0;
1
LDS       R24,0x0103 
2
ORI       R24,0x02
3
STS       0x0103,R24
4
LDS       R24,0x0103
5
ANDI      R24,0xFD
6
STS       0x0103,R24
noch kürzer geht es einfach nicht. Auch mit Assembler nicht.

A. S. schrieb:
> Welche Fehlermeldung kommt denn damit?

../meindefs.h:67:45: warning: dereferencing type-punned pointer will 
break strict-aliasing rules [-Wstrict-aliasing]
../meindefs.h:68:19: note: in expansion of macro 'WBIT_'
../main.c:19:14: note: in expansion of macro 'WBIT'
 #define MVB9 WBIT(mvar,9)

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


Lesenswert?

Maxim B. schrieb:
> noch kürzer geht es einfach nicht.

Doch: ganze Bytes benutzen statt einzelner Bits.

Daher habe ich ja gefragt, was du damit am Ende bezweckst. Das scheint 
aber so innovativ zu sein, dass du diese Antwort schuldig bleibst …

von Maxim B. (max182)


Lesenswert?

Jörg W. schrieb:
> Doch: ganze Bytes benutzen statt einzelner Bits.

Das wird gleiche Code.

Z.B. ich möchte in einer Var auf Bit13 warten und etwas machen, wenn 
gesetzt.
Statt separate #define für Set, Reset und Prüe zu schreiben, nur mit 
einem hantieren.

: Bearbeitet durch User
von mh (Gast)


Lesenswert?

Maxim B. schrieb:
> warning: dereferencing type-punned pointer will
> break strict-aliasing rules [-Wstrict-aliasing]
Hast du mittlerweile rausgefunden, warum du diese Warnung bekommst und 
was sie bedeutet?

von A. S. (achs)


Lesenswert?

Maxim B. schrieb:
> ../meindefs.h:67:45: warning:

Beim letzten gezeigten Code, oder bei beiden?

Bei "meinem" define auch (abgesehen von den Tippfehlern)

von Maxim B. (max182)


Lesenswert?

mh schrieb:
> Hast du mittlerweile rausgefunden, warum du diese Warnung bekommst und
> was sie bedeutet?

Das ist die Frage, weshalb ich hier schreibe. Bisher habe ich nur eine 
Antwort: das ist für 8bit-Var möglich und für mehr_als_8_bit_var nicht 
möglich, weil Compiler so geschrieben wurde.

von mh (Gast)


Lesenswert?

Maxim B. schrieb:
> mh schrieb:
>> Hast du mittlerweile rausgefunden, warum du diese Warnung bekommst und
>> was sie bedeutet?
>
> Das ist die Frage, weshalb ich hier schreibe. Bisher habe ich nur eine
> Antwort: das ist für 8bit-Var möglich und für mehr_als_8_bit_var nicht
> möglich, weil Compiler so geschrieben wurde.
Hast du schonmal google befragt? Ich bekomme da haufenweise korrekte und 
umfangreiche Erklärungen.

von Maxim B. (max182)


Lesenswert?

A. S. schrieb:
> Beim letzten gezeigten Code, oder bei beiden?

Bei allen Varianten. Wenn ich am ersten Mal nach Ändern Debug starte, 
kommen diese Fehlerschreibungen. Stop Debug - Noch mal Compiler und 
start Debug -> keine Warnings mehr. In allen Varianten über 8 bit. Mit 8 
bit keine Fehlermeldungen überhaupt.

von A. S. (achs)


Lesenswert?

Maxim B. schrieb:
> weil Compiler so geschrieben wurde.

Nein. Ist C. Type punning nur über ints gleicher Breite oder Char.

Probier es doch Mal und zeig Code und Warnung.

von Maxim B. (max182)


Lesenswert?

mh schrieb:
> Hast du schonmal google befragt?

Wenn ich Google frage, bekomme ich Tausend Angebote, etwas zu kaufen. 
Mehr nicht :)

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


Lesenswert?

Maxim B. schrieb:
> Z.B. ich möchte in einer Var auf Bit13 warten

Ja, weil man ja jeden Tag auf Bits in einer Variablen wartet …

Ich hatte dich gefragt, wofür das gut sein sollte – und warum es denn 
partout einzelne Bits sein müssen.

Falls das irgendwelche Kommunikationsstrukturen sind, gut, aber dann 
benenne lieber die Bitfelder vernünftig und spar dir das Makro-Gehampel. 
Es ist dann allemal sinnvoller, sowas zu schreiben:
1
   while (!device_status.ready) {
2
     /* wait here */
3
   }

statt
1
  while (!MV15) {
2
    /* wait */
3
  }

Vergiss nicht, dass du da auch noch irgendwas auf "volatile" setzen 
musst, wenn du sowas vorhast. Daher ja auch die Frage: beschreibe lieber 
dein gesamtes Problem, nicht nur die Sackgasse, in die du dich gerade 
verrannt hast.

ps: Makros sind Sch***e. Benutze sie sparsam und nur dort, wo sie 
tatsächlich in irgendeiner Weise helfen.

: Bearbeitet durch Moderator
von Maxim B. (max182)


Lesenswert?

A. S. schrieb:
> Probier es doch Mal und zeig Code und Warnung.
mydefs.h
1
struct wbits {
2
  u8 b0:1;
3
  u8 b1:1;
4
  u8 b2:1;
5
  u8 b3:1;
6
  u8 b4:1;
7
  u8 b5:1;
8
  u8 b6:1;
9
  u8 b7:1;
10
  u8 b8:1;
11
  u8 b9:1;
12
  u8 b10:1;
13
  u8 b11:1;
14
  u8 b12:1;
15
  u8 b13:1;
16
  u8 b14:1;
17
  u8 b15:1;
18
} __attribute__((__packed__));
19
20
#define WBIT_(port,pin) ((*(volatile struct wbits*)&port).b##pin)
21
#define  WBIT(x,y)  WBIT_(x,y)
mein.c
1
u16 mvar = 0;
2
#define MVB9  WBIT(mvar,9)
3
4
int main(void){ 
5
  asm volatile("nop");
6
  MVB9 = 1;
7
  MVB9 = 0;
8
  asm volatile("nop");
9
while(1){
10
  asm volatile("nop");
11
  asm volatile("nop");
12
  asm volatile("nop");
13
  asm volatile("nop");
14
  asm volatile("nop");
15
}
16
return 0;
17
}

Erste debug:
../meindefs.h:67:45: warning: dereferencing type-punned pointer will 
break strict-aliasing rules [-Wstrict-aliasing]
../meindefs.h:68:19: note: in expansion of macro 'WBIT_'
../main.c:19:14: note: in expansion of macro 'WBIT'
 #define MVB9 WBIT(mvar,9)

Build succeeded with 2 Warnings...


nochmal compilieren und start debug
Build succeeded with 0 Warnings...

von Maxim B. (max182)


Lesenswert?

Jörg W. schrieb:
> Ich hatte dich gefragt, wofür das gut sein sollte – und warum es denn
> partout einzelne Bits sein müssen.
>
> Falls das irgendwelche Kommunikationsstrukturen sind, gut, aber dann
> benenne lieber die Bitfelder vernünftig und spar dir das Makro-Gehampel.

Na klar, ich kann notfalls alles auf 8bit-Teilvariablen teilen. Wenn 
direkt mit 16bit-var nicht geht... Oder geht, aber so komisch, mal 
warning, mal nicht... Einfach eine Alternative.

: Bearbeitet durch User
von mh (Gast)


Lesenswert?

Maxim B. schrieb:
> Oder geht, aber so komisch, mal
> warning, mal nicht... Einfach eine Alternative.

Du solltest vielleicht erstmal deine Werkzeuge kennenlernen. Du hast 
hier ein Problem beim Umgang mit deiner IDE und ein Problem mit dem 
Verständnis von C.

von Maxim B. (max182)


Lesenswert?

Jörg W. schrieb:
> Daher ja auch die Frage: beschreibe lieber
> dein gesamtes Problem, nicht nur die Sackgasse, in die du dich gerade
> verrannt hast.

Ich möchte freien Zugang zu Bitvariablen unabhängig davon, ob sie in 
8bit-var oder anders physisch verpackt sind. Schließlich ermöglicht C 
Zugang zu byte-variablen unabhängig von ihrer Byte-Größe, einfach mit 
Namen. So möchte ich das auch mit bits. Einfach schreiben: bit=1. Oder 
bit=0. Statt für Setzen und Löschen verschiedene Defs oder gar 
Funktionen zu schreiben.

Wozu ich das brauche? Ich finde schon, wozu. Wenn ich damit auf 
Compiler-Grenze komme - gut, das ist auch gut, zu wissen, wo Compiler 
Grenzen hat.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Maxim B. schrieb:
> Wozu ich das brauche? Ich finde schon, wozu.

Ah, eine Lösung ohne Problem.

Sorry, da bin ich dann raus, dafür ist mir meine Zeit zu schade.

von Maxim B. (max182)


Lesenswert?

mh schrieb:
> Du hast
> hier ein Problem beim Umgang mit deiner IDE und ein Problem mit dem
> Verständnis von C.

Klar. Hätte ich das nicht, würde ich alles wissen - wozu dann hier 
schreiben?

von Maxim B. (max182)


Lesenswert?

Jörg W. schrieb:
> Sorry, da bin ich dann raus, dafür ist mir meine Zeit zu schade.

Danke für Ihre Hilfsbereitschaft.

von A. S. (achs)


Lesenswert?

Maxim B. schrieb:
> Build succeeded with 2 Warnings...

Die Warnungen waren doch schon im ersten Post und erklärt (Cast auf 
nicht Char). Hast Du eine Version mit u8 noch Mal versucht? Die sollten 
ohne Warnung geben, auch mit (nacher) 16 Bit.

: Bearbeitet durch User
von Maxim B. (max182)


Lesenswert?

A. S. schrieb:
> Hast Du eine Version mit u8 noch Mal versucht? Die sollten
> ohne Warnung geben, auch mit (nacher) 16 Bit.

Ja, ich habe das versucht.
Komisch, daß das so ist: einmal Warning, bei wiederholten Compielen 
keine Warning... Warum so? Macht Compiler zuerst Panik, dann kuckt: 
alles geht doch?

von mh (Gast)


Lesenswert?

Maxim B. schrieb:
> Komisch, daß das so ist: einmal Warning, bei wiederholten Compielen
> keine Warning... Warum so? Macht Compiler zuerst Panik, dann kuckt:
> alles geht doch?

Das wirds sein, der Compiler bekommt ne Panikattacke... Wie genau 
rufst du nochmal den Compiler auf?

von A. S. (achs)


Lesenswert?

Maxim B. schrieb:
> bei wiederholten Compielen keine Warning

Das stand hier:

A. S. schrieb:
> Die sind nicht weg:
> Der compiliert nicht, wenn keine Fehler da sind.

von A. S. (achs)


Lesenswert?

Maxim B. schrieb:
> Ja, ich habe das versucht

Und gab es da die gleiche Warnung? Falls ja, poste den Code dazu.

von Hugo H. (hugohurtig1)


Lesenswert?

Ich weiß zwar nicht wozu, aber damit kannst Du Spielen:
1
#include <avr/io.h>
2
3
typedef struct
4
{
5
  uint16_t bit0:1;
6
  uint16_t bit1:1;
7
  uint16_t bit2:1;
8
  uint16_t bit3:1;
9
  uint16_t bit4:1;
10
  uint16_t bit5:1;
11
  uint16_t bit6:1;
12
  uint16_t bit7:1;
13
  uint16_t bit8:1;
14
  uint16_t bit9:1;
15
  uint16_t bit10:1;
16
  uint16_t bit11:1;
17
  uint16_t bit12:1;
18
  uint16_t bit13:1;
19
  uint16_t bit14:1;
20
  uint16_t bit15:1;
21
}
22
Bit_Leiste;
23
24
typedef union
25
{
26
  Bit_Leiste Wort_Bits;
27
}
28
Bit_Wort;
29
30
Bit_Wort V_Bit_Wort;
31
32
int main(void)
33
{
34
  while (1)
35
  {
36
    V_Bit_Wort.Wort_Bits.bit3 = 1;
37
  }
38
}

von Nop (Gast)


Lesenswert?

Maxim B. schrieb:

> mydefs.hstruct wbits {
...
> #define WBIT_(port,pin) ((*(volatile struct wbits*)&port).b##pin)
...
> u16 mvar = 0;

Du legst eine Variable vom Typ u16 an, was wohl ein uint16_t sein wird. 
Solltest Du Dir eh angewöhnen, für sowas die Standardtypen zu nehmen. 
Dann gewinnst Du mit dem & deren Adresse und castest das auf einen 
Pointer auf ein struct um, den Du dann dereferenzierst.

Genau das ist in C eben undefined behaviour, deswegen meckert der 
Compiler. Wenn Du das über eine union machen willst, dann muß die Union 
nicht nur in Deinem Define-Verhau sein, sondern auch mvar muß von diesem 
Uniontyp sein und nicht u16.

Wenn Du mit einer u16-Variable arbeiten willst, dann laß den ganzen 
Bitfield-Unsinn weg und nimm zwei Macros.
1
#define SET_BIT(var, bit) var |= 1U << bit
2
#define RESET_BIT(var, bit) var &= ~(1U << bit)

von Hugo H. (hugohurtig1)


Lesenswert?

Ohne Union geht natürlich auch:
1
#include <avr/io.h>
2
3
typedef struct
4
{
5
  uint16_t bit0:1;
6
  uint16_t bit1:1;
7
  uint16_t bit2:1;
8
  uint16_t bit3:1;
9
  uint16_t bit4:1;
10
  uint16_t bit5:1;
11
  uint16_t bit6:1;
12
  uint16_t bit7:1;
13
  uint16_t bit8:1;
14
  uint16_t bit9:1;
15
  uint16_t bit10:1;
16
  uint16_t bit11:1;
17
  uint16_t bit12:1;
18
  uint16_t bit13:1;
19
  uint16_t bit14:1;
20
  uint16_t bit715:1;
21
}
22
Bit_Leiste;
23
24
Bit_Leiste Wort_Bits;
25
26
27
int main(void)
28
{
29
  while (1)
30
  {
31
    Wort_Bits.bit3 = 1;
32
  }
33
}

von Maxim B. (max182)


Lesenswert?

mh schrieb:
> Wie genau
> rufst du nochmal den Compiler auf?

Über AVR Studio 4.19. Einfach bequem, über JTAG alles zu sehen.

von Maxim B. (max182)


Lesenswert?

Hugo H. schrieb:
> Ohne Union geht natürlich auch:
...

Danke! ich versuche gleich.
Ich habe ja geschrieben: Kinderfrage. Ich weiß noch vieles nicht...

Ich mache langsam persönliche mydefs.h. Ich nehme File einfach in alle 
Projekte mit. So ist meine Interesse, die Lösungen zu haben, die für 
mydefs.h geeignet sind.

: Bearbeitet durch User
von mh (Gast)


Lesenswert?

Maxim B. schrieb:
> mh schrieb:
>> Wie genau
>> rufst du nochmal den Compiler auf?
>
> Über AVR Studio 4.19. Einfach bequem, über JTAG alles zu sehen.
Wenn das über JTAG alles zu sehen ist, kannst du ja sicher sofort 
erkennen wo dein Problem ist. Also warum der Compiler scheinbar nicht 
immer die Warnung anzeigt.

von Maxim B. (max182)


Lesenswert?

mh schrieb:
> Wenn das über JTAG alles zu sehen ist, kannst du ja sicher sofort
> erkennen wo dein Problem ist. Also warum der Compiler scheinbar nicht
> immer die Warnung anzeigt.

Leider nicht. Compiler ist wie eine Persönlichkeit. Der ist für alles 
fähig und ich weiß nicht immer, was ich von dem zu erwarten habe :)
"Alles zu sehen" bedeutet nichts mehr als Inhalt von Var zu sehen und 
die Funktionen einzeln überprüfen. Aber das ist so bequem...

Natürlich hat IDE auch Beschränkungen. Z.B. 24bit-Var können nicht 
gezeigt werden, obwohl Compiler sie gut versteht.

: Bearbeitet durch User
von A. S. (achs)


Lesenswert?

Maxim B. schrieb:
> Compiler ist wie eine Persönlichkeit. Der ist für alles fähig und ich
> weiß nicht immer, was ich von dem zu erwarten habe :)
> "Alles zu sehen" bedeutet nichts mehr als Inhalt von Var zu sehen und
> die Funktionen einzeln überprüfen. Aber das ist so bequem...

Das war Ironie.

Jtag hat mit dem Compiler nichts zu tun. Höchstens mit der IDE und 
Debugger.

Wenn Du das mit den Warnungen verstehen möchtest, musst Du Dich mit dem 
build-menu beschäftigen und was die Hauptaufgabe eines make ist. Und den 
Output lesen oder zumindest grob vergleichen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Maxim B. schrieb:
> Über AVR Studio 4.19.

Dort kannst Du die Compiler-Optionen anpassen.

Füge dort -Werror hinzu, dann behandelt der Compiler Warnungen wie 
Fehler und es kommt nicht dazu, dass er den Source trotzdem übersetzt. 
Das wird nämlich der Grund sein, warum Du beim Compilieren manchmal eine 
Warnung siehst und manchmal nicht. Erfolgreich compilierte Sources 
werden nämlich nur neu übersetzt, wenn man sie danach auch ändert.

von mh (Gast)


Lesenswert?

Frank M. schrieb:
> Füge dort -Werror hinzu, dann behandelt der Compiler Warnungen wie
> Fehler und es kommt nicht dazu, dass er den Source trotzdem übersetzt.
> Das wird nämlich der Grund sein, warum Du beim Compilieren manchmal eine
> Warnung siehst und manchmal nicht. Erfolgreich compilierte Sources
> werden nämlich nur neu übersetzt, wenn man sie danach auch ändert.

Bist du sicher, dass er nicht "-Wno-strict-aliasing" nutzen möchte? Ziel 
ist es doch die Warnung zu beseitigen und nicht die Ursache.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

mh schrieb:
> Bist du sicher, dass er nicht "-Wno-strict-aliasing" nutzen möchte?

Meine Antwort war lediglich eine Antwort auf seine Aussage, die 
Warnungen würde nur manchnmal erscheinen.

> Ziel ist es doch die Warnung zu beseitigen und nicht die Ursache.

Ziel wäre es meiner Meinung nach, sauberen Code zu schreiben statt 
Warnungen einfach unter den Teppich zu kehren.

Ich übersetze meinen Code grundsätzlich mit:
1
-Wall -Wextra -Werror

Ich halte das Anliegen des TOs, C-Code derart umzuschreiben, dass dieser 
ihm "komfortabler" erscheint, lediglich für eine Momentaufnahme. In ein 
bis zwei Jahren mit mehr Erfahrung kann sich dies wieder umkehren und er 
wird dann vielleicht wieder klar lesbaren unverwaschenen C-Code 
vorziehen - oder direkt auf C++ wechseln.

Von daher halte ich den Aufwand mit den Bitfeldern, den er hier treibt, 
einfach nur für pure Zeitverschwendung. Ich persönlich benutze niemals 
Bitfelder, höchstens einzelne Bits in Bytes, die man mit Bitmasken gut 
bearbeiten kann. Dadurch wird der C-Code auch nicht schwieriger, wenn 
man nach einiger Zeit darin geübt ist - ganz im Gegenteil:

Bei
1
#define BUSY_BIT 5
2
if (a & (1 << BUSY_BIT))
weiß ich sofort, was Sache ist.

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


Lesenswert?

Frank M. schrieb:
> Ich persönlich benutze niemals Bitfelder

Naja, man kann sie schon benutzen, wenn man sich über ihre Implikationen 
im Klaren ist (also inbesondere darüber, dass praktisch alles dabei 
"implementation-defined" ist).

Aber dieser Makro-Zirkus drumrum, nur um die Bits einer 16-Bit-Zahl mit 
Bitnummern zugreifen zu können, bringt's nicht. Wenn schon Bitfelder, 
dann sollte man ihnen saubere, selbst erklärende Namen geben. Das geht 
natürlich nur im Kontext dessen, was man damit dann wirklich macht.

von mh (Gast)


Lesenswert?

Frank M. schrieb:
> mh schrieb:
>> Bist du sicher, dass er nicht "-Wno-strict-aliasing" nutzen möchte?
>
> Meine Antwort war lediglich eine Antwort auf seine Aussage, die
> Warnungen würde nur manchnmal erscheinen.
>
>> Ziel ist es doch die Warnung zu beseitigen und nicht die Ursache.
>
> Ziel wäre es meiner Meinung nach, sauberen Code zu schreiben statt
> Warnungen einfach unter den Teppich zu kehren.
Um diese Ziel zu erreichen, sollte er den Umgang mit seinen Werkzeugen 
lernen. In diesem Fall den C Standard und seine IDE. Der TO hat aber bis 
jetzt anscheind nichmal versucht selbstständig rauszufinden was es mit 
dieser Warnung auf sich hat. Weder was die Warnung bedeutet, noch warum 
sie nur manchmal auftaucht.
Beide Compiler-Optionen helfen ihm nicht wirklich weiter auf dem Weg zum 
Ziel.

Frank M. schrieb:
> Ich übersetze meinen Code grundsätzlich mit:-Wall -Wextra -Werror
Bei mir ist es grundsätzlich -std=WasAuchImmer -Wall -Wextra -Wpedantic 
und mehr als 10 weitere Warnungen. -Werror kommt bei mir nicht in die 
Liste. Ich bevorzuge die zusätzliche Information, die ich bei der 
Unterscheidung habe. Warnungen sind Warnungen und Fehler sind Fehler. 
"unused variable" oder "conversion may change value" sind keine Fehler 
Fehler die ich sofort beheben muss.

Frank M. schrieb:
> Bei#define BUSY_BIT 5
> if (a & (1 << BUSY_BIT))
> weiß ich sofort, was Sache ist.
Ich muss erst Klammern überprüfen, bevor ich weiß was genau passiert.
Ein
1
if(a.busy_bit)
ist für mich deutlich einfacher zu erfassen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

mh schrieb:
> Bei mir ist es grundsätzlich -std=WasAuchImmer -Wall -Wextra -Wpedantic

Ja, -Wpedantic setze ich auch gerne ein, aber oft muss ich leider darauf 
verzichten, weil die zusätzlichen Source-Libs vom Hersteller (wie z.B. 
CMSIS oder andere Referenzimplementationen von ST) dabei nicht unbedingt 
erfolgreich durch den Compiler gehen. Das ist dann ärgerlich.

> Ich bevorzuge die zusätzliche Information, die ich bei der
> Unterscheidung habe. Warnungen sind Warnungen und Fehler sind Fehler.
> "unused variable" oder "conversion may change value" sind keine Fehler
> Fehler die ich sofort beheben muss.

Mir ist es öfters schon passiert, dass ich Warnungen beim Übersetzen von 
mehreren C-Übersetzungseinheiten überlesen habe, weil dann plötzlich in 
der nächsten Datei ein Fehler mit gaaaaanz vielen Folgefehlern 
ausgegeben werden.

Was macht man dann? Man behebt den oder die offensichtlichen Fehler und 
übersetzt aufs Neue. Da die vorherige Datei trotz der einen Warnung 
schon vorher erfolgreich übersetzt wurde, geht einem diese bei der 
nächsten Übersetzungsorgie (per make oder IDE) durch die Lappen, weil 
sie nicht mehr neu übersetzt wird. Am Ende sieht alles okay aus - aber 
das ist es nicht notwendigerweise.

Bei -Werror bleibt das Ding bei der ersten Warnung stehen und muss 
erstmal bearbeitet werden.

Ohne -Werror muss man, um die übersehenen Warnungen noch einmal zu 
reproduzieren, alles zurücksetzen und das Makefile bzw. die IDE dazu 
zwingen, alles nochmal komplett neu zu übersetzen. Das kostet u.U. Zeit, 
die ich nicht verschwenden will.

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

mh schrieb:
> Ich muss erst Klammern überprüfen, bevor ich weiß was genau passiert.
> Ein
> if(a.busy_bit)
>
> ist für mich deutlich einfacher zu erfassen.

Das ist Geschmackssache und auch eine Sache der Leseübung. Die 
Bezeichnung "a.busy_bit" ist ja auch okay, aber der TO möchte solche 
generischen Makros wie M1, M2, M3 einsetzen, die absolut nichtssagend 
sind. Von daher wird sein Source dann eher unleserlicher und auch 
unverständlicher. Daran störte sich auch schon Jörg - viel weiter oben.

: Bearbeitet durch Moderator

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.