Question

Récemment, je travaille sur certains appareils embarqués, où nous avons des syndicats qui et struct doivent être initialisées au moment de la compilation afin que nous puissions garder certaines choses en flash ou ROM qui ne ont pas besoin d'être modifiés, et enregistrer un petit flash ou SRAM à un peu d'un coût de performance. Actuellement, le code est compilé comme valide C99, mais sans cet ajustement, il permet de compiler en code C ++ ainsi, et ce serait formidable pour soutenir les choses en cours de compilation de cette façon aussi. L'une des principales choses qui empêchent cela est que nous utilisons initialiseurs désignés C99 qui ne travaillent pas dans le sous-ensemble C de C ++. Je ne suis pas beaucoup plus d'un colin C de, donc je me demande quelles façons simples il pourrait y avoir pour que cela se soit dans C ++ compatible C ou en C ++ qui permettent encore l'initialisation au moment de la compilation afin que les structs et les syndicats ne doivent pas être initialisé après le démarrage du programme dans la SRAM.

Un point de la note complémentaire: une des principales raisons pour l'utilisation du initialiseur désigné est initalizing comme pas le premier membre d'un syndicat. En outre, coller à la norme C ++ ou C ANSI est un plus afin de maintenir la compatibilité avec d'autres compilateurs (je sais au sujet des extensions GNU qui offrent quelque chose comme initialiseurs désignés sans C99).

Était-ce utile?

La solution

Je ne suis pas sûr que vous pouvez le faire en C ++. Pour les choses que vous devez initialiser en utilisant initialiseurs désignés, vous pouvez mettre les séparément dans un fichier compilé comme C99 .c, par exemple:.

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

Autres conseils

Miser sur la réponse de Shing Yip, et bénéficier du temps de 3 ans 11 C ++ peut désormais garantir la compilation initialisation du temps:

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

Assemblée:

    .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

Dans le syndicat C peut avoir des constructeurs aussi. Peut être est-ce ce que vous vouliez?

C'est un peu à la fois une réponse et une question. Je sais que ce fil est mort, mais exactement ce que je recherchais en ce soir.

Je l'ai fait un peu farfouillé et le plus proche chose que je peux obtenir ce que je veux (ce qui est similaire à ce que vous voulez ... Je travaille avec des photos et ne pas avoir besoin d'utiliser c ++, mais je suis curieux de voir comment il pourrait être fait) est le premier exemple de code:

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

a une apparence très similaire aux initialiseurs désignés de style C99 avec une mise en garde, je vais parler plus tard. (. Vous auriez probablement envelopper cette #ifdef __cplusplus si vous voulez que le struct à compiler soit) La deuxième version du code que je regardais est la suivante:

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

En fait, de regarder le démontage, il semble que le premier exemple est en fait plus lent. Je l'ai regardé à la sortie de montage et, bien, je dois être un peu rouillé. Peut-être que quelqu'un pourrait me donner un aperçu. La sortie de l'assemblage du premier cpp compilé et ressemblait à:

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

Le deuxième exemple ressemblait à:

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

Ces deux ont été générés avec une commande g++ -O0 -S main.cpp. De toute évidence, l'exemple intuitivement moins efficace généré opcode plus efficace en termes de nombre d'instructions. D'autre part, il y a peu de cas où je pourrais imaginer les quelques instructions étant critique. (D'autre part, j'ai vraiment du mal à comprendre l'ensemble n'a pas été écrit par les humains, donc je suis peut-être raté quelque chose ...) Je pense que cela fournit une solution, quoique tardive, à la question James a demandé. La prochaine chose que je dois tester est la même si l'initialisation est autorisée dans C99; si cela fonctionne, je pense qu'il répond pleinement le problème de James.

Disclaimer:. Je ne sais pas si cela fonctionne ou se comporte de même pour tout autre compilateurs autres que g ++

Rapport de trou sec:

Étant donné

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

I essayé dérivant S1 de S, où le constructeur par défaut en ligne de S1 appelle S (int) et transmet une valeur codée en dur ...

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

... puis compilé avec gcc 4.0.1 -O2 -S. L'espoir était que l'optimiseur verrait que s1.mB serait nécessairement 22 et affecter la valeur lors de la compilation, mais de l'assembleur ...

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

... il semble que le code généré ne l'initialisation lors de l'exécution avant principale. Même si elle avait travaillé, il ne serait guère compilable que C99 et aurait la bidouille de dériver une classe pour chaque objet que vous vouliez initialiser; donc, ne vous embêtez pas.

Le code suivant compile sans problème avec 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;
}

Voici le résultat:

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

La seule chose avec les C ++ initializers est que vous devez initialiser tous les éléments de la structure ou le reste sera initialisé avec des zéros. Vous ne pouvez pas choisir. Mais cela ne devrait toujours être OK pour votre cas d'utilisation.

  

Un point de la note complémentaire:. Une des principales raisons pour l'utilisation du initialiseur désigné est initalizing comme pas le premier membre d'un syndicat

Pour que vous devez utiliser la « solution » dans l'exemple où je le paramétre « float » en fournissant l'équivalent valeur int. Il est un peu un hack, mais si cela résout votre problème.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top