[英]C++ Equivalent to Designated Initializers?
最近,我一直在研究某些嵌入式設備,其中有一些結構和聯合需要在編譯時進行初始化,以便我們可以將某些不需要修改的內容保存在閃存或ROM中,並節省一些時間。閃存或SRAM,但會降低性能。 目前,該代碼可以作為有效的C99進行編譯,但是如果不進行此調整,它也可以作為C ++代碼進行編譯,並且也支持以這種方式進行編譯。 防止這種情況的關鍵之一是我們使用的是C99指定的初始化程序,這些初始化程序在C ++的C子集中不起作用。 我不是C ++愛好者,所以我想知道有什么簡單的方法可以在兼容C ++的C或仍允許在編譯時進行初始化的C ++中實現,而無需使用結構和聯合在SRAM中啟動程序后初始化。
還有一點要注意:指定初始化程序使用的一個關鍵原因是初始化為不是聯合的第一個成員。 另外,堅持使用標准C ++或ANSI C是保持與其他編譯器兼容性的一個加號(我知道GNU擴展提供了諸如C99的指定初始值設定項)。
我不確定您是否可以用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
這既是答案,又是問題。 我意識到這個線程已經死了,但這恰恰是我今晚在研究的內容。
我做了一些探索,然后就可以找到我想要的最接近的東西(這類似於您想要的東西。我一直在使用圖片,不需要使用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中。)我看過的第二個代碼版本是:
#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 ++以外的其他任何編譯器是否有效或表現相似。
#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 ++中,union也可以具有構造函數。 可能這就是您想要的嗎?
以下代碼在使用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 ++初始值設定項的唯一作用是您需要初始化該結構的所有元素,否則其余部分將被初始化為零。 您不能選擇。 但這對於您的用例仍然應該可以。
還有一點要注意:指定初始化程序使用的一個關鍵原因是初始化為不是聯合的第一個成員。
為此,您需要使用示例中顯示的“解決方法”,在該示例中,我通過提供等效的int值來設置“ float”成員。 這有點hack,但是如果它可以解決您的問題。
干孔報告:
給定
struct S {
int mA;
int mB;
S() {}
S(int b} : mB(b) {} // a ctor that does partial initialization
};
我嘗試從S派生S1,其中S1的內聯默認構造函數調用S(int)並傳遞硬編碼值...
struct S1 {
S1() : S(22) {}
} s1;
...然后使用gcc 4.0.1 -O2 -S進行編譯。 希望優化器可以看到s1.mB一定為22並在編譯時為其賦值,但是是從匯編器...
movl $22, 4+_s1-"L00000000002$pb"(%ebx)
...看起來生成的代碼在運行main之前就在運行時進行了初始化。 即使它起作用了,也很難像C99一樣編譯,並且有為要初始化的每個對象派生一個類的麻煩。 所以,不要打擾。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.