Team Curio

비주얼 노벨 한국어 패치 팀 큐리오

프로그래밍

14.c 언어강좌 (11)

연이v 2009. 7. 10. 20:46
반응형
SMALL

=============================================================================
C 프로그래밍 11회
=============================================================================

이번 강좌 에서는 공용체와 열거형 상수 그리고 타입 만들기, 선행처리기 지시어를 배워보겠습니다.

1. 공용체
공용체란 한개 이상의 변수가 기억장소를 공유하고 있는 구조라고 생각하시면 됨니다.
공용체는 구조체와 완전히 똑같습니다.
단 그 안의 모든 멤버 변수들이 기억장소를 공유하고 있다는 점이 다르죠.
즉 모든 멤버 변수들의 주소가 같습니다.
그러므로 어떤 멤버 변수의 내용이 바뀌면 다른 모든 멤버 변수의 내용도 바뀌게 됨니다.
공용체의 선언부터 사용까지도 모두 구조체와 같다고 보시면 되는데
단 구조체는 struct라는 키워드를 썼지만 공용체는 union이라는 키워드를 쓰고 있죠.
그러므로 특별히 선언, 사용방법 등에 대해서는 설명 드리지 않겠습니다.
10회에 나왔던 구조체의 설명만 잘 읽으셨고 그것을 잘 이해하셨다면 구지 설명이 필요 없다고 봅니다.
그럼 몇가지 예를 들어 보고 공용체에 대해선 마치도록 하죠.

두 정수 변수 a와 b를 멤버 변수로 가지고 있는 Data라는 이름의 공용체는 다음과 같이 만들면 되겠죠?
union Data { int a; int b; };
구조체와 똑같지만 단지 union이라는 키워드를 쓴 것 뿐입니다.
그럼 사용할땐 어떻게 할까요? 구조체에선 구조체 변수라는 것을 선언해 사용했는데,
이와 마찬가지로 공용체에선 공용체 변수라는 것을 선언해 사용하면 됨니다.
예를 들어 d라는 이름을 가진 위의 Data라는 공용체의 변수는
union Data d;
이렇게 선언하겠죠? 그리고 멤버 변수인 a를 10으로 바꾼다고 하면 구조체와 같은 방법으로
d.a=10;
이렇게 해 주면 됨니다. 그런데 여기서 중요한 것이 있는데, 지금 멤버 변수인 a에 10을 넣었습니다.
그렇다면 또다른 멤버변수 b에는 어떤 값이 들어갈까요? b에도 역시 10이 들어가겠죠?
이게 구조체라면 b라는 멤버변수에는 아무 변화가 없겠지만 공용체이기 때문에 a와 b는 기억장소를
공유하고 있으므로 그렇게 되는 것이죠.
구조체처럼 공용체에도 공용체 배열과 공용체 포인터가 있는데 이건 생략해도 상관 없을것 같군요.
어차피 struct라는 키워드 데신 union이라는 키워드를 쓴다는 것 빼고는 구조체와 선언및 사용법 등이
똑같으니까요.
구조체를 잘 공부하셨다면 그리 어렵지 않으셨을 걸로 알고 이정도로 공용체 설명은 마치겠습니다.

2. 열거형 상수
열거형 상수란 정수형 상수의 일종으로 동일한 용도로 쓰이는 상수들에게 그들을 대신할수 있는
이름을 부여하여 열거해 둔 것입니다.
 열거형 상수를 만드는 방법은 다음과 같습니다.
