Ich schreibe in der Arduino IDE ein Programm für den Arduino Nano.
Eventuell soll später nochmal der Pin, an dem Peripherie hängt geändert
werden können, indem der Sketch geändert wird. Aber : der neue Pin muss
wie der jetzige Interrupt on Change unterstützen. Das wollte ich
absichern.
Hier mein zusammengekürzter Sketch :
1
#if 0 // folgende Zeilen sind in Dateien, die automatisch eingebunden werden, ich habe sie hier nur mal zusammen gesucht
2
3
// stdint.h
4
typedef unsigned int uint8_t __attribute__((__mode__(__QI__)));
*:\*\problem\problem.ino:25:1: error: non-constant condition for static assertion
13
static_assert((uint8_t*)0 != digitalPinToPCICR(HALL_SPEED_PIN), "HALL_SPEED_PIN auf Pin legen, der Interrupt on Change unterstützt");
14
^~~~~~~~~~~~~
15
In file included from *:\Users\*\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6\variants\eightanaloginputs/pins_arduino.h:23:0,
16
from *:\Users\*\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6\cores\arduino/Arduino.h:258,
17
from *:\Users\*\AppData\Local\arduino\sketches\*\sketch\problem.ino.cpp:1:
18
*:\Users\*\appdata\local\arduino15\packages\arduino\hardware\avr\1.8.6\variants\standard\pins_arduino.h:74:61: error: reinterpret_cast from integer to pointer
Da bin ich ja mal gespannt.
Normale Leute hätten einfach ein define für die Pinnummer genommen und
einen Kommentar drangeschrieben wg. des PCI.
Ist ja schließlich Arduino, nicht Automotive...
Jens M. schrieb:> Da bin ich ja mal gespannt.>> Normale Leute hätten einfach ein define für die Pinnummer genommen und> einen Kommentar drangeschrieben wg. des PCI.> Ist ja schließlich Arduino, nicht Automotive...
Mist, erwischt ! Sonst muss ich mich beim Programmieren an MISRA halten.
Der Mensch gewöhnt sich doch irgendwie an alles.
Flunder schrieb:> Was ist reinterpret_cast ?
Ein cast zwischen nicht kompatiblen Typen.
> Wieso ist danach eine Konstante nicht mehr konstant ?
Weil sie es vorher auch nicht war.
> Wie kann ich das umgehen ?Jens M. schrieb:> Normale Leute hätten einfach ein define für die Pinnummer genommen und> einen Kommentar drangeschrieben wg. des PCI.> Ist ja schließlich Arduino, nicht Automotive...
Oder einfach: Versuch erst gar nicht, dich absichtlich von hinten durch
die Brust ins Auge zu schiessen. Keep it simple and stupid...
Oliver
Oliver S. schrieb:> Keep it simple and stupid
Ich kenn's eigentlich als "Keep it simple, stupid", wobei hier "stupid"
als Anrede gemeint ist, nach dem Motto "Mach dir das Leben nicht so
schwer, du Depp".
Oliver S. schrieb:>> Wieso ist danach eine Konstante nicht mehr konstant ?> Weil sie es vorher auch nicht war.
Äh, wenn die Zahl 104, die da irgendwo als Literal steht nicht konstant
ist, dann habe ich jetzt echt ein Verständnisproblem.
Oder ist das ein Witz wie
https://www.gutefrage.net/frage/225-fuer-extrem-grosse-werte-von-2
Ein Zeiger, der immer auf Adresse 104 zeigt, sollte doch auch konstant
sein. Ob das, wohin er zeigt konstant ist, ist ja schließlich eine
andere Frage.
Es sieht doch so aus, als ob durch den reinterpret_cast die Eigenschaft
konstant verloren geht. Wie kann man die erhalten ?
Ok, in der Tat schwierig, da ich mittlerweile im Web was gefunden habe,
dass der gcc das lange entgegen dem Standard umgesetzt hat, dass aber
dieses Verhalten, dass der jetzt von Arduino genutzte Compiler an den
Tag legt, das richtige ist - wenn auch nicht das von mir gewünschte.
Warum fordert der C++ Standard also dieses Verhalten und wie teile ich
einem C++ Compiler mit, dass ich es anders brauche ?
Glaub mir, es liegt nicht am Compiler oder am Standard. Schau Dein Makro
an.
Du lieferst in digitalPinToPCICR den Wert (&PCICR) zurück.
Das Makro PCICR nutzt intern (*(volatile uint8_t *)(mem_addr)).
Damit ist die Rückgabe natürlich nicht mehr konstant.
Ein cast hilft da nicht, dann wird der Compiler trotzdem ein
„non-constant condition for static assertion“ melden.
Dummerweise ist das nicht mein Makro, sondern eins, dass von Arduino
mitgeliefert wurde. Also eventuell von jemandem stammt, der mittlerweile
Microchip auf der Visitenkarte stehen hat.
Bei Stack Overflow habe ich mittlerweile die noch verwirrendere Lösung
für das verwirrende Problem gefunden.
1
uint8_teda;
2
#pragma push_macro("PCICR")
3
#undef PCICR
4
#define PCICR eda
5
static_assert((uint8_t*)0!=digitalPinToPCICR(HALL_SPEED_PIN),"HALL_SPEED_PIN auf Pin legen, der Interrupt on Change unterstützt");
Flunder schrieb:> Es sieht doch so aus, als ob durch den reinterpret_cast die Eigenschaft> konstant verloren geht.
So ist es:
> § 5.19/2 Constant Expressions [expr.const] the result of a> reinterpret_cast can't be a constant expression
Flunder schrieb:> Bei Stack Overflow habe ich mittlerweile die noch verwirrendere Lösung> für das verwirrende Problem gefunden.
Ach du Scheiße, das verwirrt den Verwirrten noch mehr….
Dann würde ich eher auf static_assert verzichten und es zur Laufzeit
beim Start-Up überprüfen, z.B. per assert().
Johann L. schrieb:> So ist es:> § 5.19/2 Constant Expressions [expr.const] the result of a> reinterpret_cast can't be a constant expression
Das ist aber nicht das eigentliche Problem.
Das eigentliche Problem ist, dass die Makros den Inhaltsoperator *
nutzen und der Compiler natürlich nicht den Inhalt des Registers kennt.
Daher funktioniert static_assert nicht. Da hilft kein cast.
Nachtrag:
>Dann würde ich eher auf static_assert verzichten und es zur Laufzeit>beim Start-Up überprüfen, z.B. per assert().
Falsch gedacht, das funktioniert IMHO nicht, da der Inhaltsoperator
natürlich auch auf der Adresse 0 zurück liefern kann.
Klaus H. schrieb:> Falsch gedacht, das funktioniert IMHO nicht, da der Inhaltsoperator> natürlich auch auf der Adresse 0 zurück liefern kann.
Ne, nach dem * kommt doch auch wieder ein &. Das kommt vermutlich daher,
weil hier mindestens 3 Programmierer am Werk waren und einer die Makros
des anderen nutzt. Und das frei nach dem Motto : was nicht passt, wird
passend gemacht.
gibt Mecker, weil eine Zahl nicht so einfach in einen Zeiger gewandelt
werden kann.
Das sieht der Compiler als "Ein cast zwischen nicht kompatiblen Typen"
an, und streicht dem Pointer auf die feste Adresse 42 gemäß "§ 5.19/2"
die Eigenschaft konstant.
Gut, im Buch kommt ja auch irgendwann raus, dass es 56 statt 42 hätte
heißen müssen. So etwas kann aber doch nicht der Grund für die
Einschränkung beim Typecast sein.
Flunder schrieb:> Ne, nach dem * kommt doch auch wieder ein &.
Aber das ist das Problem.
In deinem Beispiel würde folgendes ausgeführt:
1
&(*(volatileuint8_t*)(hurz))
Er holt den Inhalt und macht aus dem Inhalt einen Zeiger.
Damit ist das Ganze abhängig vom Inhalt des Registers PCICR:
(&(*(volatile uint8_t *)(0x68))
&(*(&(*(&x))) ist nicht die Adresse von x....
Flunder schrieb:> So etwas kann aber doch nicht der Grund für die> Einschränkung beim Typecast sein.
Doch. Constexpr verlangt dass der L - Wert auch zur Kompilierzeit
auswertbar ist. Der Compiler weiß aber nicht was an Addresse 42 ist.
Ungekehrt ist
const uint8_t* hurz = (uint8_t*)42;
erlaubt, denn hurz wird hier zur Laufzeit initialisiert.
Harald schrieb:> Der Compiler weiß aber nicht was an Addresse 42 ist.
Muss er doch auch nicht. Was er mit der Adresse anfangen soll, sagt ihm
ja das Programm. Im Fall von constexpr soll er mir ja nur einen anderen
Namen für "Zeiger auf Adresse 42" anlegen, damit ich nicht bei jedem
Zugriff auf Adresse 42 einen Kommentar dazu schreiben muss, worauf ich
da eigentlich zugreife.
Die Frage wieso müsste ich vermutlich Bjarne Stroustrup stellen. Er wird
sich bestimmt etwas dabei gedacht haben. Vielleicht hat er es sogar
schon irgendwo aufgeschrieben.