Die Antwort auf Ihre Frage ist spezifisch für die von Ihnen verwendete Architektur. Da Sie ARM erwähnt haben, werde ich Ihnen darauf basierend eine Antwort geben.
Der ARM Cortex ist ein registergestütztes Design, daher müssen grundsätzlich alle Operanden (const oder nicht) ihren Weg in eines der internen Register finden, bevor sie von Programmanweisungen verwendet werden können. Dies ist für die Beantwortung Ihrer Frage von zentraler Bedeutung, da die Architektur dies auf verschiedene Arten ermöglicht.
Bei kleinen Konstanten (normalerweise weniger als 8 oder 10 Bit) kann der Wert direkt in bestimmte Anweisungen codiert werden. Zum Beispiel gibt es einen ADD #imm-Befehl, der einem Register einen 12-Bit-Wert hinzufügt, der in das Befehlswort codiert ist. Dies kann verwendet werden, um direkt eine Konstante in Ihrem Programm anzugeben. Wenn Sie dieselbe Konstante an verschiedenen Stellen in Ihrem Code hinzufügen und der Wert 12 Bit oder weniger beträgt, verwendet der Compiler einfach überall dort, wo Ihre Konstante benötigt wird, einen ADD #imm-Befehl. Mit anderen Worten, die tatsächliche Konstante wird an mehreren Stellen im gesamten in FLASH gespeicherten Code repliziert.
Wenn die Konstante groß ist, funktioniert dies nicht. Daher muss der Wert an einem eigenen dedizierten FLASH-Speicherort gespeichert werden. Der Chip verfügt über einen weiteren Befehl namens LDR, mit dem ein Wert von einem Speicherort in die internen Register verschoben wird, in denen er verwendet werden kann. Dieser Anweisung ist es egal, ob der Wert physisch in FLASH oder RAM gespeichert ist, er zieht den Wert einfach von einer bestimmten Adresse im Speicher und legt ihn in einem Register ab. Beachten Sie, dass dies im Vergleich zur Situation mit kleinen Konstanten einen zusätzlichen Befehlszyklus erfordert. Wenn die Konstante jedoch wiederholt in einem Codeblock verwendet wird, speichert der Compiler sie zwischen, indem er sie in ein Ersatzregister legt, sofern eine verfügbar ist. P. >
Jetzt stoßen wir jedoch auf ein potenzielles Problem. Auf den meisten Cortex-Chips läuft der FLASH-Speicher mit der gleichen Geschwindigkeit oder langsamer als der CPU-Kern. Wenn wir versuchen, einen LDR-Befehl von einem FLASH-Ort aus auszuführen, muss diese Leseoperation des physischen Speichers mit dem Lesen des nächsten Befehls konkurrieren. Dies führt zu einem Engpass, der dazu führt, dass die CPU stehen bleibt, bis die Daten gelesen wurden. Schlimmer noch, bei vielen Implementierungen läuft der FLASH sehr langsam und ein Pipeline-Cache wird verwendet, um Anweisungen schneller an die CPU weiterzuleiten. Beim Lesen dieser Geräte kann beispielsweise eine Tabelle mit konstanten Werten den grundlegenden FLASH-Zugriffsengpass aufdecken, der zu schwerwiegenden Leistungseinbußen führt.
Aus diesem Grund versuchen viele Compiler, konstante Daten nach Möglichkeit in freie RAM-Speicherorte zu kopieren. Dies verhindert solche Probleme, und da der Zugriff auf RAM normalerweise schneller ist als auf FLASH, können viele Leistungsengpässe vermieden werden. Wenn Ihr Programm ohnehin nicht verwendeten RAM enthält, ist dies für den Compiler praktisch kein Aufwand.
Es gibt also definitiv eine Logik dafür, wie der Compiler dem physischen Speicher konstante Daten zuweist, aber zum Glück haben die Chip- und Compiler-Designer in den meisten Situationen all diese harte Arbeit für Sie geleistet, und Sie können einfach darauf vertrauen, dass er alles tut ist am besten für Ihren speziellen Code und Ihre Optimierungsstufe geeignet.