Frage

Vor kurzem habe ich an einigen Embedded-Geräten arbeiten, wo wir einige Strukturen und Gewerkschaften haben, die bei der Kompilierung initialisiert werden müssen, so dass wir bestimmte Dinge in Flash oder ROM halten können, die geändert nicht brauchen werden, und sparen ein wenig Flash-Speicher oder SRAM in einem Bit einer Leistungskosten. Derzeit stellt der Code als gültig C99, aber ohne diese Einstellung verwendete es als C ++ Code zu kompilieren als auch, und es wäre toll, Dinge zu unterstützen, auch auf diese Weise zusammengestellt werden. Eines der wichtigsten Dinge, die dies verhindert ist, dass wir C99 bezeichnet initializers verwenden, die in der C-Teilmenge von C ++ nicht funktionieren. Ich bin nicht viel von einem C ++ Buff, so frage ich mich, was einfache Möglichkeiten, es könnte sein, diese entweder in C ++ kompatibel C geschehen, oder in C ++, die noch Initialisierung bei der Kompilierung erlauben, so dass die Strukturen und Gewerkschaften nicht sein müssen nach Programmstart im SRAM initialisiert.

Ein weiterer Punkt beachten: ein wesentlicher Grund für die benannten Initialisierer Nutzung ist Initalizing als nicht das erste Mitglied einer Gewerkschaft. Auch mit Standard-C ++ oder ANSI C Kleben ist ein Plus, um die Kompatibilität mit anderen Compilern zu halten (ich weiß über die GNU-Erweiterungen, die so etwas wie bezeichnet initializers ohne C99 zur Verfügung stellen).

War es hilfreich?

Lösung

Ich bin mir nicht sicher, dass Sie es in C ++ tun können. Für die Dinge, die Sie benannten Initialisierungen mit initialisieren müssen, können Sie diese separat in einer .c Datei setzen, wie C99 zusammengestellt, z.

// In common header file
typedef union my_union
{
    int i;
    float f;
} my_union;

extern const my_union g_var;

// In file compiled as C99
const my_union g_var = { .f = 3.14159f };

// Now any file that #include's the header can access g_var, and it will be
// properly initialized at load time

Andere Tipps

Aufbauend auf Shing Yip Antwort, und mit Nutzen von 3 Jahr Zeit, C ++ 11 jetzt kann garantieren Zeit Initialisierung kompilieren:

union Bar
{
    constexpr Bar(int a) : a_(a) {}
    constexpr Bar(float b) : b_(b) {}
    int a_;
    float b_;
};

extern constexpr Bar bar1(1);
extern constexpr Bar bar2(1.234f);

Montage:

    .globl  _bar1                   ## @bar1
    .p2align    2
_bar1:
    .long   1                       ## 0x1

    .globl  _bar2                   ## @bar2
    .p2align    2
_bar2:
    .long   1067316150              ## float 1.23399997
#ifdef __cplusplus
struct Foo
{
    Foo(int a, int b) : a(a), b(b) {}
    int a;
    int b;
};

union Bar
{
    Bar(int a) : a(a) {}
    Bar(float b) : b(b) {}
    int a;
    float b;
};

static Foo foo(1,2);
static Bar bar1(1);
static Bar bar2(1.234f);
#else 
 /* C99 stuff */
#endif // __cplusplus

In C ++ Union können Konstrukteure haben. sein kann, das ist, was Sie wollen?

Dies ist eine Art sowohl eine Antwort und eine Frage. Ich weiß, das Gewinde ist tot, aber es genau das, was ich suchte in heute Abend.

Ich habe einige stochern und das nächste, was ich bekommen kann, was ich will (was ähnlich ist, was Sie wollen ... Ich habe mit Bildern und haben keine Notwendigkeit, Arbeits c ++ zu verwenden, aber ich bin neugierig, wie es getan werden könnte) ist das erste Codebeispiel:

#include <iostream>

using namespace std;

extern "C" 
{
    typedef struct stuff
    {
        int x;
        double y;
    } things;
}

int main()
{
    things jmcd = { jmcd.x = 12, jmcd.y = 10.1234 };
    cout << jmcd.x << " " << jmcd.y << endl;
    return 0;
}

