programing

한 번에 여러 개의 값을 구조체에 할당하는 방법

prostudy 2022. 6. 10. 21:30
반응형

한 번에 여러 개의 값을 구조체에 할당하는 방법

구조 Foo 초기화 시 다음과 같이 할 수 있습니다.

Foo foo =  {bunch, of, things, initialized};

하지만 난 이걸 할 수 없어.

Foo foo;
foo = {bunch, of, things, initialized};

두 가지 질문이 있습니다.

  1. 후자는 왜 할 수 없는 거죠?전자는 초기화 전용 컨스트럭터입니까?
  2. 두 번째 예시와 유사한 작업을 수행할 수 있는 방법은 무엇입니까? 즉, 이미 초기화된 후 한 줄의 코드로 구조체의 변수를 선언하는 것입니다.변수가 많은 대형 구조물에 대해서는 이 작업을 수행할 필요가 없습니다.

    Foo foo;
    
    foo.a = 1;
    foo.b = 2;
    foo.c = 3;
    //... ad infinitum
    

이것을 시험해 보세요.

Foo foo;
foo = (Foo){bunch, of, things, initialized};

이것은 정상적인 컴파일러(GCC 등)가 있는 경우 동작합니다.C99 의 경우는, 으로 할 가 있는 경우가 .--std=gnu99

첫 번째는 애그리게이트 이니셜라이저입니다.이 솔루션에서는 이러한 이니셜라이저와 태그 부착 이니셜라이저에 대해 자세히 알아볼 수 있습니다.

태그 부착 구조 초기화 구문이란 무엇입니까?

이것은 특수한 초기화 구문이며 구조 초기화 후에는 유사한 작업을 수행할 수 없습니다.할 수 있는 것은 멤버(또는 비멤버) 함수를 제공하여 일련의 값을 파라미터로 지정한 후 멤버 함수 내에서 할당하는 것입니다.이것에 의해, 구조가 동등하게 간결하게 초기화된 후에(물론 함수를 처음 쓴 후에) 이것을 실현할 수 있습니다.

C++11에서는 "tie"(태플 헤더에 선언됨)를 사용하여 여러 할당을 수행할 수 있습니다.

struct foo {
    int a, b, c;
} f;

std::tie(f.a, f.b, f.c) = std::make_tuple(1, 2, 3);

오른쪽 표현이 고정 크기이고 일부 요소만 가져오면 되는 경우, 넥타이와 함께 무시 자리 표시자를 사용할 수 있습니다.

std::tie(std::ignore, f.b, std::ignore) = some_tuple; // only f.b modified

std::tie(f.a, f.b, f.c) 구문이 너무 코드 잡음이 심한 경우 해당 참조 태플을 반환하는 멤버 함수가 있을 수 있습니다.

struct foo {
    int a, b, c;
    auto members() -> decltype(std::tie(a, b, c)) {
        return std::tie(a, b, c);
    }
} f;

f.members() = std::make_tuple(1, 2, 3);

물론 이 모든 것은 할당 연산자를 오버로드하는 것이 선택사항이 아니라고 가정합니다. 왜냐하면 이러한 일련의 값으로는 구조체를 구성할 수 없기 때문입니다. 이 경우 다음과 같이 말할 수 있습니다.

f = foo(1, 2, 3);

메모리 풋프린트 - i386에 대한 흥미로운 추가사항을 소개합니다.

많은 번거로움 끝에 최적화와 memcpy사용하면 GCC와 C99를 갖춘 i386을 사용하여 최소 설치 공간을 확보할 수 있습니다.저는 여기서 -O3를 사용하고 있습니다.stdlib에는 모든 종류의 재미있는 컴파일러 최적화가 준비되어 있는 것 같습니다.이 예에서는 그것을 사용하고 있습니다(memcpy는 실제로 여기에 컴파일되어 있습니다).

다음을 수행합니다.

Foo foo; //some global variable

void setStructVal (void)   {

    const Foo FOO_ASSIGN_VAL = {    //this goes into .rodata
            .bunch       = 1,
            .of          = 2,
            .things      = 3,
            .initialized = 4
    };

    memcpy((void*) &FOO_ASSIGN_VAL, (void*) foo, sizeof(Foo));

    return;
}

결과:

  • (.rodata) FOO_ASSIGN_VAL은 .rodata에 저장됩니다.
  • (.text) *movl FOO_ASSIGN_VAL, %registers*의 시퀀스가 발생합니다.
  • (.text) 일련의 movl %syslog, foo 발생

예제:

  • Say Foo는 uint8_t 값의 48 필드 구조체입니다.메모리로 정렬되어 있습니다.

  • (이상적) 32비트 머신에서는 foo의 주소 공간에 대한 MOVL 명령어 12개만큼 빠르게 수 있습니다.이 값은 12*10 == 120바이트의 .text 크기입니다.

  • (ACTUAL) 단, AUTO에 의한 응답을 사용하면 .text에 48개의 MOVB 명령이 생성됩니다.48*7==336바이트의 .text!!

  • (SMARKEST*) 위의 memcpy 버전을 사용합니다.얼라인먼트가 처리됩니다만,

    • FOO_ASSIGN_VAL은 .rodata(48바이트),
    • 12 MOVL을 %register로
    • .text(24*10) == 240바이트에서 사용되는 MOVL은 %text(24*10) 중 12개입니다.
    • 저는 총 288바이트입니다.

그래서 적어도 제 i386 코드로는

- Ideal:    120 bytes
- Direct:   336 bytes
- Smallest: 288 bytes

* 여기서 가장 작다는 것은 '내가 아는 가장 작은 공간'을 의미합니다.또, 상기의 방법보다 고속으로 실행됩니다(24개의 명령과 48개의 명령).물론, IDEAL 버전이 가장 빠르고 작습니다만, 아직 그것을 알 수 없습니다.

- Justin(저스틴)

* 위의 'IDEAL'을 구현하는 방법을 아는 사람이 있습니까?정말 짜증나!!

효율성에 관심이 있는 경우 한 번에 할당할 수 있는 유형으로 구조와 동일한 길이의 결합을 정의할 수 있습니다.

요소별로 값을 할당하려면 결합 구조를 사용하고 전체 데이터를 할당하려면 결합의 다른 유형을 사용합니다.

typedef union
{
    struct
    {
      char a;
      char b;
    } Foo;
    unsigned int whole;
} MyUnion;

MyUnion _Union;
_Union.Foo.a = 0x23;    // assign by element
_Union.Foo.b = 0x45;    // assign by element
_Union.whole = 0x6789;  // assign at once

메모리 구성('a'는 MSB 또는 '전체?'의 LSB)에 주의하십시오.

효율성에 크게 신경 쓰지 않는 경우, 이중으로 할당할 수 있습니다. 즉, Aggregate Initialization을 사용하여 구조의 새 인스턴스를 생성한 후 다시 복사합니다.

구조물 Foo foo;
{structure Foo __tmp__ = {구체, 사물, 초기화됨};foo = __tmp__;}

불필요한 임시 변수가 더 이상 필요하지 않은 즉시 폐기되도록 부분을 {}s로 감싼 상태로 유지하십시오.

예를 들어 구조 내에서(c++인 경우) 또는 구조 외부에서 구조 포인터를 받아들이는 '세트' 함수를 만드는 것만큼 효율적이지 않습니다(C인 경우).단, 요소별 쓰기 할당 대신 빠른 임시 할당이 필요한 경우 이 방법을 사용할 수 있습니다.

언급URL : https://stackoverflow.com/questions/9269825/how-to-assign-multiple-values-into-a-struct-at-once

반응형