enum [열거명] { 상수명 [= 상수값], ... } [변수, 변수, ..];
여기서 열거명 열거해둔 상수가 어떤 상수들인지 그 상수들 전체에 대한 이름입니다.
그리고 상수명은 상수를 대신할 이름, 상수값은 그 상수명에대한 실재 값, 마지막으로 변수는
일반 변수를 선언한 것으로서 정수형(int) 변수입니다.
여기서 상수값은 생략 가능한데 생략하면 그 전에 있는 상수의 다음 값으로 지정됨니다.
예를 들어 전에 값이 100이면 그 다음 값인 101이 되죠.
그런데 그 전에 있는 상수가 없을때 즉 처음일때는 0이 됨니다.
그리고 열거명과 변수들도 생략해도 됨니다.
그럼 예를 들어 다음과 같은 열거형 상수가 있다고 합시다.
enum NUMBER { ZERO, FIRST, SECOND, THIRD, FORHT, FIFTH };
이렇게 열거형 상수를 만들고 나면 프로그램 내에서 0대신 ZERO를 1대신 FIRST를....
이렇게 사용할수 있습니다.
그리고 열거형 상수를 만들때 열거명은 생략 가능하므로
enum { ZERO, FIRST, SECOND, THIRD, FORHT, FIFTH };
이렇게만 해도 됨니다.
또한 위와 같은 열거형 상수를 만들면서 변수 a, b를 선언하려면
enum NUMBER { ZERO, FIRST, SECOND, THIRD, FORHT, FIFTH } a, b;
이렇게 하면 됨니다.
이때 선언된 a, b는 정수형(int) 변수입니다.
그러므로
enum NUMBER { ZERO, FIRST, SECOND, THIRD, FORHT, FIFTH }; int a, b;
이렇게 하는 것과 똑같은 것이죠.
마지막으로 어떤 프로그램에는
enum 열거명 변수명[, 변수명, ...];
이렇게 선언된 변수가 있습니다. 이것은 일반 정수형(int) 변수와 완전히 똑같습니다.
그러니까 위와나온 NUMBER라는 열거형 상수가 만들어져 있을때
enum NUMBER a, b, c;
이렇게 한 것은
int a, b, c;
이것과 똑같은 의미 입니다.

3. 타입 만들기
C언어에는 여러가지 데이터 타입 키워드 들이 있습니다.
int, char, float, double등이 있죠? 이런건 그냥 쓰기에 불편한 점이 없습니다.
하지만 unsigned short int형태의 데이터를 많이 써야 한다고 합시다.
그럴때는 너무 길어서 쓰기가 지겨워 지죠.
이걸 간단히 쓰는 방법이 있는데 방법은 unsigned short int와 똑같은 형태의 데이터 타입을
새롭게 만들어 주는 것이죠.
이렇게 새로운 데이터 타입을 만들때 쓰는 것이 typedef입니다.
그럼 사용 방법을 알아보죠. 사용은 다음과 같이 합니다.
typedef 기존타입 새로운타입;
예를 들어 unsigned short int와 똑같은 형태의 word라는 데이터 형태를 만들려면
typedef unsigned short int word;
이렇게 해 주면 됨니다.
그러면 프로그램 내에서
unsigned short int a;
이거 대신
word a;
이렇게만 해 주어도 됨니다.
그리고 typedef로는 구조체를 데이터 타입으로 만들어 줄 수가 있습니다.
저번에 구조체를 설명할때 구조체는 데이터 타입을 새롭게 만드는 것이라고 생각하시면 된다고 했는데 그것이 진짜로 새로운 데이터 타입을 만든것은 아닙니다.
하지만 typedef를 쓰면 진짜로 새로운 데이터 타입을 만들수 있게 되는 것이죠.
예를 들어 Student라는 구조체가 있다고 합시다.
그때
typedef struct Student StudentType;
이렇게 해 주면 Student라는 구조체를 StudentType라는 이름의 데이터 타입으로 만들어 준 것입니다.
그러면 프로그램에서
struct Student s;
이렇게 할 것을 단지
StduentType s;
이렇게만 해 주면 됨니다. 공용체 역시 구조체와 마찬가지로 데이터 타입을 만들수 있습니다.

4. 선행처리기 지시어
선행처리기에 대해서는 1회때 배운적이 있고
선행처리기 지시어중 #include에 대해서 2회때 이미 배우셨습니다.
하지만 지시어에는 이것 외에도 몇가지가 더 있습니다. 그럼 그것들에 대해서 알아보죠.

