Forum: Mikrocontroller und Digitale Elektronik "value computed not used"


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,
ich nutze den AVR-GCC und das folgende Konstrukt:
1
    // Port mit Pin-Bitmaske als Eingang mit Pull-Up setzen
2
    #define gpio_setInputPU(PORT,PIN) (\
3
        (&PORT==&PORTA) ? (DDRA &= ~PIN, PORTA |= PIN) :\
4
      ( (&PORT==&PORTB) ? (DDRB &= ~PIN, PORTB |= PIN) :\
5
      ( (&PORT==&PORTC) ? (DDRC &= ~PIN, PORTC |= PIN) :\
6
      ( (&PORT==&PORTD) ? (DDRD &= ~PIN, PORTD |= PIN) :\
7
      0 ) ) )\
8
      )
9
10
    #define ENC_A_GPIO PORTC
11
    #define ENC_A_Pin  (1<<PC3)
12
// ...
13
int main(void)
14
{
15
    gpio_setInputPU(ENC_A_GPIO,ENC_A_Pin);
16
17
    //...
und der Compiler warnt mich (zu Recht) mit der Meldung des Threadtitels.

Nur wie überzeuge ich ihn davon, daß das in diesem Fall Absicht ist?

Viele Grüße
W.T.

P.S.: Für all jene, die sonst den ganzen Nachmittag ein mulmiges Gefühl 
im Bauch hätten:
1
}

von Daniel A. (daniel-a)


Lesenswert?

Ich verwende bei vorerst ungenutzten variablen ein cast nach void. 
Könnte auch hier funktionieren.

(void)(1+2);

Dann gibts nähmlich kein ungenutztes ergebnis mehr, weil 1+2 beim cast 
benutzt wird und das ergebnis void nunmal kein ergebnis ist.

Hier wäre jedoch ein if/else konstrukt sinnvoller.

: Bearbeitet durch User
von public (Gast)


Lesenswert?

heyho,

deine "Funktion" liefert einen Rückgabewert mit dem nichts gemacht wird.
Mach eine richtige Funktion draus, oder ein switch-case...

beste grüße
public

von Tim S. (tim_seidel) Benutzerseite


Lesenswert?

Ich würde davon absehen #define als Ersatz für Funktionen zu nutzen.
Es mag im ersten Moment elegant aussehen, aber es ist Gift für die 
Wartbarkeit und aufgrund der Wirkungsweise anfällig für Operator-Binding 
Probleme.

An Zweiteres hast du z.B. bei der Definition von
1
    #define gpio_setInputPU(PORT,PIN) (\
2
        (&PORT==&PORTA) ? (DDRA &= ~PIN, PORTA |= PIN) :\
3
      ( (&PORT==&PORTB) ? (DDRB &= ~PIN, PORTB |= PIN) :\
4
      ( (&PORT==&PORTC) ? (DDRC &= ~PIN, PORTC |= PIN) :\
5
      ( (&PORT==&PORTD) ? (DDRD &= ~PIN, PORTD |= PIN) :\
6
      0 ) ) )\
7
      )
nicht bedacht. Mit nicht-literalen ungeklammerten Ausdrücken macht dein 
define Unsinn. Beispiel:
1
    gpio_setInputPU(PORTC, (1 << 1) | (1 << 2));

=>
1
    #define gpio_setInputPU(PORT,PIN) (\
2
        (&PORTC==&PORTA) ? (DDRA &= ~(1 << 1) | (1 << 2), PORTA |= (1 << 1) | (1 << 2)) :\
3
      ( (&PORTC==&PORTB) ? (DDRB &= ~(1 << 1) | (1 << 2), PORTB |= (1 << 1) | (1 << 2)) :\
4
      ( (&PORTC==&PORTC) ? (DDRC &= ~(1 << 1) | (1 << 2), PORTC |= (1 << 1) | (1 << 2)) :\
5
      ( (&PORTC==&PORTD) ? (DDRD &= ~(1 << 1) | (1 << 2), PORTD |= (1 << 1) | (1 << 2)) :\
6
      0 ) ) )\
7
      )

Das ist offensichtlich nicht das, was der Name beschreibt.

Daher: Defines sind keine Funktionen!

von Walter T. (nicolas)


Lesenswert?

Hng, da habe ich Klammern vergessen. Danke für's Entdecken!

Tim Seidel schrieb:
> Es mag im ersten Moment elegant aussehen,

