C++ 지정 이니셜라이저와 동등합니까?
최근에 저는 임베디드 장치에 대해 작업하고 있습니다. 컴파일 시 초기화해야 하는 구조와 유니언이 있으므로 수정할 필요가 없는 특정 항목을 플래시 또는 ROM에 보관하고 약간의 성능 비용으로 플래시 또는 SRAM을 절약할 수 있습니다.현재 코드는 유효한 C99로 컴파일되지만, 이 조정이 없으면 C++ 코드로도 컴파일되었으며, 그렇게 컴파일되는 것도 지원하면 좋을 것입니다.이를 방지하는 핵심 사항 중 하나는 C++의 C 하위 집합 내에서 작동하지 않는 C99 지정 이니셜라이저를 사용한다는 것입니다.저는 C++ 버프를 별로 좋아하지 않기 때문에 C++ 호환 C 또는 컴파일 시 초기화를 허용하여 SRAM에서 프로그램 시작 후 구조와 유니언을 초기화할 필요가 없도록 하는 간단한 방법이 무엇인지 궁금합니다.
한 가지 추가 사항: 지정된 이니셜라이저를 사용하는 주요 이유는 조합의 첫 번째 구성원이 아닌 초기화하는 것입니다.또한 표준 C++ 또는 ANSIC를 고수하는 것은 다른 컴파일러와의 호환성을 유지하기 위한 장점입니다(C99 없이 지정된 이니셜라이저와 같은 것을 제공하는 GNU 확장에 대해 알고 있습니다).
C++로 할 수 있을지 모르겠습니다.지정된 이니셜라이저를 사용하여 초기화해야 하는 항목의 경우 해당 항목을 별도로.c
C99로 컴파일된 파일(예:
// 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
Sing Yip의 답변을 바탕으로 C++11은 이제 3년의 시간을 활용하여 컴파일 시간 초기화를 보장할 수 있습니다.
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__cplus로 마무리해야 할 것입니다.)두 번째 버전의 코드는 다음과 같습니다.
#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
例권지 으로 덜 는 명령어수 더했습니다.직관적으로 덜 효율적인 예제는 명령어 수 측면에서 더 효율적인 opcode를 생성했습니다.반면에 몇 가지 명령어가 비판적인 것을 상상할 수 있는 경우는 거의 없습니다. (반면, 저는 인간이 작성하지 않은 어셈블리를 이해하는 데 정말 어려움을 겪고 있기 때문에, 아마도 뭔가를 놓치고 있는 것 같습니다...저는 이것이 제임스가 질문한 질문에 대한 늦은 해결책을 제공한다고 생각합니다.다음으로 제가 테스트해야 할 것은 C99에서 동일한 초기화가 허용되는지 여부입니다. 만약 그것이 효과가 있다면, 저는 그것이 제임스의 문제를 완전히 해결한다고 생각합니다.
고지 사항:나는 이것이 g++ 이외의 다른 컴파일러에서도 작동하는지 동작하는지 전혀 모릅니다.
건조 구멍 보고서:
정해진
struct S {
int mA;
int mB;
S() {}
S(int b} : mB(b) {} // a ctor that does partial initialization
};
S1에서 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로 거의 컴파일할 수 없으며 초기화하려는 각 개체에 대한 클래스를 파생하는 kulbs가 있을 것이므로 신경 쓰지 마십시오.
다음 코드는 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++ 이니셜라이저의 유일한 점은 구조체의 모든 요소를 초기화해야 한다는 것입니다. 그렇지 않으면 나머지 요소가 0으로 초기화입니다.당신은 고르고 고를 수 없습니다.그러나 사용 사례에 대해서는 여전히 문제가 없을 것입니다.
한 가지 추가 사항: 지정된 이니셜라이저를 사용하는 주요 이유는 조합의 첫 번째 구성원이 아닌 초기화하는 것입니다.
이를 위해서는 동일한 int 값을 제공하여 "플로트" 멤버를 설정한 예제에 나와 있는 "해결 방법"을 사용해야 합니다.약간의 해킹이지만, 만약 그것이 당신의 문제를 해결한다면요.
언급URL : https://stackoverflow.com/questions/855996/c-equivalent-to-designated-initializers
'programing' 카테고리의 다른 글
원격 클라이언트에서 Mariadb를 연결할 수 없습니다. (0) | 2023.08.08 |
---|---|
Galera 노드가 클러스터에 연결할 수 없음 (0) | 2023.08.08 |
결과 집합에서 열 값을 읽을 수 없습니다. (0) | 2023.08.08 |
jquery에서 텍스트 영역의 값을 얻는 방법은 무엇입니까? (0) | 2023.08.08 |
Swift UI - Swift에 해당하는 popViewController가 있습니까?UI? (0) | 2023.08.08 |