(1) #define
#define라는 지시어는 매크로 기능을 수행하는 지시어 입니다.
기본적인 사용법은 다음과 같습니다.
#define 매크로명 [값]
이렇게 해 두면 프로그램 내에서 매크로명과 같은 이름을 가진 단어들을 모두 값으로 바꿔 줌니다.
그리고 여기서 값은 없어도 되죠.
예를 들어
#define DATA 10
이렇게 해 주면 프로그램 내에 DATA라는 단어를 모두 10으로 바꿔 주게 됨니다.
즉 프로그램에서
if(a==DATA) { . . }
이렇게 쓴 것은 실재로는
if(a==10) { . . }
이렇게 되어 버리는 것 입니다.
#define라는 지시어로는 함수와 같은 매크로도 만들수 있습니다.
만드는 방법은 다음과 같죠.
#define 매크로함수명([인수, 인수, ...]) [문장]
이때 인수는 일반 함수의 인수와 똑같은 용도로 쓰입니다.
즉 값을 전달에 주는 역활을 하죠.
물론 없어도 상관 없고요.
그리고 문장은 매크로의 내용으로 인수들을 쓸수 있죠.
그럼 예를 들어 보죠.
#define FUNC(a,b) printf(a,b);
이렇게 매크로를 만들었다고 합시다.
그리고 프로그램 내에서 이 매크로를
FUNC("%d",10);
이렇게 사용했다면 이건 선행처리기가 지시어를 번역한 후에는
printf("%d",10);
이렇게 되어 버리는 것 입니다.
이정도면 이해가 되셨겠죠?

(2) ##와 \
매크로를 만들때만 사용할수 있는 몇가지 지시어가 있는데, 바로 ##와 \입니다.
##는 함수와 같은 매크로에서만 사용하는 것으로 두가지 인수를 연결시켜 버리는 기능을 합니다.
예를 들어
#define MACRO(a,b) a##b
이렇게 매크로를 만들었다고 합시다.
프로그램에서 이 매크로를
a=MACRO(First,Last);
이렇게 사용했다면 실재로는 두 인수 First와 Last가 연결되어
a=FirstLast;
이렇게 되는 것 입니다.
\는 매크로의 내용이 너무 길때 여러줄에 쓰기 위해 필요한 것입니다.
줄 맨 끝에 \를 붙여 주면 그 아랫줄에 계속 연결하여 쓸수 있게 되는 것이죠.
예를 들어
#define MACRO(a,b,c) a=b+c;
printf("%d\n",a);
a=b-c;
printf("%d\n",a)
이런 매크로가 있다고 합시다.
이건 \를 써서 다음과 같이 쓰면 보기도 쉽고 만들기도 쉽죠.
#define MACRO(a,b,c) a=b+c;
\ printf("%d\n",a);
\ a=b-c;
\ printf("%d\n",a)

(3) #undef
#define로 만든 매크로를 없엘때는 어떻게 할까요?
그때 #undef라는 지시어를 사용합니다. 사용법은 다음과 같죠.
#undef 매크로명
여기서 매크로명은 없에려고 하는 매크로의 이름으로 이미 만들어 져 있는 것이어야 합니다.
이렇게 해 주면 해당 매크로는 없어져서 더이상 사용할수 없게 됨니다.

