본문으로 바로가기

- 구조체 메모리 최적화 -


#include <stdio.h>  //데이터간 장치간 통신할때 사용하는 프로그래밍 해 볼 것

typedef struct _smart  //최적화 전. 28바이트
{
  int a;    
  char b;    
  short c;  
  int d;    
  char e;    
  short f;
  char g;
  int h;
  char i;
  char j;
  short k;
}smart;

typedef struct _smart1  //메모리 최적화 구조체. 24바이트
{
  int a;
    
  char b;  
  short c;
  
  int d;
    
  char e;    
  char g;
  short f;

  int h;

  char i;
  char j;
  short k;
}smart1;

#pragma pack(1)    

typedef struct _smart2  //pragma 테스트 최적화 전.
{
  int a;    
  char b;    
  short c;  
  int d;    
  char e;    
  short f;
  char g;
  int h;
  char i;
  char j;
  short k;
}smart2;

#pragma pack(4)    // 이 범위 안에는 최적화를 자동으로 시켜준다.
      // 전처리어 중에 컴파일러한테 지시를 내리는 것이 있는데 그 중 하나다.
      // 컴파일러 한테 셋팅을 바꾸라는 말이다.
      // pack 은 packing 의 뜻. 어떤 단위로 싼다
      // pack(1)을 하면 1바이트로 싼다.
      // 즉, 다시 애기하면 원래는 pack(4) 4바이트로 최적화가 자동으로 되어있는 상태였고 그것을 임시적으로 (1) 1바이트로 최적화 시켜라.
      // 라고 그 범위만 설정 해 논것이다.
#pragma pack(1)

typedef struct _smart3
{
  int a;
    
  char b;
  short c;
  
  int d;
    
  char e;    
  char g;
  short f;

  int h;

  char i;
  char j;
  short k;
}smart3;

#pragma pack(4)    //왠만하면 구조체 사용시에만 사용하는 것이 좋다. 구조체는 4byte 와 2byte를 좋아하는 성질이 있기 때문에 메모리 최적화를 자기 스스로 시키지 못하기 때문이다.

pragma는 한마디로 진짜 포장한다라는 의미이다. 메모리를 어떤식으로 포장하여 사용할 것인가를 구분해준다.

int main(void)
{
  printf("구조체 type smart의 크기는 ? : %d Byte\n",sizeof(smart));
  printf("구조체 type smart1의 크기는 ? : %d Byte\n",sizeof(smart1));
  printf("구조체 type smart2의 크기는 ? : %d Byte\n",sizeof(smart2));
  printf("구조체 type smart3의 크기는 ? : %d Byte\n",sizeof(smart3));

  return 0;
}
/* 스택 구조는 아래서 부터 변수가 선언 되는 것인데
20바이트를 차지하려면 밑에서부터 5칸을 차지 해야 한다.
★컴파일러가 32비트기에 4바이트에 맞추려고 노력중이다.
int 가 4바이트라 우선순위가 제일 높고 하나의 스텍을 쓰게된다.
허나, char 와 short는 1바이트와 끝에 2바이트를 생성하여 한바이트를 뛰어넘게 된다.
즉, int를(4바이트) 제일 좋아하고 그 다음을 short 형 (2바이트)를 그 다음으로 좋아하고
다시 정리하면 1 1 2 , 2 1 1 과 같다. 좋아하는 2바이트는 중간에 쓰게 되면 한칸 띄우고 한다.

ex) 5바이트를 보내려한다면 2바이트를 먼저 선언 후 , char 형을 세개 선언해줘야 순서가 맞다.
그리고 나서 8바이트 나머지를 선언하려 한다면 char형을 선언해준 다음 그 다음에 short를 선언해줘야
딱 맞는 8바이트 형태가 된다. 
*/


- 구조체 변수 전달 예제 -

#include <stdio.h>

typedef struct _point
{
  int xpos;
  int ypos;
}point;

void showposition(point pos)
{
  printf("[%d, %d]\n", pos.xpos, pos.ypos);
}

point getcurrentposition(void)
{
  point cen;
  printf("input current pos : ");
  scanf("%d %d"&cen.xpos, &cen.ypos);

  return cen;
}

int main(void)
{
  point curpos = getcurrentposition();
  showposition(curpos);  

  return 0;
}



- 구조체 변수 전달 예제 2-


#include <stdio.h>

typedef struct _person
{
  char name[20];
  char phonenum[20];
  int age;
}person;

void showpersoninfo(person man)
{
  printf("name : %s\n", man.name);
  printf("phone : &s\n", man.phonenum);
  printf("age : %d\n",man.age);
}

person readpersoninfo(void)
{
  person man;
  printf("name? "); scanf("%s", man.name);
  printf("phone? "); scanf("%s", man.phonenum);
  printf("age? "); scanf("%d"&man.age);
}

int main(void)
{
  person man = readpersoninfo();
  showpersoninfo(man);

  return 0;  
}



- 구조체 변수 전달 예제 3-


#include <stdio.h>

