구조체

구조체는 기존의 자료형인 int, char...등을 묶어 만든 사용자 정의 자료형입니다. 구조체는 struct{ 내용 }의 형식으로 만들 수 있습니다. 또, 구조체 자료형의 변수를 만들려면 struct 구조체 이름 변수 이름과 같이 해 주면 됩니다.

#include <stdio.h>
struct st1 {
      int a, b;
};
struct st1 p;
struct st2 {
      int c, d;   //멤버 이름이 겹쳐도 딱히 문제는 없습니다.
} q, k;           //바로 써도 OK
int main() {
      struct st1 ob1;
      struct st2 ob2;
      struct { int e, f; } ob3; //같은 자료형으로 더 이상 변수를 만들 생각이 없다면 OK
      p.a = 1, p.b = 2;
      q.c = 10, q.d = 20;
      ob1.a = 3, ob1.b = 4;
      ob2.c = 30, ob2.d = 40;
      ob3.e = 5, ob3.f = 6;
      printf("p.a: %d, p.b: %d\n", p.a, p.b);
      printf("q.c: %d, q.d: %d\n", q.c, q.d);
      printf("ob1.a: %d, ob1.b: %d\n", ob1.a, ob1.b);
      printf("ob2.c: %d, ob2.d: %d\n", ob2.c, ob2.d);
      printf("ob3.e: %d, ob3.f: %d\n", ob3.e, ob3.f);
      return 0;
}

p.a: 1, p.b: 2
q.c: 10, q.d: 20
ob1.a: 3, ob1.b: 4
ob2.c: 30, ob2.d: 40
ob3.e: 5, ob3.f: 6

자, 한 예제에 모두 담아 보았습니다. pob1을 만드는 부분은 가장 기초적인 구조체 사용법입니다. 여기서의 ab멤버(멤버 변수)라 합니다.

qk를 만드는 것은 조금 특별해 보입니다. 이렇게 구조체를 만들고, 중괄호 뒤에 바로 변수를 선언할 수도 있습니다.

마지막으로 ob3을 만드는 것은 많이 이상해 보입니다. 하지만 이는 문법에 맞습니다. 이렇게 이름 없는 자료형으로 구조체를 만들 수도 있습니다.

멤버의 초기화는 어떻게 할까요?

struct st1 {
      int a = 0, b = 0;
};

아아! 이런 방법은 통하지 않습니다! 귀찮게스리. 그쵸? 물론 컴파일러 자체 확장 기능으로 이런 초기화를 지원하기도 합니다만, 모든 곳에서 컴파일되는 것은 기대하지 마십시오.

#include <stdio.h>
struct st1 {
      int a, b;
};
int main() {
      struct st1 a = { 0, 0 }, b = { 1, 2 };
      printf("a.a: %d, a.b: %d\n", a.a, a.b);
      printf("b.a: %d, b.b: %d\n", b.a, b.b);
      return 0;
}

a.a: 0, a.b: 0
b.a: 1, b.b: 2

이렇게 { 중괄호 }를 사용해 각 변수에 대해 하나하나 초기화를 해 주는 방법밖에 없습니다.

구조체 변수의 크기를 보겠습니다.

#include <stdio.h>
int main() {
      printf("%d %d %d %d\n",
      sizeof(struct{ int a; }),
      sizeof(struct{ int a, b; }),
      sizeof(struct{ int a, b, c; }),
      sizeof(struct{ int a, b, c, d; }));
      return 0;
}

4 8 12 16

그냥 평범하게 각 멤버들 크기의 합으로 보이는 것 같습니다만, 실은 아닙니다. 속았죠?

#include <stdio.h>
int main() {
      printf("%d %d %d %d\n",
      sizeof(struct{ char a; int k; }),
      sizeof(struct{ char a, b; int k; }),
      sizeof(struct{ char a, b, c; int k; }),
      sizeof(struct{ char a, b, c, d; int k; }));
      return 0;
}

8 8 8 8

5 6 7 8이 나와야 할 것 같은데, 8 8 8 8이 나옵니다! 좀 이상하지 않나요?

컴파일러는 최대한 좋은 프로그램을 만들어 주려 노력합니다. 과거에는 메모리 자원이 모자랐기 때문에 메모리를 아끼는 것이 가장 좋은 것이라 생각되었지만, 오늘날에는 메모리 자원이 아주 풍족하기 때문에 조금이라도 더 빠른 프로그램이 좋은 평가를 받습니다.

자료형을 설명하며, 명령어의 길이에 맞는 자료형이 가장 빠르다고 한 것을 기억하나요? 이 때문에, 컴파일러는 메모리를 조금 희생하는 한이 있더라도, 구조체의 크기를 멤버 변수 중 가장 큰 크기를 갖는 것에 맞춥니다. 이렇게요.

#include <stdio.h>
int main() {
      printf("%d\n", sizeof(struct{ char a; long long k; }));
      return 0;
}

16

이런 것을 바이트 패딩이라 부릅니다. #pragma pack을 사용해 이런 최적화를 할 것인지 말 것인지 결정할 수 있지만, 여기에서는 다루지 않겠습니다.