programing

C++ 지정 이니셜라이저와 동등합니까?

yellowcard 2023. 8. 8. 21:28
반응형

C++ 지정 이니셜라이저와 동등합니까?

최근에 저는 임베디드 장치에 대해 작업하고 있습니다. 컴파일 시 초기화해야 하는 구조와 유니언이 있으므로 수정할 필요가 없는 특정 항목을 플래시 또는 ROM에 보관하고 약간의 성능 비용으로 플래시 또는 SRAM을 절약할 수 있습니다.현재 코드는 유효한 C99로 컴파일되지만, 이 조정이 없으면 C++ 코드로도 컴파일되었으며, 그렇게 컴파일되는 것도 지원하면 좋을 것입니다.이를 방지하는 핵심 사항 중 하나는 C++의 C 하위 집합 내에서 작동하지 않는 C99 지정 이니셜라이저를 사용한다는 것입니다.저는 C++ 버프를 별로 좋아하지 않기 때문에 C++ 호환 C 또는 컴파일 시 초기화를 허용하여 SRAM에서 프로그램 시작 후 구조와 유니언을 초기화할 필요가 없도록 하는 간단한 방법이 무엇인지 궁금합니다.

한 가지 추가 사항: 지정된 이니셜라이저를 사용하는 주요 이유는 조합의 첫 번째 구성원이 아닌 초기화하는 것입니다.또한 표준 C++ 또는 ANSIC를 고수하는 것은 다른 컴파일러와의 호환성을 유지하기 위한 장점입니다(C99 없이 지정된 이니셜라이저와 같은 것을 제공하는 GNU 확장에 대해 알고 있습니다).

C++로 할 수 있을지 모르겠습니다.지정된 이니셜라이저를 사용하여 초기화해야 하는 항목의 경우 해당 항목을 별도로.cC99로 컴파일된 파일(예:

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

반응형