typedef struct _point
{
  int xpos;
  int ypos;
}point;

void orgsymtrans(point* ptr)  //원점 대칭
{
  ptr->xpos = (ptr->xpos) * -1;
  ptr->ypos = (ptr->ypos) * -1;
}

void showposition(point pos)
{
  printf("[%d, %d]\n", pos.xpos, pos.ypos);
}

int main(void)
{
  point pos = {7, -5};
  orgsymtrans(&pos);
  showposition(pos);
  orgsymtrans(&pos);
  showposition(pos);

  return 0;
}



- 구조체 변수 전달 예제 2 수정-



#include <stdio.h>

typedef struct _person
{
  char name[20];
  char phonenum[20];
  int age;
}person;

void showpersoninfo(person* man)
{
  printf("name : %s\n", man->name);  // 같은 작업.
  printf("phone : &s\n", man->phonenum);
  printf("age : %d\n", man->age);
}

void readpersoninfo(person* man)  // 주소를 받기에 4바이트.
{
    ;
  printf("name? "); scanf("%s", man->name);  //.을 지우고 -> 로 바꾼다.
  printf("phone? "); scanf("%s", man->phonenum);
  printf("age? "); scanf("%d", man->age);

  return;
}

int main(void)
{
  person man;  //44바이트의 복사가 일어난다. 그렇기에 인자로 주소를 던져줘서 point 매개변수로 받아 그 값을 포인터로 수정하게끔 최적화.
  readpersoninfo(&man);
  showpersoninfo(&man);

  return 0;  
}



- 구조체 변수 전달 예제 4-



#include <stdio.h>

typedef struct _point
{
  int xpos;
  int ypos;
}point;

int main(void)
{
  point pos1 = {12};
  point pos2;
  pos2 = pos1;

  printf("크기 : %d\n"sizeof(pos1));
  printf("[%d, %d]\n", pos1.xpos, pos1.ypos);
  printf("크기 : %d\n"sizeof(pos2));
  printf("[%d, %d]", pos2.xpos, pos2.ypos);

  return 0;

}




- 구조체 변수 전달 예제 5-



#include <stdio.h>

typedef struct _point
{
  int xpos;
  int ypos;
}point;

point addpoint(point pos1, point pos2)
{
  point pos = {pos1.xpos + pos2.xpos, pos1.ypos + pos2.ypos};
  
  return pos;
}

point minpoint(point pos1, point pos2)
{
  point pos = {pos1.xpos - pos2.xpos, pos1.ypos - pos2.ypos};

  return pos;
}

int main(void)
{
  point pos1 = {56};
  point pos2 = {29};
  point result;

  result = addpoint(pos1, pos2);
  printf("[%d, %d]\n", result.xpos, result.ypos);
  result = minpoint(pos1, pos2);
  printf("[%d, %d]\n", result.xpos, result.ypos);

  return 0;
}




- 구조체 안의 구조체 선언-



#include <stdio.h>

typedef struct _point
{
  int xpos;
  int ypos;
}point;

typedef struct _circle
{
  point cen;
  double rad;
}circle;

void showcircleinfo(circle* cptr)
{
  printf("[%d, %d]\n", (cptr->cen).xpos, (cptr->cen).ypos);
  printf("radius : %g\n\n", cptr->rad);
}

int main(void)
{
  //circle c1 = { { 1, 2 }, 3.5 };
  
  circle c1;
  circle c2 = { 243.9 };  //구분 짓지 않으면 순서대로 초기화 한다. xpos 다음 ypos
  
  c1.cen.xpos = 1;  //계속해서 구조체를 생성 가능하고 그 구조체 안으로 계속 접근할때는 dot 연산자를 이용해서 
  c1.cen.ypos = 2;  //계속해서 접근할 수 있다.
  c1.rad = 3.5;

  showcircleinfo(&c1);
  showcircleinfo(&c2);

  return 0;
}




- 공용체의 의미 -



#include <stdio.h>


typedef struct _T
{
  unsigned int a;  
  unsigned short b;
  unsigned char c;
}T;

typedef union _T1
{
  unsigned int a;    //78 56 34 12 의 형태로 저장 되어 반대로 12 34 56 78 로 출력되게 된다.
  unsigned short b;  //이러한 것으로 말미암아 쇼트 b는 덮어씌우는 형태로 78 56 부분에 저장하게 될 것이고
  unsigned char c;    //차 c는 78부분에 덮어씌우게 될 것이다.
}T1;