Dies hat ein sehr ähnliches Aussehen wie den C99-Stil bezeichnet initializers mit einem Vorbehalt ich später erwähnen werden. (. Sie würden wahrscheinlich diese wickeln in #ifdef __cplusplus, wenn Sie die Struktur kompiliert werden, indem entweder wollte) Die zweite Version des Codes ich sah, ist dies:

#include <iostream>

using namespace std;

extern "C" 
{
    typedef struct stuff
    {
        int x;
        double y;
    } things;
}


int main()
{
    things jmcd;
    jmcd.x = 12;
    jmcd.y = 10.1234;
    cout << jmcd.x << " " << jmcd.y << endl;
    return 0;
}

Im Grunde genommen aus an der Demontage sucht, scheint es das erste Beispiel ist tatsächlich langsamer. Ich habe an dem Montag Ausgang sah und, na ja, ich muß ein wenig rostig sein. Vielleicht könnte jemand mir einen kleinen Einblick geben. Der Montag Ausgang des ersten CPP zusammengestellt und sah aus wie:

main:
.LFB957:
    .cfi_startproc
    .cfi_personality 0x0,__gxx_personality_v0
    pushl   %ebp
    .cfi_def_cfa_offset 8
    movl    %esp, %ebp
    .cfi_offset 5, -8
    .cfi_def_cfa_register 5
    subl    $24, %esp
    movl    $0, 12(%esp)
    movl    $0, 16(%esp)
    movl    $0, 20(%esp)
    movl    $12, 12(%esp)
    movl    12(%esp), %eax
    movl    %eax, 12(%esp)
    fldl    .LC0
    fstpl   16(%esp)
    fldl    16(%esp)
    fstpl   16(%esp)
    movl    12(%esp), %eax
    movl    %eax, 4(%esp)
    fildl   4(%esp)
    fldl    16(%esp)
    faddp   %st, %st(1)
    fnstcw  2(%esp)
    movzwl  2(%esp), %eax
    movb    $12, %ah
    movw    %ax, (%esp)
    fldcw   (%esp)
    fistpl  4(%esp)
    fldcw   2(%esp)
    movl    4(%esp), %eax
    leave
    ret
    .cfi_endproc

Das zweite Beispiel sah aus wie:

main:
.LFB957:
    .cfi_startproc
    .cfi_personality 0x0,__gxx_personality_v0
    pushl   %ebp
    .cfi_def_cfa_offset 8
    movl    %esp, %ebp
    .cfi_offset 5, -8
    .cfi_def_cfa_register 5
    subl    $24, %esp
    movl    $12, 12(%esp)
    fldl    .LC0
    fstpl   16(%esp)
    movl    12(%esp), %eax
    movl    %eax, 4(%esp)
    fildl   4(%esp)
    fldl    16(%esp)
    faddp   %st, %st(1)
    fnstcw  2(%esp)
    movzwl  2(%esp), %eax
    movb    $12, %ah
    movw    %ax, (%esp)
    fldcw   (%esp)
    fistpl  4(%esp)
    fldcw   2(%esp)
    movl    4(%esp), %eax
    leave
    ret
    .cfi_endproc
Beide

wurden mit einem g++ -O0 -S main.cpp Befehl erzeugt. Offensichtlich erzeugt die intuitiv weniger effizient Beispiel effizienter Opcode in Bezug auf die Anzahl von Anweisungen. Auf der anderen Seite gibt es nur wenige Fälle, in denen ich die wenigen Befehle kritisch zu sein vorstellen konnte. (Auf der anderen Seite, ich habe wirklich Schwierigkeiten zu verstehen, Montage nicht von Menschen geschrieben, vielleicht ich bin etwas fehlt ...) Ich denke, das ist eine Lösung bietet, wenn auch spät, auf die Frage, fragte James. Das nächste, was ich testen soll, ist, wenn die gleiche Initialisierung in C99 erlaubt ist; Wenn das funktioniert, ich denke, es James Problem vollständig adressiert.

Disclaimer:. Ich habe keine Ahnung, ob das funktioniert oder verhält sich ähnlich für andere Compiler außer g ++

Trockenloch Bericht:

Da

struct S {
  int mA;
  int mB;
  S() {}
  S(int b} : mB(b) {} // a ctor that does partial initialization
};

versuchte I S1 aus S Ableiten, wobei S1 die inline Standardkonstruktors ruft S (int) und übergibt einen hartcodierte Wert ...

struct S1 {
  S1() : S(22) {}
} s1;

... und dann mit gcc 4.0.1 -O2 -S zusammengestellt. Die Hoffnung war, dass der Optimierer würde sehen, dass s1.mB notwendigerweise 22 wäre und den Wert, den es zum Zeitpunkt der Kompilierung zuweisen, aber vom Assembler ...

    movl    $22, 4+_s1-"L00000000002$pb"(%ebx)

... es sieht aus wie der generierte Code die Initialisierung zur Laufzeit macht vor dem Haupt. Auch wenn es gearbeitet hatte, wäre es kaum übersetzbar als C99 und würde für jedes Objekt die Flickschusterei der Ableitung einer Klasse haben Sie initialisieren wollte; so, nicht stören.

Der folgende Code kompiliert ohne Probleme mit g ++:

#include <iostream>

struct foo
{
  int a;
  int b;
  int c;
};

union bar
{
  int a;
  float b;
  long c;
};

static foo s_foo1 = {1,2,3};
static foo s_foo2 = {1,2};
static bar s_bar1 = {42L};
static bar s_bar2 = {1078523331}; // 3.14 in float


int main(int, char**)
{
  std::cout << s_foo1.a << ", " <<
               s_foo1.b << ", " <<
               s_foo1.c << std::endl;

  std::cout << s_foo2.a << ", " <<
               s_foo2.b << ", " <<
               s_foo2.c << std::endl;

  std::cout << s_bar1.a << ", " <<
               s_bar1.b << ", " <<
               s_bar1.c << std::endl;

  std::cout << s_bar2.a << ", " <<
               s_bar2.b << ", " <<
               s_bar2.c << std::endl;

  return 0;
}

Hier ist das Ergebnis:

$ g++ -o ./test ./test.cpp
$ ./test
1, 2, 3
1, 2, 0
42, 5.88545e-44, 42
1078523331, 3.14, 1078523331

Das einzige, was mit dem C ++ initializers ist, dass Sie alle Elemente der Struktur initialisieren müssen oder der Rest wird mit Nullen initialisiert werden. Sie können nicht wählen, und wählen. Aber das sollte noch für Ihren Anwendungsfall in Ordnung sein.

  

Ein weiterer Punkt beachten: a. Hauptgrund für bestimmte initializer Nutzung ist Initalizing als nicht das erste Mitglied einer Gewerkschaft

Für das müssen Sie die „Abhilfe“ in dem gezeigten Beispiel verwenden, wo ich die „float“ member gesetzt durch das Äquivalent int-Wert bereitstellt. Es ist ein bisschen wie ein Hack, aber wenn es Ihr Problem löst.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top