Hallo zusammen,
ich bin vor ein paar Tagen über einen "witzigen" Effekt gestolpert.
Irrigerweise hatte sich bei mir die Vorstellung festgesetzt, dass der
Compiler immer(!) constexpr-Ausdrücke in den generierten Code übernimmt
und deswegen für z.B. constexpr Objekte kein RAM benötigt. Schließlich
kann ich ja zur Compile-Zeit mit Hilfe von constexpr-Funktionen ganze
Container sortieren, ohne ein einziges Byte zu belegen, etc.
Im folgenden Beispiel ist das auch so: das Data-Segment ist 0-Bytes
lang.
1 | #include <stdint.h>
|
2 |
|
3 | volatile uint8_t x = 0;
|
4 | volatile uint8_t y = 0;
|
5 |
|
6 | constexpr uint16_t size = 4;
|
7 | constexpr uint16_t offset = 1;
|
8 |
|
9 | int main() {
|
10 | constexpr const uint8_t array[size + offset] = {1, 2, 3, 4};
|
11 |
|
12 | y = array[x];
|
13 |
|
14 | while(true) {}
|
15 | }
|
Der Compiler erzeugt ein "assembler-switch-case".
Macht man allerdings
1 | constexpr uint16_t offset = 1;
|
so erhält man ein Data-Segment von 4 Bytes.
Diesen Effekt kann man generell beobachten: das Array muss immer um
mindestens 1 länger sein als die Anzahl der Initializer. Auch ein einem
std::array<>:
1 | #include <stdint.h>
|
2 | #include "std/array.h"
|
3 |
|
4 | volatile uint8_t x = 0;
|
5 | volatile uint8_t y = 0;
|
6 |
|
7 | constexpr uint16_t size = 250;
|
8 | constexpr uint16_t offset = 1;
|
9 |
|
10 | int main() {
|
11 | constexpr const auto array = [](){
|
12 | std::array<uint8_t, size + offset> a;
|
13 | for(std::remove_cv_t<decltype(size)> i = 0; i < size; ++i) {
|
14 | a[i] = i + 1;
|
15 | }
|
16 | return a;
|
17 | }();
|
18 |
|
19 | y = array[x];
|
20 |
|
21 | while(true) {}
|
22 | }
|
Ist hier offset >= 1, bekommen wir wieder 0 Bytes im Data-Segment, aber
2456 Bytes(!) Code (atmega328). Bei offset == 0 sind es eben 250 Bytes
Data-Segment.
(Die Initialisierung per IIFE ist nur deswegen im o.g. Beispiel da,
damit der Compiler auch eine lange Sprungtabelle generieren muss.)
Selbstverständlich ist das alles konform, doch hatte ich damit, nämlich
Platz im Data-Segment, nicht gerechnet, sondern mit einer Abwicklung im
Code...