int main(void)
{
  T obj1;
  T1 obj2;
  
  obj1.a = 0x12345678;
  obj1.b = 0xABCD;
  obj1.c = 0xEE;  //8보다 크면 무조건 음수로 취급하기 때문에 양수 형태로 선언해야 한다. 그래서 현재 FFFFABCD , FFFFFFEE로 출력 되고 있다.

  obj2.a = 0x12345678;
  obj2.b = 0xABCD;
  obj2.c = 0xEE;  

  printf("구조체 type T의 변수 obj1의 멤버 a의 16진수 값은 ? %X\n",obj1.a);
  printf("구조체 type T의 변수 obj1의 멤버 b의 16진수 값은 ? %X\n",obj1.b);
  printf("구조체 type T의 변수 obj1의 멤버 c의 16진수 값은 ? %X\n\n",obj1.c);

  printf("공용체 type T1의 변수 obj2의 멤버 a의 16진수 값은 ? %X\n",obj2.a);
  printf("공용체 type T1의 변수 obj2의 멤버 b의 16진수 값은 ? %X\n",obj2.b);
  printf("공용체 type T1의 변수 obj2의 멤버 c의 16진수 값은 ? %X\n\n",obj2.c);

  printf("구조체 type T의 크기는 ? %d\n",sizeof(T));
  printf("유니온 type T1의 크기는 ? %d\n",sizeof(T1));

  return 0;
}





- 공용체 예제 -



#include <stdio.h>

typedef struct _sbox
{
  int mem1;
  int mem2;
  double mem3;
}sbox;

typedef union _ubox
{
  int mem1;
  int mem2;
  double mem3;
}ubox;

int main(void)
{
  sbox sbx;
  ubox ubx;

  printf("%p %p %p\n",&sbx.mem1, &sbx.mem2, &sbx.mem3);
  printf("%p %p %p\n",&ubx.mem1, &ubx.mem2, &ubx.mem3);
  printf("%d %d\n",sizeof(sbox), sizeof(ubox));

  return 0;
}







- 공용체 예제 2 -

#include <stdio.h>

typedef union _ubox
{
  int mem1;
  int mem2;
  double mem3;
}ubox;

int main(void)
{
  ubox ubx;
  ubx.mem1 = 20;
  printf("%d\n", ubx.mem2);

  ubx.mem3 = 7.15;
  printf("%d\n", ubx.mem1);
  printf("%d\n", ubx.mem2);
  printf("%g\n", ubx.mem3);

  return 0;
}





- 공용체 예제3 -

#include <stdio.h>

typedef struct _dbshort
{
  unsigned short upper;  //short를 제일 먼저 선언하게 되면 구조체는 오른쪽에다가 할당 해 준다. 그래서 상위 쇼트라고 이름 지었다.
  unsigned short lower;  //
}dbshort;

typedef union _rdbuf
{
  int ibuf;
  char bbuf[4];
  dbshort sbuf;
}rdbuf;

int main(void)
{
  rdbuf buf;
  printf("정수 입력 : ");
  scanf("%d"&(buf.ibuf));

  printf("상위 2바이트 : %u\n",buf.sbuf.upper);
  printf("하위 2바이트 : %u\n",buf.sbuf.upper);
  printf("상위 1바이트 아스키 코드 : %c\n",buf.bbuf[0]);
  printf("상위 1바이트 아스키 코드 : %c\n",buf.bbuf[3]);

  return 0;
}





- 열거형 예제 -

#include <stdio.h>

typedef enum _syllable  //typedef 선언이 추가된 열거형의 정의
{
  Do = 1, re = 2, mi = 3, fa = 4, so = 5, la = 6, ti = 7
}syllable;

void sound(syllable sy)
{
  switch (sy)
  {
  case Do:
    puts("도는 하얀 도라지");
    return;

  case re:
    puts("레는 하얀 도라지");
    return;

  case mi:
    puts("미는 하얀 도라지");
    return;

  case fa:
    puts("파는 하얀 도라지");
    return;

  case so:
    puts("솔는 하얀 도라지");
    return;

  case la:
    puts("라는 하얀 도라지");
    return;

  case ti:
    puts("시는 하얀 도라지");
    return;
  }

  puts("다 함께 부르세 ~ 도레미파 솔라시도 솔 도~");
}

int main(void)
{
  syllable tone;

  for (tone = Do; tone <= ti; tone += 1)
  {
    sound(tone);
  }

  return 0;
}





- 열거형 기본형 준비 -

#include <stdio.h>  

typedef enum _smart  //열거형 enumeratedv type, 이것은 보통 int 타입이라 생각하면 된다.
{
  ZERO = -100,  //이렇게 초기화 한 후 ONE 을 출력하면 1이 증가한 형태인
  ONE,    //보통 대문자로 선언.
  TWO = 502,  //이렇듯 중간에서도 바꿔서 그 다음부터 열거 식으로 넘버링이 가능하다.
  THREE,
  FOUR



}smart;

int main(void)
{
  int e1;
  
  e1 = ONE;

  printf("%d",e1);
  printf("%d",THREE);

  return 0;
}
//일종의 디파인, 우리가 1,2,3,4 적을 필요 없이 순서대로 차례로 늘어나게끔 된다.
//넘버링 즉 번호 매길때 편리하게 쓰이는 열거형 타입이다.
//일종의 디파인 이라는 소리라는 것은 변수 형태로 따로 선언을 해주지 않고
//enum 으로 정의해주면 어디서든 불러서 쓸 수 있다.
//레지스터 주소 매기듯이 데이터를 열거해서 쓸 수 있다. (volatile 하듯이)