나의 IT일지
구조체와 비트필드 본문
구조체는 여러 자료형을 가진 변수를 통해 만드는 자료형으로, 구조체 자료형으로 만든 변수를 구조체 변수이다. 이러한 구조체 변수는 정해진 필드 형태에 따라 여러 자료형의 데이터를 저장할 수 있는데, 데이터량이 적을경우 저장공간이 많이 남는경우가 발생한다. 저장공간은 하나의 데이터만 저장할 수 있기 때문에, 저장공간의 낭비가 발생한다. 그래서 우리는 필드의 저장공간을 정하는 방법에 대해서 알아야 한다.
비트필드
비트란 데이터의 최소단위로, 2진수로 표현된 데이터의 자릿수에 따라 비트의 값이 결정된다. 예를들어, 4의 2진수는 "100"이며 데이터로 저장될 때에는 3bit의 공간을 차지한다.
생성방법 struct 구조체명{ 자료형 변수명: 필요한 비트수; 자료형 변수명: 필요한 비트수; 자료형 변수명: 필요한 비트수; ... }; |
위의 구조는 비트필드를 생성하는 구조이다. 비트필드란 구조체내에서 필드의 저장공간을 비트단위로 지정하는 기능으로, 사용하는 레코드(필드에 저장되는 데이터)의 범위에 따라 비트로 재정의 할 수 있다. 이때 첫번쨰 비트는 최상위 비트(부호 비트)이므로 "표현할 데이터의 범위 +1"해서 지정해야 한다.
#include<stdio.h>
struct s_Data {
int grade;
int class;
int gender;
};
struct bit_data {
int grade: 2;
int class: 3;
int gender: 5;
};
void main() {
struct s_Data s;
struct bit_data b;
printf("s_data:%d\n", sizeof(s));
printf("bit_data:%d\n", sizeof(b));
}
위의 코드를 보면, 비트필드를 이용한 변수가 차지하는 메모리 공간이 4byte인 것을 확인할 수 있다. 이는 CPU는 4byte단위로 데이터를 읽기 때문에 나타나는 현상이다.
위의 코드중 gender필드의 자료형을 문자형으로 바꾸면 다음과 같은 결과가 나온다.
#include<stdio.h>
struct s_Data {
int grade;
int class;
int gender;
};
struct bit_data {
int grade: 2;
int class: 3;
char gender[2] ;
};
void main() {
struct s_Data s;
struct bit_data b;
printf("s_data:%d\n", sizeof(s));
printf("bit_data:%d\n", sizeof(b));
}
이유는 정수형 필드가 사용하는 저장공간과 문자형 필드가 사용하는 메모리 공간이 구분되어 있어서 나타나는 현상이다. 정수형 필드의 최대 저장공간이 4byte이고 문자형 필드의 최대 저장공간이 2byte이지만, 패딩 바이트를 넣어 멤버들을 가지런하게 정렬한다.
이를 바이트 얼라인먼트라고 하는데, 이렇게 저장공간을 가지런히 정렬하는 이유는 cpu접근을 더 용이하게 하기 위함이다. 우리 CPU는 32bit나 64bit로 운영이 된다. 즉 CPU를 운영할 때, 4byte단위로 한번에 읽으면서 운영이 진행된다.
만약 패딩 바이트가 없을 경우, CPU의 운영 부하는 증가하게 된다. 예를들어, 문자형 변수뒤에 정수형 변수가 추가되었다고 가정한다면, CPU는 문자형의 데이터를 읽은다음, 정수형의 데이터를 읽어야 하는데, 패딩 바이트가 없을 경우, CPU는 메모리에서 정수형 데이터를 찾는 과정을 2번 실행하게 된다.
패딩바이트가 있을 경우, 문자형 데이터와 정수형 데이터가 구분되어 있기에 정수형 데이터를 찾는 과정은 1번만 실행한다. 이러한 CPU의 운영을 1번 줄이기 위해 저장공간의 낭비가 있더라도 패딩바이트를 사용하는 것이다.
구조체의 비트필드의 사용예시
#include <stdio.h>
#include<string.h>
struct bit_data {
int grade : 3;
int class : 5;
char gender[7];
};
void main() {
struct bit_data data;
data.grade = 1;
data.class = 10;
strcpy(data.gender,"female");
printf("data.grade : %d\n", data.grade);
printf("data.class : %d\n", data.class);
printf("data.gender : %s\n", data.gender);
}
grade의 속성의 비트수는 3bit으로 부호비트를 제외하면 2bit로 데이터를 저장해야 한다. 즉 grade의 저장할 수 있는 데이터의 범위는 "00","01","10","11"로 0~3까지 저장이 가능하다. 같은 이유로, class는 4bit에 해당하는 정수의 범위인 0~15까지 저장이 가능하다.
만약 해당 범위에 벗어난 데이터를 입력할 경우, 비트필드로 출력할 수 있는 정수의 값이 저장할 수 있는 데이터를 기준으로 차례대로 출력이 된다. 예를 들면 비트필드 "3"인변수에 "4"를 입력하면, "-4"가 출력되는 것을 알 수 있는데, 이는 비트필드로 만들 수 있는 값이 "-4~3"까지 이기에, 3까지는 정상적으로 출력이 되고, 4부터는 -4를 시작으로 5는 -3, 6은 -2 순으로 출력이 된다.