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
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...
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.
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...
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".
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");
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.
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.
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.