Unit 56 구조체 필드 사용하기
지금까지는 여러 자료형을 사용하여 해당 자료형의 크기만큼만 구조체에서 공간을 차지하도록 했는데, 비트 필드를 사용하면 bit 단위로도 값을 저장할 수 있다.
사용은 간단하다.
struct <구조체 명>
{
<정수 자료형> <멤버 명> : <비트 수>;
};
로 멤버를 선언하면 해당 비트만큼의 크기를 가진 멤버가 생성된다.
#include <stdio.h>
typedef struct a
{
unsigned int a : 1; // 1bit
unsigned int b : 2; // 2bit
unsigned int c : 4; // 4bit
} A;
int main()
{
A a1;
a1.a = 1; // a에 1 저장 0000 0001
a1.b = 4; // b에 4 저장 0000 0100
a1.c = 15; // c에 15 저장 0000 1111
printf("%u %u %u", a1.a, a1.b, a1.c); // 각 멤버 출력
return 0;
}
위는 비트 단위로 멤버를 선언하고 멤버에 값을 넣은 후 각 멤버들을 출력해보는 코드다.
실행 결과를 보면 a, c는 정상적으로 저장한 값이 나오지만 b는 0이 나오는걸 볼 수 있는데, 이 이유는 b의 비트수는 2bit(00)인데 4를 넣으면 100 이렇게 bit를 초과하게 된다. 따라서 저장 비트 범위에 벗어나기 때문에 바뀌는게 없어 0을 출력하는 것이다.
위에서 구조체를 선언한 것을 보면 unsigned int로 선언한 것을 볼 수 있는데, 이 unsigned int로 선언하면 비트 필드의 최대 크기가 이 unsigned int 자료형의 크기가 된다. 따라서 unsinged int보다 큰 값은 저장할 수 없다.
위 사진처럼 자료형의 비트 아래 각 멤버들의 비트 수들이 최하위 비트(가장 작은 값)부터 차례대로 배치된다.
#include <stdio.h>
typedef struct a
{
unsigned int a : 1;
unsigned int b : 2;
unsigned int c : 4;
} A;
int main()
{
printf("%d", sizeof(A)); // a 구조체의 크기 출력
return 0;
}
위 코드는 sizeof 함수로 a 구조체의 크기를 구해서 출력한다.
자료형(unsigned int)의 크기인 4가 출력되는 것을 볼 수 있다. 만약 unsigned short로 선언한다면 unsigned short의 크기인 2byte가 구조체의 크기가 될 것이다.
#include <stdio.h>
typedef struct a
{
union
{
struct
{
unsigned int a : 1;
unsigned int b : 2;
unsigned int c : 4;
};
unsigned int d;
};
} A;
// 익명 공용체 선언 및 비트 필드 생성
int main()
{
A a = { 0, };
a.a = 1; // 0000 0001
a.b = 2; // 0000 0010
a.c = 15; // 0000 1111
// 값 할당
printf("%u", a.d); // 1111 10 1
// d 멤버의 값 출력
return 0;
}
마찬가지로 공용체에서도 역시 비트 필드를 사용할 수 있다. 위 코드는 a, b, c를 1, 2, 4 bit 크기로 선언하고 d와 공간을 나눠쓰도록 했는데 이 a, b, c에 각각 값을 넣어주고 d 멤버의 값을 출력하게 작성했다.
출력해보면 125가 나오는데, 이 이유는 d는 a,b,c와 공간을 공유하고 있기 때문에(공용체) d의 값은 a, b, c의 bit를 총 합친 값으로 되기 때문이다. 자세하게 설명하면 작은 값부터 공간을 뒤에서 차지하기 때문에 a 멤버는 1이므로 1(0000 0001), b는 2이므로 10(0000 0010), c는 15이므로 1111(0000 1111) 이 bit를 모두 합치면 1111 10 1이 된다.
이 1111 10 1은 10진수로 125이므로 이 값이 d에 저장돼 있는 것이다. 따라서 d를 출력하면 125가 출력된다.
Unit 57 열거형 사용하기
-열거형-
열거형은 정수형 상수에 이름을 붙여서 코드를 이해하기 쉽게 해준다.
사용은
enum <열거형 명>
{
<값1> = <초기 값>,
<값2>,
.....
};
로 사용한다.
또한 열거형 역시 구조체와 마찬가지로 정의만 해서는 사용할 수 없기 때문에 enum <열거형 명> <변수>;로 사용해야한다.
#include <stdio.h>
enum mouse // 열거형 정의
{
left = 0,
middle,
right
};
int main()
{
enum mouse m1; // 열거형 변수 선언
m1 = left; // 열거형 변수에 값 저장
printf("%d", m1); // 열거형 변수의 값 출력
}
위는 열거형으로 간단하게 마우스를 정의해본 코드다. 먼저 맨 처음 값인 left에 초기 값 0을 할당했는데, 이렇게 하면 middle은 1, right는 2로 자동으로 값이 정의된다. 이처럼 열거형은 맨 처음 값만 할당해주면 나머지 값들은 1 씩 증가된 값으로 자동 저장된다.
main 코드는 열거형 변수 선언을 하고 해당 변수에 left를 넣은 후 해당 변수의 값을 출력해준다.
실행 결과를 보니 left의 값인 0이 출력되는 것을 볼 수 있다.
이 열거형은 그냥 상수를 좀더 가독성 있게 해주는 문법이라고 이해하면 될 것 같다.
enum mouse // 열거형 정의
{
left = 0,
middle = 4,
right = 5
};
위처럼 각 열거형 값에 0, 4, 5등의 값을 임의로 넣어줄 수는 있지만 솔직히 열거형 쓰면서 값을 임의로 넣어주는 경우는 못본 것 같다.(그냥 1씩 증가하는데로 쓰는게 좋고 편하다.)
typedef enum mouse // 열거형 정의
{
left = 0,
middle = 4,
right = 5
} Mo; // 열거형 별칭
typedef enum
{
left = 0,
middle = 4,
right = 5
} Mo; // 열거형 별칭 정의
열거형 역시 구조체처럼 typedef로 별칭을 만들거나 익명 구조체로도 선언할 수 있다.
enum mouse
{
left = 0,
middle = 4,
right = 5
} Mo; // 열거형 변수 선언
위처럼 열거형 정의와 동시에 열거형 변수를 선언할 수 있다.
-열거형 X switch
#include <stdio.h>
enum mouse
{
left = 0,
middle,
right
};
int main()
{
enum mouse m1;
m1 = left;
switch (m1)
{
case left:
printf("왼쪽 버튼 클릭");
break;
case middle:
printf("가운데 버튼 클릭");
break;
case right:
printf("오른쪽 버튼 클릭");
break;
default:
break;
} // 열거형 변수의 값을 기준으로 분기
}
위 코드처럼 열거형은 switch문에서 유용하게 사용할 수 있다. 위는 열거형 값을 이용한 분기로 간단하게 마우스 버튼 클릭 이벤트를 구현해본 모습이다.
당연히 열거형 변수 m1은 left 값(0)을 가지므로 "왼쪽 버튼 클릭"이 출력되는 것을 볼 수 있다.
-열거형 X for
#include <stdio.h>
enum mouse
{
a = 0,
b,
c,
d,
e
};
int main()
{
for (enum mouse m = a; m < e+1; m++) // 열거형 값 a부터 e까지
{
printf("%d ", m); // 해당 값 출력
}
}
위는 열거형을 이용해 for문으로 반복을 하는 코드다. for문의 초기 값으로 a(0)을 할당하고 e+1(4)까지 반복하면서 해당 열거형 값을 출력해주는 역할을 한다.
위 결과처럼 a~e까지 값을 반복하며 출력해주는 것을 볼 수 있다.
Unit 56 ~ Unit 57 문제
비트 필드를 만드는 방법은 <정수형 자료형> <멤버 명> : <비트 수>로 하면 된다. 주의할 점은 비트 수가 자료형의 비트 수를 넘으면 안된다.
답 : d
비트 필드로 구조체를 만들면 그 구조체의 크기는 비트 필드를 만들 때 사용한 자료형의 크기가 된다. 위의 경우 unsigned int를 사용했으므로 크기가 4이다.
답 : 4
위는 익명 구조체, 공용체가 합쳐진 구조체다. 이 때 a, b에 3 7을 할당했을 경우 같은 공간을 공유하는 c의 값을 구하는 것이 문제인데, a는 11(0000 0011) b는 111(0000 0111)이므로 c는 1111 -> 0001 1111가 된다.
답 : e
3 1 63이 출력되게 만드는 것이 목적이다. 각 멤버에 저장될 비트 수를 조정해 원하는 값만큼만 저장하면 될 것 같다.
#include <stdio.h>
struct Flags {
unsigned int a : 2; // 11만 저장 = 3
unsigned int b : 1; // 1만 저장 = 1
unsigned int c : 6; // 0011 1111만 저장 = 63
};
int main()
{
struct Flags f1;
f1.a = 0xffffffff;
f1.b = 0xffffffff;
f1.c = 0xffffffff;
printf("%u %u %u\n", f1.a, f1.b, f1.c);
return 0;
}
공용체의 특징을 이용해서 e와 공간을 공유하고 멤버의 값을 설정해 e의 값을 32936으로 만드는 것이 목적이다. 이미 멤버들의 값이 설정돼 있으니 a,b,c,d 멤버를 short형으로 선언해주면 될 것 같다.
#include <stdio.h>
struct Flags {
union {
struct {
unsigned short a : 4; // 4bit
unsigned short b : 2; // 2bit
unsigned short c : 2; // 2bit
unsigned short d : 8; // 8bit
};
unsigned short e;
};
};
int main()
{
struct Flags f1 = { 0, };
f1.a = 8;
f1.b = 2;
f1.c = 2;
f1.d = 128;
printf("%u\n", f1.e);
return 0;
}
15, 127, 7이 출력되게 하는 것이 목적인데 보면 a, b, c의 값이 주어져 있다. 저 값들로는 15, 127, 7을 출력할 수 없으므로 비트 필드로 구조체를 생성해 15, 127, 7이 각 멤버에 들어가도록 비트 크기를 조절하면 될 것 같다.
#include <stdio.h>
struct Flags
{
unsigned int a : 4; // 4bit
unsigned int b : 7; // 7bit
unsigned int c : 3; // 3bit
};
int main()
{
struct Flags f1;
f1.a = 0xffffffff;
f1.b = 0xffffffff;
f1.c = 0xffffffff;
printf("%u %u %u\n", f1.a, f1.b, f1.c);
return 0;
}
a는 15(0000 1111)이 나오도록 4bit, b는 127(0111 1111)이 나오도록 7bit, c는 7(0000 0111)이 나오도록 3bit로 각각 unsigned 자료형 비트 필드로 선언해서 풀었다.
공용체의 특성을 이용해 e의 값을 57412로 만드는 것이 목적이다. a, b, c, d의 공간을 e와 공유하도록 익명 구조체에 멤버를 비트 필드로 선언하면 될 것 같다.
#include <stdio.h>
struct Flags {
union {
struct {
unsigned short a : 3; // 3bit
unsigned short b : 4; // 4bit
unsigned short c : 7; // 7bit
unsigned short d : 2; // 2bit
};
unsigned short e;
};
};
int main()
{
struct Flags f1 = { 0, };
f1.a = 4;
f1.b = 8;
f1.c = 64;
f1.d = 3;
printf("%u\n", f1.e);
return 0;
}
각 멤버에 들어갈 값에 맞는 bit를 넣어서 멤버들을 만들었다.
열거형을 정의할 때 사용하는 키워드는 enum이다.
답 : d
열거형의 값들은 초기 값을 기준으로 1씩 증가하므로 TYPE_CINEMA의 정수 값은 4가 된다.
답 : 4
열거형에서 switch 분기문의 case로 사용할 수 있는 것은 열거형 값이나 정수형 값이다.
답 : e(열거형 안에 정의되어 있지 않는 값이다.)
FORMAT_BMP ~ FORMAT_COUNT까지 반복하는 코드를 for문으로 작성하는 것이므로 for(FORMAT i = FORMAT_BMP; i < FORMAT_COUNT; i++)로 작성하면 될 것 같다.(여기서 FORMAT_COUNT는 열거형 값 개수를 구하기 위해 작성한 값이므로 <=로 포함하지 않는다.)
답 : c
3이 출력되게 하는 것이 목적인데, 이 출력문에서 출력되는 열거형 값은 바로 DEVICE_IEEE1394다. 열거형 값의 정수 값은 초기 값부터 1씩 증가하므로 초기 값에 2를 넣어주면 DEVICE_IEEE1394의 정수형 값은 3이 될 것이다.
#include <stdio.h>
enum DEVICE_TYPE {
DEVICE_PCI_EX = 3, // 초기 값을 3으로 설정
DEVICE_IEEE1394,
DEVICE_USB
};
int main()
{
enum DEVICE_TYPE type;
type = DEVICE_IEEE1394;
printf("%d\n", type);
return 0;
}
정의돼 있는 열거형과 열거형 변수를 바탕으로 switch문을 작성해 구르기를 출력하는 것이 목적이다. 열거형 변수에는 Tumble이 들어가 있으므로 switch의 맨 첫 case가 작동되도록 Tumble을 넣어주면 될 것 같다.
#include <stdio.h>
enum VayneSkill {
Tumble = 1, // 구르기
SilverBolts, // 은화살
Condemn, // 선고
FinalHour // 결전의 시간
};
int main()
{
enum VayneSkill skill;
skill = Tumble;
switch
{
case Tumble:
printf("구르기\n");
break;
case SilverBolts:
printf("은화살\n");
break;
case Condemn:
printf("선고\n");
break;
case FinalHour:
printf("결전의 시간\n");
break;
default:
break;
} // 열거형에 작성된 주석대로 switch문을 완성
return 0;
}
이번에는 for문으로 열거형 값들의 정수형 값을 1~12까지 출력하는 것이 목적이다.
#include <stdio.h>
typedef enum _Month {
Jan = 1,
a,
b,
c,
d,
e,
f,
g,
h,
i,
j,
k,
MonthCount
} Month; // 13개의 열거형 값 정의
int main()
{
for (Month i = Jan; i < MonthCount; i++)
{
printf("%d ", i);
}
return 0;
}
월 이름으로 모두 정의하기에는 너무 많아서 Jan, MonthCount만 정의하고 나머지는 더미로 a~k를 작성했다.
6, 5, 4가 출력되도록 열거형을 정의하는 것이 목적이다.
#include <stdio.h>
enum PROTOCOL_TYPE
{
PROTOCOL_IP = 4,
PROTOCOL_UDP,
PROTOCOL_TCP
}; // 열거형 정의(역순)
int main()
{
enum PROTOCOL_TYPE p1, p2, p3;
p1 = PROTOCOL_TCP;
p2 = PROTOCOL_UDP;
p3 = PROTOCOL_IP;
printf("%d %d %d\n", p1, p2, p3);
return 0;
}
PROTOCOL_IP, _UDP, _TCP 열거형 값 정의, 각 정수형 값이 4, 5, 6이 들어가도록 정의했다.
명상이 출력되도록 하는 것이 목적인데, switch, enum이 모두 선언돼 있기 때문에 main 코드에 열거형 변수 선언 및 값만 할당하면 끝나는 문제다.
#include <stdio.h>
enum MasterYiSkill {
AlphaStrike = 1,
Meditation,
WujuStyle,
Highlander
};
int main()
{
enum MasterYiSkill skill; // 열거형 변수 선언
skill = Meditation; // 열거형 변수에 Meditation 할당
switch (skill)
{
case AlphaStrike:
printf("일격 필살\n");
break;
case Meditation:
printf("명상\n");
break;
case WujuStyle:
printf("우주류 검술\n");
break;
case Highlander:
printf("최후의 전사\n");
break;
default:
break;
}
return 0;
}
열거형 변수를 선언하고 해당 변수에 "명상"이 출력되도록 Meditation을 할당해줘서 풀었다.
요약하자면 for문으로 정의된 열거형의 값들을 0부터 15까지 쭉 출력하는 것이 목적이다.
#include <stdio.h>
// INTERFACE_TYPE은 Windows 커널의 winddk.h 헤더 파일에 정의된 열거형
typedef enum _INTERFACE_TYPE {
InterfaceTypeUndefined = -1,
Internal,
Isa,
Eisa,
MicroChannel,
TurboChannel,
PCIBus,
VMEBus,
NuBus,
PCMCIABus,
CBus,
MPIBus,
MPSABus,
ProcessorInternal,
InternalPowerBus,
PNPISABus,
PNPBus,
MaximumInterfaceType
} INTERFACE_TYPE, *PINTERFACE_TYPE;
int main()
{
for(INTERFACE_TYPE i = Internal; i < MaximumInterfaceType; i++)
{ // Internal(0) ~ PNPBus(15)까지 출력
printf("%d ", i);
}
return 0;
}
초기 값이 -1이기 때문에 그 다음 값인 Internal을 for문 i의 초기 값으로 설정했고 조건을 i < MaximumInterfaceType로 작성해 PNPBus까지 출력하도록 했다.
'Old (2021.01 ~ 2021.12) > Programming' 카테고리의 다른 글
[PHP] php의 기본적인 문법 (0) | 2021.09.21 |
---|---|
c언어 코딩도장 Unit 58 ~ Unit 59 (0) | 2021.04.11 |
c언어 코딩도장 Unit 54 ~ Unit 55 (0) | 2021.03.27 |
c언어 코딩도장 Unit 51 ~ Unit 53 (0) | 2021.03.27 |
c언어 코딩도장 Unit 48 ~ Unit 50 (0) | 2021.03.13 |