質問
最近、私は、我々は変更する必要はありませんフラッシュまたはROMで特定の物事を保つことができるように、コンパイル時に初期化する必要があるいくつかの構造体と共用体を持っているいくつかの組み込みデバイス、に取り組んできた、とパフォーマンスコストのビットで、ほとんどのフラッシュやSRAMを保存します。現在のコードは、有効なC99としてコンパイルしますが、この調整なしそれは同様にC ++コードとしてコンパイルするのに使用され、同様にそのようにコンパイルされているものをサポートするために素晴らしいことです。これを防ぐ重要なことの一つは、我々はC ++のCサブセット内で動作していないC99指定の初期化子を使用していることです。私はC ++バフのあまりないので、私は簡単な方法は、これはどちらかのC ++互換Cで起こる、または構造体と共用体は、である必要はないように、C ++のそれはまだコンパイル時に初期化できるようにするためにあるかもしれない何を思ったんだけどSRAM内のプログラムの起動後に初期化されます。
ノートの1つの追加のポイント:指定イニシャライザの使用のための重要な理由は、労働組合の最初のメンバーとして、NOT initalizingされます。また、標準のC ++またはANSI Cに固執することは、他のコンパイラとの互換性を維持するためにプラスである(私はC99のない指定された初期化子のようなものを提供GNU拡張について知っている)。
解決
私はあなたがC ++でそれを行うことができますかわかりません。あなたが指定された初期化子を使用して初期化する必要があるものについて、あなたは例えばC99、としてコンパイル.c
ファイルで個別にそれらを置くことができます。
// 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
他のヒント
シン・イップの答えに、そして3年の期限の利益の構築、C ++ 11は、現在の時間の初期化をコンパイル保証することができます:
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);
アセンブリます:
.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
C ++組合では、あまりにもコンストラクタを持つことができます。これはあなたが望んでいることができますか?
この答えと質問の両方の一種です。私は、このスレッドが死んで実現するが、それは私が今夜に探していたまさにます。
私がやったいくつかのチャンスをうかがって、私は私はあなたが望むものに似ている(欲しいものを得ることができる最も近いものは...私は写真での作業やC ++を使用する必要がありませんが、私は好奇心てきたどのようにそれを)で行われるかもしれない最初のコード例である:
#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;
}
これは私が後で言及します注意点がC99のスタイル指定された初期化子と非常によく似た外観を有します。 (あなたがいずれかの方法でコンパイルする構造体を望んでいた場合は、おそらくの#ifdef __cplusplusでこれをラップします。)私は見てコードの2番目のバージョンを、この次のとおりです。
#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;
}
基本的には、解体を見てから、最初の例は、実際に遅い表示されます。私はよく、私は少し錆びている必要があり、アセンブリ出力を見てきました。たぶん誰かが私にいくつかの洞察力を与えることができます。最初のCPPのアセンブリ出力をコンパイルしように見えた:
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
第二の例は、のように見えました
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
これらの両方がg++ -O0 -S main.cpp
コマンドを使用して生成されました。明らかに、直感的にあまり効率的例は、命令の数の点でより効率的なオペコードを生成しました。一方、私はいくつかの命令が重要であることを想像することができ、いくつかの例があります。 (一方で、私は本当にので、多分、私は何かが欠けています、トラブル理解する人間によって書かれていないアセンブリを持っている...)私はジェームズが尋ねた質問には、後半にもかかわらず、これは解決策を提供していと思います。同じ初期化がC99で許可されている場合、私はテストする必要があります次のことはあります。それが動作するかどうか、私はそれが完全にジェームズの問題に対処すると思います。
免責事項:この作品またはg ++以外の任意の他のコンパイラについても同様に動作している場合、私は見当がつかない。
ドライ穴レポート:
を考える
struct S {
int mA;
int mB;
S() {}
S(int b} : mB(b) {} // a ctor that does partial initialization
};
私はS1のインラインデフォルトコンストラクタは、S(int)を呼び出し、ハードコードされた値を渡しSからS1を導出する試み...
struct S1 {
S1() : S(22) {}
} s1;
...そしてGCC 4.0.1 -O2 -Sを指定してコンパイル。希望は、オプティマイザがs1.mBは必ずしも22になるだろうと見て、コンパイル時に、それを値を割り当てるが、というものであったアセンブラから...
movl $22, 4+_s1-"L00000000002$pb"(%ebx)
...生成されたコードは、メインの前に、実行時に初期化を行うように見えます。それが働いていたとしても、それはほとんどC99としてコンパイルしないであろうと、あなたが初期化したい各オブジェクトのクラスを派生のその場しのぎを持っているでしょう。そう、気にしないでください。
次のコードは、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;
}
ここでの結果です。
$ g++ -o ./test ./test.cpp
$ ./test
1, 2, 3
1, 2, 0
42, 5.88545e-44, 42
1078523331, 3.14, 1078523331
C ++初期化子を持つ唯一のことは、あなたが構造体のすべての要素を初期化する必要があるか、残りがゼロで初期化されるということです。あなたは選ぶと選択することはできません。しかし、それはまだあなたのユースケースのためにOKである必要があります。
ノートの1つの追加のポイント:指定イニシャライザの使用のための重要な理由は、労働組合の最初のメンバーとして、NOT initalizingされる。
。
そのために私は同等のint型の値を提供することにより、「フロート」メンバーを設定する例で示した「回避策」を使用する必要があります。これは、ハッキングのビットだが、それはあなたの問題を解決するかどうか。