노는게 제일 좋습니다.

18회차(끝) : 구조체 초기화, 비트 구조체, 공용체 본문

C

18회차(끝) : 구조체 초기화, 비트 구조체, 공용체

노는게 제일 좋습니다. 2017. 3. 3. 13:28

0. 참고 자료

http://soen.kr/


1. 구조체 초기화

구조체의 멤버들은 마치 배열을 초기화하듯 초기화할 수 있다. 별거없다.

struct b {
  int apple;
  int banana;
 };
 struct a {
  struct b bb;
  int tomato;
 };

 struct a plug = { {1,2},3 };
 printf("%d %d %d\n", plug.bb.apple, plug.bb.banana, plug.tomato);


2. 구조체의 대입

구조체는 같은 모양이면 대입할 수 있다. 멤버들을 덮어씌우는 것이다.


struct strt {
  int one;
  int two;
 };
 struct strt a = { 1,2 };
 struct strt b=a;
 printf("%d %d", b.one, b.two);

위 예제는 strt태그로부터 구조체 a,b를 만든다. 그리고 b에 a를 대입한다.

이게 가능하다는 것은, 구조체가 좌변값이라는 것. 함수 인수로 받을 수도 있고, 리턴하는데 구조체를 쓸 수 있다.

b=a 구문은 memcpy(&b, &a, sizeof(a)); 와 같다. 메모리를 푹 퍼다가 복사해주는 것이다.


3. 깊은 복사와 얕은 복사

 struct strt {
  char *pc;
 };

 struct strt a = { NULL };
 struct strt b;

 a.pc = malloc(32);
 strcpy_s(a.pc,sizeof("helololollooo"),"helololollooo");

 b = a;

 printf("%s %s\n", a.pc, b.pc);
 
 strcpy_s(a.pc, sizeof("goodbyeeeyee"), "goodbyeeeyee");
 printf("%s %s\n", a.pc, b.pc);


위 코드는 a.pc에 "hellololo"비슷한걸 복사하고난뒤에, b=a를 한다.

이후에 a.pc가 가리키는 문자열의 내용을 바꿨더니 b.pc도 바뀐다.

이것은 b.pc에 a.pc의 값 그 자체가 단순히 복사되어 들어갔기 때문이다. helolollolo 문자열이 아닌, 포인터를 복사했다는 말이다.

잘못됐다는 것이 아니라, 이런 현상이 일어나기 때문에 대입했을 때 의도치않은 상황이 생길 수 있다는 것이다.

이와 같이 그냥 단순히 복사만 하는 것을 '얕은 복사' 라고 한다.


반면 '깊은 복사'는 포인터를 복사하는게 아니고, 포인터를 따라가면 나오는 그 값을 취한다.

즉, b=a를 할 때 깊은 복사가 일어났다면, a.pc 라는 포인터가 b.pc로 대입되지 않는다.

b.pc는 새로운 공간을 할당한 뒤에, "helololllo"를 여기에 기록한다.


 b = a;
 b.pc = malloc(32);
 strcpy_s(b.pc, strlen(a.pc)+1, a.pc);

위는 깊은 복사의 한 예이다. b에 일단 a를 대입한다. 그 다음 b에다가는 a포인터를 따라가면 나오는 "helololo"따위의 상수를 기록해준다.


4. 비트 구조체

비트들을 멤버로 가지는 구조체이다.


struct tag_bit {
  unsigned int a : 4;
  unsigned int b : 8;
  unsigned int c : 4;
 };

위 코드는 비트 구조체를 정의한 것이다. 타입 멤버이름 : 비트수; 의 형식으로 멤버들을 적어준다.

위의 경우 총 16비트 = 2바이트를 차지한다. 비트들은 먼저 쓰인것이 일반적으로 하위비트(작은 자리)로 들어간다.

예를 들어, 0101 00110101 1110 이렇게 2바이트 코드가 있을 때, 맨뒤 1110을 a가 나타내고, 맨앞 0101을 c가 나타낸다.


struct tag_bit {
  unsigned int a : 4;
  unsigned int  : 0;
  unsigned int c : 4;
 };

만약 이렇게 크기를 0으로 주면, 해당 워드에서 사용되지 않은 비트는 모두 버린다.

c는 그 다음 워드에서 시작한다. 구조체 패딩과 비슷한 맥락에서 이해할 수 있겠다.


물론, 비트 필드가 구조체에 쓰였다고 해서 우리가 늘상 쓰던 멤버를 쓸 수 없는 것은 아니다. 섞어써도 된다. 


5. 공용체

공용체는 구조체와 문법이 유사하나, 멤버들이 기억공간을 공유한다는 특징을 가진다.


union {

  int a;

  char b[10];

}unab;

위와 같은 코드로 unab라는 이름의 공용체를 하나 정의했다. 여기서 a의 주소와 b의 주소는 같다.

즉, a값이 바뀌면 b값도 바뀐다. b값이 바뀌면 마찬가지로 a값도 바뀐다.

공용체의 크기는 가장 큰 멤버의 크기와 같다.


하나의 정보를 나타내는데 여러 형식으로 나타내고 싶을 때 공용체를 사용한다.

Comments