Arduino Parser belügt mich

Gast #5651042
Lesenswert?

Nee der lügt natürlich nicht. Aber es wirkt so.

Ich hab gerade eine Meldung, die ich nicht nachvollziehen kann
1
#define COUNT  54  // Anzahl Digitalpins (Wert 54)
2
#define PIN    A0  // Analoger Pin A0    (Wert 54)
3

4
#if (PIN < COUNT)
5
#error PIN ist zu klein
6
#endif
7

8
void setup() {
9
  Serial.begin(9600);
10
  delay(500);
11
  Serial.print("COUNT = ");
12
  Serial.println(COUNT);
13
  Serial.print("A0 = ");
14
  Serial.println(A0);
15
}
16

17
void loop() {
18
}

Beim compilieren kommt eine Fehlermeldung
1
exit status 1
2
#error PIN ist zu klein

Wenn ich die Prüfung des Makros auskommentiere, compiliert der Code und 
es wird 2x 54 angezeigt, was auch korrekt ist. Und wieso kriegt der 
Parser das nicht hin?
Angehängte Dateien:
Gast #5651052
Lesenswert?

makroOderMeinFehler schrieb:
> Rufus Τ. F. schrieb:
>> Zeig' das #define von A0.
>>
>> Das ist ziemlich sicher nicht der numerische Wert 54.
>
> Ja iwas stimmt nicht. Nur: print gibt für "A0" definitiv 54 aus. Was
> m.E. auch ok ist.

Wie auch immer: Schaue Dir die Definition von A0 an.
Es wird sich vermutlich herausstellen, dass A0 zur Kompilationszeit und 
zur Laufzeit zwei verschiedene Wirkungen hat.
Gast #5651053
Lesenswert?

https://electronics.stackexchange.com/questions/67087/analogread0-or-analogreada0
1
hardware/arduino/avr/variants/standard/pins_arduino.h
2

3
static const uint8_t A0 = 14;
4
static const uint8_t A1 = 15;
5
static const uint8_t A2 = 16;
6
static const uint8_t A3 = 17;
7
static const uint8_t A4 = 18;
8
static const uint8_t A5 = 19;
9
static const uint8_t A6 = 20;
10
static const uint8_t A7 = 21;
Gast #5651057
Lesenswert?

Auszug aus der Datei hardware/arduino/avr/variants/mega:
1
#define PIN_A0   (54)
2
static const uint8_t A0 = PIN_A0;

A0 ist eine Variable im RAM. Auf solche Variablen kann der Präprozessor 
nicht zugreifen.
Gast #5651063
Lesenswert?

at-user schrieb:
> Schonmal drangedacht dass "A0" eine CONST Variable ist und kein
> Präprozessor Makro?

Nee. Aber wenn du recht hast erklärt es den Effekt

In pins_arduino.h ist A0 aber auch definiert
1
#define PIN_A0   (14)
2

3
static const uint8_t A0 = PIN_A0;

hat at-user ja auch gerade geschrieben

Nur dann verstehe ich nicht, wieso 54 ausgegeben wird.

Oder ist A0 ein Pointer und print gibt den Inhalt aus? Ich verstehs noch 
nicht
Gast #5651065
Lesenswert?

Stefanus F. schrieb:
> Auszug aus der Datei hardware/arduino/avr/variants/mega:
>
1
> #define PIN_A0   (54)
2
> static const uint8_t A0 = PIN_A0;
3
>
>
> A0 ist eine Variable im RAM. Auf solche Variablen kann der Präprozessor
> nicht zugreifen.

OK. Der Klick kam langsam. Aber jetzt ist er auch bei mir angekommen.

Vielen Dank :)
Gast #5651066
Lesenswert?

>Nur dann verstehe ich nicht, wieso 54 ausgegeben wird.

54 ist der Inhalt der in der Variable drin steht, die du gerade 
ausliest.
A0 ist kein Pointer, sondern ein ganz normaler Integer.
Println() wandelt dir automatisch deinen Integer in einen String um und 
gibt diesen aus.
Gast #5651082
Lesenswert?

at-user schrieb:
>>Nur dann verstehe ich nicht, wieso 54 ausgegeben wird.
>
> 54 ist der Inhalt der in der Variable drin steht, die du gerade
> ausliest.
> A0 ist kein Pointer, sondern ein ganz normaler Integer.
> Println() wandelt dir automatisch deinen Integer in einen String um und
> gibt diesen aus.


OK noch eine Frage zum verständnis: Was "sieht" der Parser, wenn er A0 
sieht?
Gast #5651096
Lesenswert?

1
#define COUNT  54  // Anzahl Digitalpins (Wert 54)
2
#define PIN    A0  // Analoger Pin A0    (Wert 54)

Und was mir noch -etwas- unklar ist:
PIN wird aber vom Parser bestückt, der den Wert A0 nicht erkennt.
Im Programm -runtime- hat PIN dann aber dann doch den korrekten Wert 54.

Das würde ich gerne verstehen.
Gast #5651101
Lesenswert?

static_assert funktioniert mit Konstanten und Makros:
1
static_assert(PIN >= COUNT, "PIN ist zu klein");
Bei der Gelegenheit kann man auch direkt die dumme Textersetzung via 
Makro durch richtige Konstanten ersetzen:
1
static constexpr uint8_t COUNT = 54;
2
static constexpr auto PIN =  A0;
Gast #5651124
Lesenswert?

makroOderMeinFehler schrieb:
> OK noch eine Frage zum verständnis: Was "sieht" der Parser, wenn er A0
> sieht?

Der Parser vom Präprozessor und der vom Compiler sehen beide ein 
Terminalsymbol "A0".

makroOderMeinFehler schrieb:
> PIN wird aber vom Parser bestückt, der den Wert A0 nicht erkennt

Der Parser liest nur Dinge ein. Der verarbeitet und ersetzt gar nichts. 
Makro-Textersetzung würde der Präprozessor nach dem Parsen machen, 
wenn A0 denn ein Makro wäre. Der Präprozessor - welcher das #if und 
#error auswertet - sieht nicht dass die beiden A0 zusammen hängen.

Der Compiler sieht erst eine Definition von A0 als Konstante. Bei der 
Nutzung von A0 sucht er die gleichnamige Konstante (gäbe es eine lokale 
Variable namens A0, würde diese stattdessen gefunden). Das Constant 
Folding im Optimizer wird den Wert 54 an die Stelle der Nutzung 
übertragen und da in die "ldi"-Instruktion einsetzen, die hier 
wahrscheinlich genutzt wird. Ein sehr dummer Compiler der keinerlei 
Optimierung vornimmt, könnte die Konstante stattdessen in den RAM legen 
(beim Start initialisiert) und dann bei der Nutzung erst aus dem RAM 
laden (z.B. per "lds") und dann an println übergeben.

at-user schrieb:
> Ja logisch, weil der Parser alles mit "PIN" durch "A0" ersetzt

Der Parser ersetzt nichts. Das macht der Präprozessor.
Gast #5651126
Lesenswert?

Der Präprozessor ersetzt Text. Wenn du schreibst:
1
#define PIN_A0   (54)
2
static const uint8_t A0 = PIN_A0;
3
#define PIN A0
4
Serial.println(PIN);

Wird daraus:
1
static const uint8_t A0 = (54);
2
Serial.println(A0);

Nach dieser Textersetzung wird dein Quelltext compiliert.

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