Arduino ist ein seltsamer Hybrid, bei dem einige C ++ - Funktionen in der eingebetteten Welt verwendet werden - traditionell eine C-Umgebung. Tatsächlich ist eine Menge Arduino-Code jedoch sehr C-artig.
C hat traditionell #define
s für Konstanten verwendet. Dafür gibt es eine Reihe von Gründen:
- Sie können mit keine Array-Größen einstellen
const int
. - Sie können keine
const int
case-Anweisungsbezeichnungen verwenden (obwohl dies in einigen Compilern funktioniert). - Sie können nicht
const
mit einem anderen initialisierenconst
.
Sie können diese Frage auf StackOverflow überprüfen, um weitere Überlegungen anzustellen.
Also, was sollen wir für Arduino verwenden? Ich tendiere dazu #define
, aber ich sehe, dass einige Code verwenden const
und andere eine Mischung.
programming
c++
coding-standards
Cybergibbons
quelle
quelle
#define
ist die naheliegende Wahl. Mein Beispiel ist die Benennung von analogen Pins - wie A5. Es gibt keinen geeigneten Typ dafür, der als verwendet werden könnte.const
Die einzige Möglichkeit besteht darin, a zu verwenden#define
und ihn vom Compiler als Texteingabe ersetzen zu lassen, bevor die Bedeutung interpretiert wird.Antworten:
Es ist wichtig zu beachten , dass
const int
sich nicht gleich in C verhalten und in C ++, so in der Tat einige der Einwände dagegen, die in der ursprünglichen Frage und in Peter Bloomfields umfangreiche Antwort erwähnt worden sind , sind nicht gültig:const int
Konstanten Werte für die Kompilierungszeit und können zum Festlegen von Array-Grenzen, als Fallbezeichnungen usw. verwendet werden.const int
Konstanten belegen nicht unbedingt Speicherplatz. Sofern Sie ihre Adresse nicht angeben oder extern deklarieren, haben sie in der Regel nur eine Kompilierzeit.Bei ganzzahligen Konstanten ist es jedoch häufig vorzuziehen, einen (benannten oder anonymen) Wert zu verwenden
enum
. Ich mag das oft, weil:const int
(genauso wie typsicher in C ++ 11).In einem idiomatischen C ++ - Programm gibt es also keinen Grund
#define
, eine Ganzzahlkonstante zu definieren. Auch wenn Sie C-kompatibel bleiben möchten (aufgrund technischer Anforderungen, weil Sie in die Jahre gekommen sind oder weil Leute, mit denen Sie zusammenarbeiten, dies vorziehen), könnenenum
und sollten Sie dies weiterhin tun, anstatt es zu verwenden#define
.quelle
const int
. Bei komplexeren Typen haben Sie Recht, dass Speicher zugewiesen wird, aber es ist unwahrscheinlich, dass Sie schlechter dran sind als bei einem#define
.BEARBEITEN: microtherion gibt eine hervorragende Antwort, die einige meiner Punkte hier korrigiert, insbesondere in Bezug auf die Speichernutzung.
Wie Sie festgestellt haben, gibt es bestimmte Situationen, in denen Sie zur Verwendung von a gezwungen sind
#define
, da der Compiler keineconst
Variablen zulässt . In einigen Situationen sind Sie gezwungen, Variablen zu verwenden, z. B. wenn Sie ein Array von Werten benötigen (dh Sie können kein Array von Werten haben#define
).Es gibt jedoch viele andere Situationen, in denen nicht unbedingt eine einzige „richtige“ Antwort vorliegt. Hier sind einige Richtlinien, denen ich folgen würde:
Typensicherheit Im
Hinblick auf die allgemeine Programmierung
const
sind Variablen in der Regel vorzuziehen (soweit möglich). Der Hauptgrund dafür ist die Typensicherheit.Ein
#define
(Präprozessor-Makro) kopiert den Literalwert direkt an jede Stelle im Code, wodurch jede Verwendung unabhängig wird. Dies kann hypothetisch zu Mehrdeutigkeiten führen, da der Typ je nach Verwendungszweck unterschiedlich aufgelöst werden kann.Eine
const
Variable ist immer nur ein Typ, der durch ihre Deklaration bestimmt und bei der Initialisierung aufgelöst wird. Es wird oft eine explizite Besetzung erfordern, bevor es sich anders verhält (obwohl es verschiedene Situationen gibt, in denen es sicher implizit vom Typ heraufgestuft werden kann). Zumindest kann der Compiler (bei korrekter Konfiguration) eine zuverlässigere Warnung ausgeben, wenn ein Typproblem auftritt.Eine mögliche Problemumgehung besteht darin, eine explizite Umwandlung oder ein Typ-Suffix in ein einzuschließen
#define
. Beispielsweise:Dieser Ansatz kann jedoch in einigen Fällen möglicherweise zu Syntaxproblemen führen, je nachdem, wie er verwendet wird.
Speichernutzung
Im Gegensatz zum Allzweck-Computing hat Speicher offensichtlich einen hohen Stellenwert im Umgang mit so etwas wie einem Arduino. Die Verwendung einer
const
Variablen im Vergleich zu einer#define
kann sich darauf auswirken, wo die Daten im Speicher gespeichert sind, wodurch Sie möglicherweise gezwungen werden, die eine oder andere zu verwenden.const
Variablen werden (normalerweise) zusammen mit allen anderen Variablen im SRAM gespeichert.#define
werden häufig im Programmbereich (Flash-Speicher) neben der Skizze selbst gespeichert.(Beachten Sie, dass es verschiedene Faktoren gibt, die genau beeinflussen können, wie und wo etwas gespeichert wird, z. B. die Compilerkonfiguration und -optimierung.)
SRAM und Flash haben unterschiedliche Einschränkungen (zB 2 KB bzw. 32 KB für das Uno). Für einige Anwendungen ist es recht einfach, kein SRAM mehr zu haben. Daher kann es hilfreich sein, einige Dinge in Flash zu verschieben. Das Gegenteil ist auch möglich, wenn auch wahrscheinlich weniger verbreitet.
PROGMEM
Es ist möglich, die Vorteile der Typensicherheit zu nutzen und gleichzeitig die Daten im Programmspeicher (Flash) zu speichern. Dies geschieht mit dem
PROGMEM
Schlüsselwort. Es funktioniert nicht für alle Typen, wird jedoch häufig für Arrays von ganzen Zahlen oder Zeichenfolgen verwendet.Die allgemeine Form in der Dokumentation ist wie folgt:
String-Tabellen sind etwas komplizierter, aber die Dokumentation enthält alle Details.
quelle
Für Variablen eines bestimmten Typs, die während der Ausführung nicht geändert werden, kann in der Regel eine von beiden verwendet werden.
Für in Variablen enthaltene digitale PIN-Nummern kann entweder Folgendes funktionieren:
Aber es gibt einen Umstand, den ich immer benutze
#define
Es sollen analoge Pin-Nummern definiert werden, da diese alphanumerisch sind.
Sicher, Sie können die PIN-Nummern im gesamten Programm wie folgt fest codieren
a2
,a3
und der Compiler weiß, wie er damit umgehen soll. Wenn Sie dann die Stifte wechseln, muss jede Verwendung geändert werden.Außerdem möchte ich meine PIN-Definitionen immer ganz oben an einer Stelle haben, damit die Frage auftaucht, welcher Typ
const
für eine als definierte PIN geeignet wäreA5
.In diesen Fällen benutze ich immer
#define
Spannungsteiler Beispiel:
Alle Setup-Variablen befinden sich ganz oben und es wird keine Änderung des Werts von
adcPin
außer zur Kompilierungszeit geben.Keine Sorge, welcher Typ
adcPin
ist. In der Binärdatei wird kein zusätzlicher RAM zum Speichern einer Konstanten verwendet.Der Compiler ersetzt einfach jede Instanz von
adcPin
durch den String,A5
bevor er kompiliert.Es gibt einen interessanten Arduino-Forum-Thread, in dem andere Entscheidungsmöglichkeiten diskutiert werden:
#define vs. const variable (Arduino-Forum)
Ausschnitte:
Code-Ersetzung:
Debugging-Code:
Definiert
true
undfalse
als Boolean, um RAM zu sparenVieles hängt von persönlichen Vorlieben ab, aber es ist klar, dass dies
#define
vielseitiger ist.quelle
const
nicht mehr RAM als a#define
. Und für die analogen Pins würde ich sie als definierenconst uint8_t
, obwohlconst int
das keinen Unterschied machen würde.const
nicht mehr RAM verwendet, [...] bis es tatsächlich verwendet wird ". Sie haben meinen Standpunkt verfehlt: a verwendet meistensconst
kein RAM, auch wenn es verwendet wird . Dann ist dies ein Multipass-Compiler . Am wichtigsten ist, dass es sich um einen optimierenden Compiler handelt. Wann immer möglich, werden Konstanten in unmittelbare Operanden optimiert .