(4) #if-#elif-#else-#endif
#if-#elif-#else-#endif는 선택적 매크로 선언이나 선택적 컴파일 기능을 하는 매크로 입니다.
C언어 프로그램 흐름제어중 if문과 비슷하죠. 사용법은 다음과 같습니다.
#if 조건A /* A부분 */
. .
#elif 조건B /* B부분 */
. . . .
#else /* else부분 */
. .
#endif
여기서 조건A가 만족하면 A부분만을 조건B가 만족하면 B부분만을...
그리고 어떤 조건에도 만족하지 않으면 else부분만을 컴파일 해 주게 됨니다.
그리고 #elif부분과 #else부분은 없어도 됨니다.
조건은 일반 C언어의 관계형 연산자와 논리 연산자 그리고 defined라는 것을 사용한 조건이지만
변수같은건 사용될 수 없고 매크로를 사용할수 있습니다.
예를 들어
DATA1 == DATA2
이런 조건은 DATA1이란 매크로와 DATA2라는 매크로의 값은 같다 라는 조건 입니다.
그리고 defined는 특정 매크로가 만들어져 있으면
참을 그렇지 않으면 거짓을 돌려 주는 기능을 하는데, 사용법은 다음과 같습니다.
defined(매크로명)
이때 매크로명에 해당하는 매크로가 만들어져 있으면 참을 그렇지 않으면 거짓을 돌려주죠.
그럼 한가지 예를 들어 보죠.
#define MACRO 10
#if !defined(MACRO) printf("MACRO not found\n");
#elif MACRO == 0 printf("MACRO = 0\n");
#elif MACRO == 5 printf("MACRO = 5\n");
#elif MACRO == 10 printf("MACRO = 10\n");
#else printf("MACRO = Another value\n");
#endif
다음과 같은 내용이 있을때 실재로 컴파일 되는 것은 어떤 문장 일까요?
당연히
printf("MACRO = 10\n");
이 문장 이겠죠.
잘 분석해 보시면 왜 그런지는 아시게 되실 겁니다.

(5) #ifdef-#else-#endif
#ifdef-#else-#endif는 #if-#elif-#else-#endif와 비슷하지만 다른 조건들을 줄수 없고
단지 어떤 매크로가 만들어져 있을겨우 특정 부분을 컴파일 시켜 주는 기능을 합니다.
사용은 다음과 같이 합니다.
#ifdef 매크로명 /* A부분 */
. .
#else /* B부분 */
. .
#endif
여기서 매크로명에 해당하는 매크로가 만들어져 있을경우
A부분을 그렇지 않으면 B부분을 컴파일 합니다.
그리고 #else부분은 없어도 됨니다.

(6) #ifndef-#else-#endif
#ifndef-#else-#endif는 위에 #ifdef-#else-#endif와 거의 똑같습니다.
하지만 위에것에선 어떤 매크로가 만들어져 있을때 특정 부분을 컴파일 시키는 것이지만,
이건 특정 매크로가 만즐어 져 있지 않을때 특정 부분을 컴파일 시켜 주는 것 입니다.
사용은
#ifndef 매크로명 /* A부분 */
. .
#else /* B부분 */
. .
#endif
이렇게 합니다.
여기서 매크로명에 해당하는 매크로가 만들어져 있지 않으면 A부분을
그렇지 않고 만들어져 있으면 B부분을 컴파일 해 주고 #else부분을 없어도 됨니다.

(7) #error
#error라는 지시어는 에러를 발생시켜 컴파일을 중지 시키는 지시어 입니다.
지금은 별로 쓸 일이 없지만 언젠간 꼭 쓸 일이 있을 겁니다.
사용은 다음과 같이 합니다.
#error 에러내용
여기서 쓴 에러내용이 컴파일 할때 표시가 되며, 컴파일이 중지 됨니다.
이것으로 11회에 걸친 C 프로그래밍 강좌를 모두 마치겠습니다.
지금까지 C언어 문법에 중점을 두어 설명을 해 드렸는데,
C언어를 활용하기에는 문법만 잘 알고 있는 것으로는 부족합니다.
반응형

'프로그래밍' 카테고리의 다른 글

16.DirectX 개론  (0) 2009.07.10
15.c 언어강좌 (12)  (0) 2009.07.10
13.c 언어강좌 (10)  (0) 2009.07.10
12.c 언어강좌 (9)  (0) 2009.07.10
11.c 언어강좌 (8)  (0) 2009.07.09