Ich finde Präprozessorgefrickel keineswegs elegant - aber manchmal 
unvermeidbar. Aus dem folgenden:
1
     static inline __attribute__((always_inline)) void
2
     gpio_setInputPU(uint8_t PORT,const uint16_t Pin)
3
     {
4
         if(PORT==PORTA) {
5
             DDRA  &= ~Pin;
6
             PORTA |= Pin;
7
         }
8
         else if (PORT==PORTB) {         
9
             DDRB  &= ~Pin;
10
             PORTB |= Pin;
11
         }
12
         else if (PORT==PORTC) {
13
             DDRC  &= ~Pin;
14
             PORTC |= Pin;
15
         }         
16
         else if (PORT==PORTD) {
17
             DDRD  &= ~Pin;
18
             PORTD |= Pin;
19
         }
20
     }
macht der AVR-GCC das hier:
1
    // I/O einstellen
2
    void encoder_init(void)
3
    {
4
        gpio_setInputPU(ENC_A_GPIO,ENC_A_Pin);
5
    4084:  85 b3         in  r24, 0x15  ; 21
6
            )
7
8
     static inline __attribute__((always_inline)) void
9
     gpio_setInputPU(uint8_t PORT,const uint16_t Pin)
10
     {
11
         if(PORT==PORTA) {
12
    4086:  9b b3         in  r25, 0x1b  ; 27
13
    4088:  89 13         cpse  r24, r25
14
    408a:  03 c0         rjmp  .+6        ; 0x4092 <encoder_init+0xe>
15
             DDRA  &= ~Pin;
16
    408c:  d2 98         cbi  0x1a, 2  ; 26
17
             PORTA |= Pin;
18
    408e:  da 9a         sbi  0x1b, 2  ; 27
19
    4090:  11 c0         rjmp  .+34       ; 0x40b4 <encoder_init+0x30>
20
         }
21
         else if (PORT==PORTB) {         
22
    4092:  98 b3         in  r25, 0x18  ; 24
23
    4094:  89 13         cpse  r24, r25
24
    4096:  03 c0         rjmp  .+6        ; 0x409e <encoder_init+0x1a>
25
             DDRB  &= ~Pin;
26
    4098:  ba 98         cbi  0x17, 2  ; 23
27
             PORTB |= Pin;
28
    409a:  c2 9a         sbi  0x18, 2  ; 24
29
    409c:  0b c0         rjmp  .+22       ; 0x40b4 <encoder_init+0x30>
30
         }
31
         else if (PORT==PORTC) {
32
    409e:  95 b3         in  r25, 0x15  ; 21
33
    40a0:  89 13         cpse  r24, r25
34
    40a2:  03 c0         rjmp  .+6        ; 0x40aa <encoder_init+0x26>
35
             DDRC  &= ~Pin;
36
    40a4:  a2 98         cbi  0x14, 2  ; 20
37
             PORTC |= Pin;
38
    40a6:  aa 9a         sbi  0x15, 2  ; 21
39
    40a8:  05 c0         rjmp  .+10       ; 0x40b4 <encoder_init+0x30>
40
         }         
41
         else if (PORT==PORTD) {
42
    40aa:  92 b3         in  r25, 0x12  ; 18
43
    40ac:  89 13         cpse  r24, r25
44
    40ae:  02 c0         rjmp  .+4        ; 0x40b4 <encoder_init+0x30>
45
             DDRD  &= ~Pin;
46
    40b0:  8a 98         cbi  0x11, 2  ; 17
47
             PORTD |= Pin;
48
    40b2:  92 9a         sbi  0x12, 2  ; 18
49
        gpio_setInputPU(ENC_B_GPIO,ENC_B_Pin);
50
    40b4:  85 b3         in  r24, 0x15  ; 21
51
            )
52
53
     static inline __attribute__((always_inline)) void
54
     gpio_setInputPU(uint8_t PORT,const uint16_t Pin)
55
     {
56
         if(PORT==PORTA) {
57
    40b6:  9b b3         in  r25, 0x1b  ; 27
58
    40b8:  89 13         cpse  r24, r25
59
    40ba:  03 c0         rjmp  .+6        ; 0x40c2 <encoder_init+0x3e>
60
             DDRA  &= ~Pin;
61
    40bc:  d3 98         cbi  0x1a, 3  ; 26
62
             PORTA |= Pin;
63
    40be:  db 9a         sbi  0x1b, 3  ; 27
64
    40c0:  08 95         ret
65
         }
66
         else if (PORT==PORTB) {         
67
    40c2:  98 b3         in  r25, 0x18  ; 24
68
    40c4:  89 13         cpse  r24, r25
69
    40c6:  03 c0         rjmp  .+6        ; 0x40ce <encoder_init+0x4a>
70
             DDRB  &= ~Pin;
71
    40c8:  bb 98         cbi  0x17, 3  ; 23
72
             PORTB |= Pin;
73
    40ca:  c3 9a         sbi  0x18, 3  ; 24
74
    40cc:  08 95         ret
75
         }
76
         else if (PORT==PORTC) {
77
    40ce:  95 b3         in  r25, 0x15  ; 21
78
    40d0:  89 13         cpse  r24, r25
79
    40d2:  03 c0         rjmp  .+6        ; 0x40da <encoder_init+0x56>
80
             DDRC  &= ~Pin;
81
    40d4:  a3 98         cbi  0x14, 3  ; 20
82
             PORTC |= Pin;
83
    40d6:  ab 9a         sbi  0x15, 3  ; 21
84
    40d8:  08 95         ret
85
         }         
86
         else if (PORT==PORTD) {
87
    40da:  92 b3         in  r25, 0x12  ; 18
88
    40dc:  89 13         cpse  r24, r25
89
    40de:  02 c0         rjmp  .+4        ; 0x40e4 <encoder_init+0x60>
90
             DDRD  &= ~Pin;
91
    40e0:  8b 98         cbi  0x11, 3  ; 17
92
             PORTD |= Pin;
93
    40e2:  93 9a         sbi  0x12, 3  ; 18
94
    40e4:  08 95         ret



(für die inline-Funktion kann ich leider kein switch/case verwenden, da 
sich der Datentyp "_SFR_IO8" wohl nicht in ein Int casten läßt.)
Aus dem Makro von oben wird:


1
    // I/O einstellen
2
    void encoder_init(void)
3
    {
4
        gpio_setInputPU(ENC_A_GPIO,ENC_A_Pin);
5
    4084:  a2 98         cbi  0x14, 2  ; 20
6
    4086:  aa 9a         sbi  0x15, 2  ; 21
7
        gpio_setInputPU(ENC_B_GPIO,ENC_B_Pin);
8
    4088:  a3 98         cbi  0x14, 3  ; 20
9
    408a:  ab 9a         sbi  0x15, 3  ; 21
10
    408c:  08 95         ret



und da das Ganze u.A. auch in Bitbanging-Routinen seinen Platz findet, 
ist das schon ein Unterschied.

Und ich sehe gerade, daß ich vorher den Cast nach void, den ich probiert 
hatte, bevor ich die Frage ins Forum stellte, einfach an die falsche 
Stelle gesetzt habe. So ist die Warnung weg:
1
        // Port mit Pin-Bitmaske als Eingang mit Pull-Up setzen
2
        #define gpio_setInputPU(PORT,PIN) (void) (\
3
              (&PORT==&PORTA) ? (DDRA &= ~(PIN), PORTA |= (PIN)) :\
4
            ( (&PORT==&PORTB) ? (DDRB &= ~(PIN), PORTB |= (PIN)) :\
5
            ( (&PORT==&PORTC) ? (DDRC &= ~(PIN), PORTC |= (PIN)) :\
6
            ( (&PORT==&PORTD) ? (DDRD &= ~(PIN), PORTD |= (PIN)) :\
7
             0 ) ) )\
8
            )

Danke für's Lesen!
W.T.

von Rolf Magnus (Gast)


Lesenswert?

Walter Tarpan schrieb:
> Ich finde Präprozessorgefrickel keineswegs elegant - aber manchmal
> unvermeidbar. Aus dem folgenden:     static inline
> __attribute__((always_inline)) void
>      gpio_setInputPU(uint8_t PORT,const uint16_t Pin)

Warum ist PORT ein uint8_t? Das hätte eigentlich eine Adresse sein 
müssen.

>      {
>          if(PORT==PORTA) {

Hier liest du den Wert von PORTA aus (also den Wert, der im Register 
selbst gespeichert ist) und vergleichst den mit dem an die Funktion 
übergebenen uint8_t. Du wolltest wahrscheinlich eine Adresse übergeben 
und die mit der Adresse von PORTA vergleichen. Das läßt sich dann nicht 
nur zur Compilezeit auflösen, sondern ist außerdem noch korrekt.

von Clemens L. (c_l)


Lesenswert?

Walter Tarpan schrieb:
> Ich finde Präprozessorgefrickel keineswegs elegant - aber manchmal
> unvermeidbar. Aus dem folgenden:
>     ...
>     if(PORT==PORTA) {

Das vergleicht nicht mehr die Adresse.

Mit dem üblichem do/while-Trick kann man 'normalen' Code in ein Makro 
packen:
1
#define gpio_setInputPU(PORT,PIN)        \
2
    do {                                 \
3
        if (&(PORT) == &PORTA) {         \
4
            DDRA &= ~(PIN);              \
5
            PORTA |= (PIN);              \
6
        } else if (&(PORT) == &PORTB) {  \
7
            DDRB &= ~(PIN);              \
8
            PORTB |= (PIN);              \
9
        } else                           \
10
            ...                          \
11
    } while (0)
(Aber das Gefrickel mit Klammern und die Gefahr von Seiteneffekten 
bleibt.)

von Tim S. (tim_seidel) Benutzerseite


Lesenswert?

Walter Tarpan schrieb:
> macht der AVR-GCC das hier:

Moment, Schritt zurück.

Es ist ein vollkommen anderer Code. Auslöser des unterschiedlichen 
Kompilats ist nicht der Präprozessor, sondern, dass du den Ablauf und 
die Semantik deines Quellcodes änderst.

Zudem ist deine Funktion falsch. Warum willst du anhand des Port-Inhalts 
entscheiden welcher Port angesprochen wird?
1
     gpio_setInputPU(uint8_t PORT,const uint16_t Pin)
2
     {
3
         if(PORT==PORTA) {
4
...

Analog zu deinem #define:
(Ohne Gewähr, da Copy&Paste ohne Test)
1
     static inline __attribute__((always_inline)) void
2
     gpio_setInputPU(volatile uint8_t &PORT, const uint8_t Pin)
3
     {
4
       (void)(&PORT==&PORTA) ? (DDRA &= ~PIN, PORTA |= PIN) :
5
           ( (&PORT==&PORTB) ? (DDRB &= ~PIN, PORTB |= PIN) :
6
           ( (&PORT==&PORTC) ? (DDRC &= ~PIN, PORTC |= PIN) :
7
           ( (&PORT==&PORTD) ? (DDRD &= ~PIN, PORTD |= PIN) :
8
             0 ) ) ) ;      
9
     }

Das macht das Konstrukt zwar immer noch nicht schön, aber korrigiert, 
dass
a) das #define nicht auf Zeilenebene durchgesteppt werden kann im 
Debugger
b) die Operatoren-Bindings verschleiert werden

von Walter T. (nicolas)


Lesenswert?

Rolf Magnus schrieb:
> Warum ist PORT ein uint8_t? Das hätte eigentlich eine Adresse sein
> müssen.

Stimmt. Ich hatte in freudiger Erwartung des Mittagessens den längst 
gelöschten Kram mal eben eingehackt. So ist es richtig:
1
#define ENC_A_GPIO &PORTC
2
#define ENC_A_Pin  (1<<PC2)
3
4
#define ENC_B_GPIO &PORTC
5
#define ENC_B_Pin  (1<<PC3)
6
7
8
     static inline __attribute__((always_inline)) void
9
     gpio_setInputPU(volatile uint8_t *PORT,const uint8_t Pin)
10
     {
11
         if(PORT==&PORTA) {
12
             DDRA  &= ~Pin;
13
             PORTA |= Pin;
14
         }
15
         else if (PORT==&PORTB) {         
16
             DDRB  &= ~Pin;
17
             PORTB |= Pin;
18
         }
19
         else if (PORT==&PORTC) {
20
             DDRC  &= ~Pin;
21
             PORTC |= Pin;
22
         }         
23
         else if (PORT==&PORTD) {
24
             DDRD  &= ~Pin;
25
             PORTD |= Pin;
26
         }
27
     }
28
29
    void encoder_init(void)
30
    {
31
        gpio_setInputPU(ENC_A_GPIO,ENC_A_Pin);
32
        gpio_setInputPU(ENC_B_GPIO,ENC_B_Pin);
33
    }
und das Ergebnis ist mit der Makro-Version identisch.

Dann werde ich noch einmal sorgfältig nachdenken, warum ich mich damals 
gegen die Inline-Funktion für das Makro entschieden habe und das ggf. 
ändern.

: Bearbeitet durch User
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.