Domanda

Recentemente ho lavorato su alcuni dispositivi embedded, dove abbiamo alcune strutture e i sindacati che hanno bisogno di essere inizializzato in fase di compilazione, in modo che possiamo tenere certe cose in flash o ROM che non hanno bisogno di essere modificato, e risparmiare un po 'di flash o SRAM a un po' di un costo di prestazioni.Attualmente il codice viene compilato come valido C99, ma senza questa regolazione è utilizzato per la compilazione come codice C++ così, e sarebbe grande per il supporto di cose essere compilato così.Una delle cose principali che impedisce di questo è che stiamo usando C99 area di inizializzatori che non funzionano all'interno del C sottoinsieme del C++.Io non sono molto di un C++ buff, quindi mi chiedo che cosa i modi più semplici, ci potrebbe essere per fare questo accadere in C++ compatibile C o in C++ che ancora permettono di inizializzazione in fase di compilazione, in modo che le strutture e i sindacati non hanno bisogno di essere inizializzato dopo l'avvio del programma in ram.

Un ulteriore punto di nota:una delle ragioni fondamentali per inizializzatore designato utilizzo è initalizing come NON è stato il primo membro di un sindacato.Inoltre, attaccare con standard di C++ e / o ANSI C è un plus per mantenere la compatibilità con altri compilatori (so che su GNU estensioni che forniscono qualcosa come area di inizializzatori senza C99).

È stato utile?

Soluzione

Non sono sicuro che si può fare in C ++. Per le cose che è necessario inizializzare utilizzando inizializzatori designati, si può mettere quelli separatamente in un file .c compilato come C99, per esempio:.

// 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

Altri suggerimenti

Sulla risposta di Shing Yip, e con il vantaggio di tempo tre anni di, C ++ 11 ora in grado di garantire la compilazione di inizializzazione tempo:

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

Assembly:

    .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 ++ unione può avere costruttori troppo. Può essere questo è quello che volevi?

Questa è una sorta di sia una risposta e una domanda. Mi rendo conto che questa discussione è morto, ma è esattamente quello che cercavo in questa notte.

Ho fatto qualche rovistando e la cosa più vicina che posso arrivare a ciò che voglio (che è simile a quello che si vuole ... Ho lavorato con le foto e non hanno necessità di utilizzare C ++, ma io sono curioso come potrebbe essere fatto) è il primo esempio di codice:

#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;
}

Questo ha un aspetto molto simile ai inizializzatori stile C99 designati con un avvertimento citerò più tardi. (. E 'probabile che questo avvolgere in #ifdef __cplusplus se si voleva la struttura per essere compilato da entrambi) La seconda versione del codice che ho guardato è questo:

#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;
}

Fondamentalmente, guardando il disassemblaggio, sembra che il primo esempio è in realtà più lento. Ho guardato l'uscita di montaggio e, beh, devo essere un po 'arrugginito. Forse qualcuno potrebbe darmi qualche informazione. L'uscita di assemblaggio del primo cpp compilato e sembrava che:

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

Il secondo esempio sembrava:

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

Entrambi questi sono stati generati con un comando g++ -O0 -S main.cpp. Chiaramente, l'esempio intuitivamente meno efficiente generato opcode più efficiente in termini di numero di istruzioni. D'altra parte, ci sono alcuni casi in cui ho potuto immaginare le poche istruzioni essere critici. (D'altra parte, ho davvero difficoltà a capire il montaggio non scritto da esseri umani, così forse mi manca qualcosa ...) Credo che questo fornisce una soluzione, sia pure in ritardo, alla domanda posta James. La prossima cosa che dovrei verificare è se la stessa di inizializzazione è consentito in C99; se funziona, penso che affronta pienamente il problema di James.

. Disclaimer: Non ho idea se questo funziona o si comporta in modo simile per altri compilatori diversi da g ++

Lavaggio del foro di report:

Dato

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

Ho provato derivanti S1 S, dove S1 inline costruttore predefinito invoca S(int) e passa un valore hardcoded ...

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

...e poi compilato con gcc 4.0.1 -O2 -S.La speranza era che l'ottimizzatore vedrebbe che s1.mB dovrebbe essere necessariamente 22 e assegnare il valore in fase di compilazione, ma dall'assembler ...

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

...sembra che il codice generato l'inizializzazione in fase di runtime prima principale.Anche se avesse funzionato, sarebbe difficilmente essere compilato come C99 e kludge di derivazione di una classe per ogni oggetto che si voleva inizializzare;quindi, non preoccupatevi.

Il seguente codice viene compilato senza problemi con 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;
}

Ecco il risultato:

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

L'unica cosa con gli inizializzatori C ++ è che è necessario inizializzare tutti gli elementi della struttura o il resto verrà inizializzato con gli zeri. Non si può scegliere. Ma questo dovrebbe essere ancora OK per il vostro caso d'uso.

  

Un ulteriore punto di nota:. Una delle ragioni principali per l'utilizzo inizializzatore designato è Inizializzare come NOT il primo membro di un sindacato

Per questo è necessario utilizzare la "soluzione" mostrato nell'esempio in cui ho impostato il membro "galleggiare", fornendo il valore int equivalente. E 'un po' di un hack, ma se si risolve il problema.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top