6.1 조건문
조건문은 주어진 조건에 맞는 실행을 선택하는 역활을 합니다. C에는 if와 switch가 있습니다.

1) if / else if / else

if는 대부분의 언어에 비슷하게 존재하는 대표적인 조건문으로 아래와 같은 문법으로 사용합니다.

if([조건]) { [코드] }

if문 다음의 괄호 안의 [조건]이 0이 아니면 다음에 나오는 [코드]를 실행하고, 0이면 실행하지 않습니다. 일단 사용 예 부터 보겠습니다.

int a = 2;
if(a < 3)
{
    printf("TRUE");
}

위의 코드는 (a < 3)이 참(1)이므로 {}내의 내용이 실행되어 printf를 출력합니다. 만약 변수 a를 int a = 4;와 같이 변경하면 거짓(0)이 되므로 printf의 내용을 출력하지 않습니다.

if 다음 실행해야 될 코드가 한줄일 경우에는 아래와 같이 {}를 생략할 수 있습니다. 이는 나중에 나올 for, while문 등도 마찬가지 입니다.

if(a < 3)
    printf("TRUE");

if는 else if, else와 더불어 여러 조건들을 검사 할 수 있습니다. else if는 if의 조건 다음에 나오는 조건들을 검사합니다. else 는 if나 else if의 마지막에 위치하면 위의 조건들이 모두 일치하지 않을 때만 실행됩니다.

if와 else는 한 if문에서 하나씩만 올 수 있지만, else if는 여러개가 올 수 있습니다. 사용예는 아래와 같습니다.

int a = 2;
if(a < 3)
    printf("one");
else if(a < 6)
    printf("two");
else
    printf("three");
   
첫번째 if문은 a가 3보다 작을 경우 실행되고, 위와 같이 a가 2일 경우에는 "one"을 출력하고 그 다음에 오는 else if, else의 코드들은 실행되지 않습니다.

만약 a가 4로  첫번째 if문의 조건이 거짓(0)이되면, 그 다음의 else if문에서 다음 조건을 검사합니다. a가 4면 6보다 작으므로 "two"를 출력하고, 뒤의 else문은 실행이 되지 않습니다.

마지막 else의 경우는 위의 if, else if의 두 조건인 a가 3보다 작지 않고 6보다 작지 않은 조건에 걸리지 않는다면 "three"를 출력합니다.

>> 조건 연산자
간단하게 한가지 조건을 검사하고 변수에 값을 저장 할 때는 이전 연산자에서 잠시 본 조건 연산자를 사용할 수 있습니다. 조건 연산자는 아래와 같이 사용합니다.

[조건] ? [A] : [B];

위의 조건은 if문 괄호내의 조건과 동일합니다. [조건]이 참(1)일 경우 [A]의 값을 반환하고, 거짓(0)일 경우 에는 [B]의 값을 반환합니다. 아래는 사용 예 입니다.

int a = 2;
int b;
b = (a < 3) ? 100 : 200;

a = 2이므로 (a < 3)는 참(1)입니다. 참이므로 첫번째 숫자인 100을 반환합니다. 이를  if문을 사용하는 동일한 코드를 작성하면 아래와 같습니다.

if(a < 3)
    b = 100;
else
    b = 200;


2) switch

if문과 더불어 많이 사용하는 조건문이 switch문 입니다. 한 변수(int, char)에 대하여 많은 조건을 검사해야 할 경우에는 switch문이 가독성이 좋을 수도 있습니다. switch문은 아래와 같이 사용할 수 있습니다.

switch([조건])
{
    case [값] :
        [code];
        break;
    case [값] :
        [code];
        break;
    default :
        [code];
        break;
}

switch  괄호내에 있는 [조건]의 값이 각각의 case의 값과 일치할 경우에는 해당 case 문내의 [code]가 실행 됩니다. case 문 내의 코드가 끝나는 곳에는 break;가 있어야 다음 case 문으로 실행이 되지 않습니다.

default는 생략이 가능하며 if문의 else와 마찬가지로 위의 모든 case 조건에 해당 사항이 없을 때, default내의 [code]가 실행됩니다. 아래는 사용 예입니다.

int a = 2;

switch(a)
{
    case 1:
        printf("1\n");
        break;
    case 2:
        printf("2\n");
        break;
    case 3:
        printf("3\n");
        break;
    default:
        printf("not 1 or 2 or 3");
        break;
}    

위에서 변수 a의 값을 1, 2, 3, 그 외 다른 수로 변경하면서 컴파일/실행해 보시면 switch문을 이해하실 수 있습니다. a의 값을 1부터 차례대로 증가시키면서 변경하면 1, 2, 3, not 1 or 2 or 3이 출력 됩니다.

만약 case 2의 break;를 삭제하면 2가 되더라도 다음 break;를 만나는 case 3까지 실행됩니다. 코드는 아래와 같습니다.

switch(a)
{
    case 1:
        printf("1\n");
        break;
    case 2:
        printf("2\n");
    case 3:
        printf("2 or 3\n");
        break;
    default:
        printf("not 1 or 2 or 3");
        break;
}
   
위의 코드는 다른 부분은 위와 동일 하지만, a가 2일 경우에는 case 2에 break;가 없기 때문에 2를 출력하고 case 3까지 내려와 2 or 3을 출력한 후에 break;문을 만나 switch문을 나가게 됩니다.


6.2 반복문
어떤 작업에 대하여 일정한 반복이 필요할 경우에 사용되는 반복문입니다. C의 for와 while에 대하여 알아 보겠습니다.

1) for

for는 아래와 같이 사용합니다.

for([초기화]; [조건]; [변경])
{
    [코드]
}

[초기화] 부분은 for문이 반복되기 전에 한번만 실행되며, 이곳에서 for문의 반복 횟수를 나타내는 변수등을 초기화 합니다.

[조건]은 항상 반복전에 검사되며 참(1)일 경우에는 계속 진행되고, 거짓(0)일 경우에는 for문을 종료합니다.

[변경]은 [코드]가 실행 된 후에 실행되는 부분으로 일반적으로 반복 횟수를 나타내는 변수를 증감하여, for문이 원하는 [조건]에서 종료할 수 있도록 합니다.

사용예는 아래와 같습니다.

int i;
for(i = 0; i < 10; i++)
{
    printf("%d\n", i);
}

위의 for문이 10번 반복되면서 0~9까지 출력하는 소스입니다. 위의 소스는 아래와 같이 실행됩니다.
  1. 초기화 부분에서 i = 0로 저장됩니다.
  2. i < 10인지 검사하고, 참이면 코드 부분이 실행되고 거짓이면 for문이 종료됩니다.
  3. printf가 i를 출력합니다.
  4. i가 1 증가 됩니다.
위에서 2~4 부분은 4까지 오면 다시 2로 가서 계속 반복 됩니다. 이렇게 반복되면서 printf가 9를 출력하고 i가 10이 될 때에는  2에서 i < 10 조건이 거짓(0)이 되므로 for문이 종료됩니다.


2) while

while은 아래와 같이 사용됩니다.

while([조건])
{
    [코드]
}

[조건]이 참(1)일 동안은 [코드]가 계속 반복해서 실행됩니다. 위의 0부터 1까지 출력하는 for문을 while로 변경하면 다음과 같습니다.

int i = 0;
while(i < 10)
{
    printf("%d\n", i++);
}

for문도 마찬가지지만 while 사용시에는 특히 (i < 10)의 조건 부분이 원하는 만큼만 반복하고 나올 수 있도록 유의하여야 합니다. 위에 printf문의 i++가 같이 i가 증가되는 부분이 없으면, (i < 10)은 항상 참이 되므로, 프로그램이 무한이 반복되는 무한루프에 빠지지 됩니다.

while(1)
{
    printf("d");
}

위에 while문은 조건 부분이 항상 1이므로 무한히 반복되며 d를 출력합니다. 멈추기 위해서는 Ctrl+c등 강제적인 수단을 써야 합니다. for문은 아래와 같이 하면 무한루프가 됩니다.

for(;;)
{
    printf("d");
}


6.3 break, continue, goto

위의 for와 while 같은 반복문 내에서 또는 단독으로 사용되는 continue와 break, goto에 대해서 알아 보겠습니다.

1.break

break가 실행되면 무조건 그 반복문은 그 시점에서 종료됩니다. break는 반복문에서 특정한 조건을 만나면 반복을 중지해야 할 경우에 사용됩니다.

for(i = 0; i < 10; i++)
{
    if(i == 5)
        break;
    printf("%d\n", i);
}

이전 소스코드에서 위와 같이 break;문이 있으면 (i == 5)일 경우가 되면 if문 내의 break가 실행되면서 그 순간 for문은 종료됩니다. 소스를 위와 같이 수정하고 실행 시켜면 프로그램은 0~4까지만 출력하고 종료 됩니다.


2. continue

break가 무조건 반복을 종료한다면, continue는 continue 다음의 코드를 실행하지 않고 반복은 계속 됩니다. 아래의 소스를 보겠습니다.

for(i = 0; i < 10; i++)
{
    if(i == 5)
        continue;
    printf("%d\n", i);
}

(i == 5)일 경우에는 if문내의 continue가 실행되며, continue 아래의 모든 코드는 실행되지 않고 건너 뛰게 됩니다. 그런 후 i는 6으로 증가 되어 이 후로는 for문의 조건을 만족하는 동안 코드는 반복됩니다.

위의 코드는 프로그램을 실행시키면 5를 제외한 0, 1, 2, 3, 4, 6, 7, 8, 9를 출력합니다.


3. goto

goto문은 위의 break와 continue와는 다르게, 반복문 이외에도 자유롭게 사용할 수 있습니다. 아래는 goto문의 사용법입니다.

goto [LABEL];

[LABEL]:

실행 시 위의 goto를 만나게 되면, 무조건 해당 [LABEL]이 있는 곳으로 건너 뛰어, 그 이후로 부터 실행 됩니다. [LABEL] 의 선언은 C의 일반적인 선언과 틀리게 마지막에 ":"을 사용하는 것에 유의하셔야 합니다.
 
while(i < 10)
{
    if(i == 7)
        goto END;
    
    printf("%d\n", i++);
}

printf("while end");

END:

위의 소스는 i가 7이되면 중간의 모든 명령을 건너뛰고 해당 레벨인 END로 가게됩니다. 이런 무지막지성(?) 때문에 소스에 혼란을 줄 수 있고, 예측할 수 없는 상황을 야기할 수도 있기 때문에 대부분 goto를 사용하지 말것을 권합니다.

하지만 아주 간혹(정말 간혹 입니다.) goto는 쓸데없이 많은 조건문(if 등)을 생략할 수 있게 해주고, 오히려 더 의미를 명확하게 해줄 경우가 있습니다.

그렇지만 당분간은 없는 명령어로 생각하시는 것이 좋습니다.

'프로그래밍 강좌 > C 언어 기초' 카테고리의 다른 글

8. 포인터 (pointer)  (4) 2007.06.16
7. C 함수 (function)  (4) 2007.06.15
5. 연산자  (0) 2007.06.13
4. 변수  (2) 2007.06.12
3. C 기초문법  (0) 2007.06.05
AND

5. 연산자

C에서 연산자는 변수나 상수에 특정한 연산을 하는 C에서 예약된 기호들이며, 일반적으로 수학에서 많이 사용하는 기호와 연산이 유사합니다.

1) =

"="는 변수에 값을 대입할 때 사용하는 연산자 입니다. 일반적으로 사용하는 것과 반대 방향으로 우측에 있는 값을 좌측 변수에 대입 합니다. 상수 뿐만 아니라 아래와 같이 변수, 함수의 반환값, 포인터 등에도 사용할 수 있습니다.

int num1 = 3;
int num2 = GetNum(); /* GetNum은 함수로 후에 설명하겠습니다. */
int num3 = count + 1;
char* p = &n; /* *는 포인터를 나타내는 연산자로 후에 설명하겠습니다. */


2) +, -, *, /, %

실생활에서도 많이 사용하는 더하기(+), 빼기(-), 곱하기(*), 나누기(/), 나머지(%) 계산에 관한 연산자 들입니다.

연산자에는 우선순위가 있습니다. 일반적인 연산 순서는 좌에서 우로 갑니다. 하지만 () 연산이 최상위에 있고, *, /, % 연산이 +, - 보다 위에 있습니다.

그러므로 아래와 같은 코드가 있다면.

int num1 = 4+4/2;
int num2 = (4+4)/2;

num1에는 6, num2에는 4가 들어 갑니다.

이 연산자들은 또한 "="의 앞에 결합되어 사용할 수 있습니다. 의미는 아래와 같습니다.
int a = 1;

a += 3;        /* a = a + 3;  과 동일 */
a -= 3;        /* a = a - 3;  과 동일 */
a *= 3;        /* a = a * 3;  과 동일 */
a /= 3;        /* a = a / 3;  과 동일 */
a %= 3;        /* a = a % 3;  과 동일 */


3) ==, !=, <, <=, >, >=

위의 연산자들은 두 값의 사이에서 비교하는 연산자이며, 비교값이 참일 경우에는 1, 거짓일 경우에는 0이 됩니다.

  • "a == b" 는 a와 b가 같은지 비교합니다.
  • "a != b" 는 a와 b가 틀린지 비교합니다.
  • "a < b" 는 a가 b보다 작은지 비교합니다.
  • "a <= b" 는 a가 b보다 작거나 같은지 비교합니다.
  • "a > b" 는 a가 b보다 큰지 비교합니다.
  • "a >= b" 는 a가 b보다 크거나 같은지 비교합니다.

nt n1 = (3 == 4);
int n2 = (3 != 3);
int n3 = (3 > 1);
int n4 = (3 > 10);
int n5 = (3 <= 4);

여기서도 = 연산자가 비교 연산자(==, !- 등) 보다 연산순위가 낮기 때문에 괄호를 사용하지 않더라도 비교 연산이 먼저지만 보기 쉽게 하기위해 괄호를 하였습니다.

위에서 값들은 각각 n1는 0, n2는 0, n3는 1, n4는 0, n5는 1의 값을 같습니다.


4) ++, --

증감 연산자는 변수의 값을 1씩 더하거나 빼기를 합니다. 즉 a++은 a = a + 1; 과 같은 의미이며, b--는 b = b - 1; 와 같은 의미입니다. ++, -- 증감 연산자에서 중요한 점은 변수의 앞과 뒤에 위치할 수 있으면, 이것은 연산 순서의 변경을 가지고 옵니다.

++(or --)이 변수 앞에 오면 그 라인의 명령이 실행되기 전에 먼저 ++(or --)가 먼저 실행되고,  ++(or --)이 변수 뒤에 오면 그 라인의 명령이 실행된 후에 ++(or --)가 실행됩니다.

#include <stdio.h>

int main(int argc, char* argv[])
{
    int a = 2;
    int b1 = 4;
    int b2 = 4;

    int c1 = a + b1++;
    int c2 = a + ++b2;
   
    printf("%d, %d, %d, %d", c1, c2, b1, b2);

    return 0;
}

위의 소스를 컴파일 후 실행 하면 "6, 7, 5, 5"가 출력됩니다.

int c1 = a + b1++; 은
int c1 = a + b1;
b1 = b1 + 1;
과 동일하며,

int c2 = a + ++b2; 은
b2 = b2 + 1
int c2 = a + b2; 
와 동일합니다.

5) &&, ||, !

"A && B"는 AND 연산을 하며 A와 B 두개의 값이 모두 0이 아닐 경우, 1을 반환 하고 그 외에는 0을 반환합니다.

"A || B"는 OR 연산을 하며 A와 B 두개의 하나 이상이 0이 아닐 경우, 1을 반환 하고 그 외에는 0을 반환합니다.

"!A"는 A가 0이 아닐 경우에는 0, 0일 경우에는 1을 반환합니다. !A는 (A == 0)과 의미가 같습니다.

아래의 소스를 보면 위의 내용을 확인할 수 있습니다.
#include <stdio.h>

int main(int argc, char* argv[])
{
    printf("%d, ", 0 > 1 && 2 > 1);
    printf("%d, ", 0 > 1 || 2 > 1);
    printf("%d\n", !(0 > 1 && 2 > 1));

    return 0;
}

위의 소스를 컴파일 후, 실행하면 0, 1, 1로 출력 됩니다.

printf("%d, ", 0 > 1 && 2 > 1);
&&, ||은 연산자 우선 순위가 낮기 때문에 <, > 보다 늦게 실행됩니다. (0 > 1) && (2 > 1)과 같은 의미입니다. 우선 0 > 1은 거짓(0)이고 2 > 1은 참(1)이므로 위는 "0 && 1"과 의미가 같습니다. && 연산자는 양쪽 모두 0이 아닐때만, 1을 반환하므로 0이 됩니다.

printf("%d, ", 0 > 1 || 2 > 1);
위는 0 > 1은 거짓(0)이고 2 > 1은 참(1)이므로 위는 "0 || 1"과 의미가 같습니다. || 연산자는 하나 이상만 0이 아니면 1을 반환하므로 1이 됩니다.

printf("%d\n", !(0 > 1 && 2 > 1));
(0 > 1 && 2 > 1)는 위 첫번째와 같은 값이며 0입니다.  "!0" (0 == 0)이 되기 때문에 1을 반환합니다.
 

6) &, |, ^, ~, >>, <<

다음은 이전 변수 에서 잠시 살펴 본, 비트에 관한 연산자 들입니다. 이전에 말씀 드린 것과 같이 bit는 0과 1 두가지 경우를 나타낼 수 있는 컴퓨터에서 사용하는 최소 단위입니다.

1. and 연산자(&)
&는 비트 단위로 and 연산을 합니다. &는 양쪽이 다 같이 1일 경우에만 참(1)입니다. 1바이트 에서 &연산은 아래와 같습니다.

#include <stdio.h>

int main(int argc, char* argv[])
{
    unsigned char a = 153;
    unsigned char b = 83;
    unsigned char c;
   
    c = a & b;

    printf("%d", c);

    return 0;
}

1바이트형의 양수만 쓰는 unsigned char형으로 a, b, c를 위와 같이 선언 합니다. 참고로 153은 2진수로 10011001이고 83은 01010011이며 c = a & b 연산은 아래의 그림과 같이 처리 됩니다. (2진수 -> 10진수 변환은 이전 장에 언급되었습니다.)
사용자 삽입 이미지
a, b의 같은 번째의 bit를 비교해서 두개 모두 1일 경우에만, c의 같은 위치가 1이되며 나머지는 0이 됩니다. 위의 소스를 컴파일 하면 17이란 10진수가 나오는데 이는 2진수로 00010001로 위의 c와 같습니다.

2. or 연산자(|)
or 연산자 |는 두 bit를 비교하여 둘 중 어느 한쪽에 1이 있으면 1이 됩니다. 위의 소스 중에서 c = a & b; 부분을 c = a | b;로 변경하시고 컴파일 후 실행하면 확인할 수 있습니다.
사용자 삽입 이미지
실행 후 확인해 보면 10진수로 219가 출력되며, 이는 2진수 11011011로 위의 c와 동일합니다.

3. xor 연산자(^)
xor은 두 비트를 비교하여 서로 다른 값일 경우에만 1이 됩니다. or과 마찬가지로 위의 소스 에서 c = a & b; 부분을 c = a ^ b;로 변경하시고 컴파일 후 실행하면 확인할 수 있습니다.
사용자 삽입 이미지
실행 후 확인해 보면 10진수로 202가 출력되며, 이는 2진수 11001010으로 위의 c와 동일합니다.

4. not 연산자(~)
not은 위의 경우와는 달리 2개의 값에 대한 연산이 아니라, 1개의 값에 대한 연산을 하며, 1은 0으로 0은 1로 비트값을 반전시킵니다. 마찬가지로 위의 소스에서 c = a & b; 부분을 b = ~a;로 변경하시고 확인할 수 있습니다.
사용자 삽입 이미지
실행 후 확인해 보면 10진수로 202가 출력되며, 이는 2진수 01100110으로 위의 b와 동일합니다.

5. 우 쉬프트 연산자(>>)
우 쉬프트 연산은 숫자 만큼 bit를 우측으로 밀어 내고, 밀려 난 비트는 사라집니다. 좌측에 남은 비트는 0으로 채워집니다. 위의 소스에서 c = a & b; 부분을  c = a >> 3;로 변경하시고 확인할 수 있습니다.
사용자 삽입 이미지
위의 이미지를 보면 a를 오른쪽으로 3칸 밀고, 밀려난 좌측의 흑색 부분은 사라집니다.  그 후 비워진 앞부분(연두색)은 0으로 채워집니다.

실행 후 확인해 보면 10진수로 19가 출력되며, 이는 2진수 0001001로 위와 동일합니다.

5. 좌 쉬프트 연산자(>>)
좌 쉬프트 연산은 위의 우 쉬프트 연산과 방식이 동일하며 방향만 다릅니다. 위의 소스에서 c = a & b; 부분을  c = a << 3;로 변경하시고 확인할 수 있습니다.
사용자 삽입 이미지
위의 이미지를 보면 a를 왼쪽으로 3칸 밀고, 밀려난 우측의 흑색 부분은 사라집니다.  그 후 비워진 뒷부분(연두색)은 0으로 채워집니다.

실행 후 확인해 보면 10진수로 200이 출력되며, 이는 2진수 11001000로 위와 동일합니다.

7)  기타

그 외 이 전에 보았던 sizeof, 조건(a ? b:c), ',', '.', '->' 등이 있습니다.

이전장에서 보았던 sizeof는 변수 타입의 크기를 반환합니다.

a ? (b:c)는 a가 참(1)일 경우에는 b, 거짓(0)일 경우에는 c를 반환합니다. 이는 제어문에서 다시 언급하겠습니다. 그외의 것도 각각 함수, 구조체 언급 시에 설명하겠습니다.

'프로그래밍 강좌 > C 언어 기초' 카테고리의 다른 글

7. C 함수 (function)  (4) 2007.06.15
6. 제어문  (0) 2007.06.14
4. 변수  (2) 2007.06.12
3. C 기초문법  (0) 2007.06.05
2. 소스코드, 컴파일, 링크  (6) 2007.06.04
AND

C에서 변수는 말 그대로 변할 수 있는 값을 의미하며, 변수는 메모리에서 값을 저장할 수 있는 저장소 입니다.  "[변수타입] [변수명];"와 같이 변수를 선언하고 사용할 수 있습니다.

int a;

위에는 a라는 int(정수)형 변수를 선언한 예 입니다.  int가 변수타입 ,  a가 변수 명입니다.

4.1 변수 타입
변수 타입은 문자, 정수, 부동소수점 등 변수에서 저장할 값의 종류를 의미합니다.  C에서는 아래와 같은 변수타입을 제공합니다.
사용자 삽입 이미지

1) char

char 는 1바이트 크기를 가지고 있으며, ASCII 코드의 한 문자 또는 0~255(-128~127)의 숫자를 저장할 수 있습니다. C에서 char의 한 문자는 홑따움표(')를 사용하여 표현하고, 문자열은 쌍따움표(")를 사용하여 표현합니다.


2) short, int , long

일반적인 정수를 표현하기 위한 변수형입니다. 흔히 int는 해당 시스템이 가장 빠르게 처리할 수 있는 크기라고 하며, 일반적으로 2 또는 4Byte의 크기를 가집니다.


3) float, double

float과 double은 부동소수점을 표현하는데 사용됩니다. 모든 데이터를 2진수로 인식하는 컴퓨터에서는 부동소수점을 처리할 때, 약간의 문제가 있습니다. 이 부분에 대해서는 후에 기회가 되면 다시 언급하겠습니다.


4) signed/unsigned

각 변수 타입 앞에는 signed 또는 unsigned 를 선언할 수 있습니다. 생략된 경우에는 signed로 간주합니다. signed와 unsigned는 음수를 포함할 지, 포함하지 않을지를 결정합니다.

1byte인  char를 예로 들면 256가지 경우의 수를 표현할 수 있습니다. 이는 양수만 사용할 경우에는 0~255까지 표현할 수 있지만, 음수도 포함할 경우에는 -128~127까지 표현할 수 있습니다.

4바이트인 int형일 경우에는 비트로 환산하면 4X8=32Bit, 즉 232 까지 표현할 수 있습니다.

참고로 기계가 인식할 수 있는 단위를 비트(bit)라고 합니다. 1bit는 0과 1 (On/Off)의 두가지 경우의 값을 나타낼 수 있습니다. 1 Byte는 8개의 bit로 이루어져 있습니다. 그러므로 2에 8승, 즉 256가지 값을 표현할 수 있습니다.

소스에서 char c = 9; 라는 코드는 실행 시 메모리에 변수 c를 위해 1Byte(8bit)를 할당하고 값은 9로 저장되는데 , 이 9는 컴퓨터에서는 이진수 00001001로 아래와 같이 메모리에 저장됩니다.
사용자 삽입 이미지
위의 2진수는 아래와 같이 10진수로 변환할 수 있습니다.
(0 X 27) + (0 X 26) + (0 X 25) + (0 X 24) + (1 X 23) + (0 X 22) + (0 X 21) + (1 X 20)

첫번째와 네번째만 1이므로 우측으로 부터 첫번째와 두번째 연산인 (1 X 23) + (1 X 20)만 유효하므로 9로 표현됩니다. 2진수를 이해하고 있어야 C에서 사용하는 쉬프트 나 비트 연산을 이해할 수 있습니다.


5) 변수 타입 크기

각 변수타입들의 크기는 일반적으로 아래의 출력내용과 비슷하나, 시스템에 따라서 약간 틀릴 경우도 있습니다. 아래의 코드로 사용하는 시스템에서 변수 타입별로 크기를 확인하실 수 있습니다.

#include <stdio.h>

int main(int argc, char* argv[])
{
    char c;
    short s;
    int n; 
    long l;
    float f;
    double d;

    printf("char: %d\nshort: %d\nint: %d\nlong: %d\nfloat: %d\ndouble: %d\n",      sizeof(c), sizeof(s), sizeof(n), sizeof(l), sizeof(f), sizeof(d));
   
return 0;
}

위의 소스를 컴파일 하고 실행보면, 아래와 같이 각 변수타입 별 바이트 수를 확인하 실 수 있습니다. 아래는 제 맥의 터미널에서 실행해 본 화면 입니다.
사용자 삽입 이미지


4.2 변수명

1) 작성 규칙

변수명은 용도에 따라서 아래의 규칙에 따라 개발자의 마음대로 정할 수 있습니다.
  • 알파벳 대소문자([A-Z][a-z]), 숫자([0-9]), 언더바(_)를 사용할 수 있습니다.
  • 첫 글자에 숫자가 올 수 없습니다.
  • 대소문자를 구별합니다.

>> 아래는 유효한 변수명의 예 입니다.
int myData; int my_data; int mydata_1;

>> 아래는 사용할 수 없는 변수명의 예 입니다.
int my data; int 3mydata;

>> 아래의 temp와 Temp는 서로 다른 변수로 인식 합니다.
int temp; int Temp;


2) 명명법

함수도 마찬가지지만 변수명은 소스를 이해하기 쉽게 만드는데 많은 영향을 줍니다.

윈도우 API 함수와 MFC에서 주로 사용되는 헝가리안 표기법이 있습니다. 변수의 타입과 용도를 알기쉽게 만들어 주는 표기법입니다. 간단하게 예를 들면 아래와 같습니다.

char*  g_pszAppName;
g_ 는 전역변수를 의미하며, p는 포인터, sz은 NULL로 끝나는 문자를 의미 합니다. 그뒤의 이름은 의미별로 대문자로 구별합니다. 이런식의 표기법은 소스 중간에서 g_pszAppName을 보더라도 쉽게 타입과 용도를 추측할 수 있습니다.

하지만 일반적으로 unix C 프로그래머들은 대문자를 define, 전역변수나 특수한 용도가 아니면, 많이 사용하지 않았습니다. 대소문자 구분 대신 "_"를 주로 사용하였습니다. 위의 예를 들면 아래와 같습니다.
char* app_name;

그외 java나 objective-c에선 아래와 같은 명명법을 선호합니다.
char* appName;

어떤 것이 좋은지는 저도 알 수 없고,  윈도우 프로그래머라고 해서 꼭 헝가리안 표기법을 사용하거나 unix 나 java 프로그래머라고 해서 꼭 위와 같이 하지는 않습니다.

하지만 한가지 확실한 점은 일관된 규칙으로 의미있는 변수명을 사용해야 소스의 이해 및 관리가 쉽습니다. 간단히 예를 들면 만약 남녀의 수를 합산하는 코드가 있다면, 1)의 소스 보다 2)의 소스가 이해하기가 더욱 쉽습니다.

1) a = b + c;
2) total_count = man_count + woman_count;


4.3 변수 선언 위치
C에서 변수는 함수의 처음 위치에서 선언되어야 합니다. 하지만 C++ 부터 변수를 함수내에 사용하는 곳에서 자유롭게 선언할 수 있게 되었습니다.

오래된 C 컴파일러는 아래의 좌측 이미지와 같이 함수에서 사용하는 모든 변수들은 함수가 시작되면서 선언되어야 합니다.  하지만 C++의 장점을 포용한 현재의 C 컴파일러들은 아래의 우측과 같이 실행코드 중간에 int j; 와 같이 변수를 선언하는 것을 허용합니다.
사용자 삽입 이미지 사용자 삽입 이미지


4.4 변수 유효 범위
변수는 선언되는 위치에 따라서 전역(global)변수와 지역(local)변수로 나누어 집니다.

#include <stdio.h>

int temp = 5;

int main(int argc, char* argv[])
{
    int temp = 3;

    printf("%d", temp);

    return 0;
}

위에서 int temp = 10; 으로 함수 밖에서 선언된 변수는 전역변수이며, 어느 곳에서나 사용될 수 있습니다.

main 함수 내의 int temp = 3; 으로 선언된 변수는 지역변수이며, main 함수 내에서만 사용할 수 있습니다. 

함수 내에서는 지역변수가 우선됨으로 위의 소스를 실행하면, 지역변수 temp의 3이 출력됩니다. main함수 내의 int temp =3; 라인을 삭제 후 컴파일 하면 전역변수 temp의 5가 출력됩니다.

전역변수와 지역변수의 큰 차이점은 전역변수는 어플리케이션 메모리 에서 힙(heap)이라 불리우는 곳에, 지역변수는 지역변수와 더불어 함수인자 등에 사용되는 스택(stack)에 위치 합니다.

스택은 시스템에 따라 제한된 일정한 크기를 가지고 있습니다. 그렇기 때문에 큰 배열 등의 대용량의 메모리가 필요한 경우에는 전역변수나 malloc등을 이용하여 힙영역에 위치 시키거나, 인자로 전달할 때는 포인터를 사용하여야 합니다.


4.5 static 변수
변수타입 앞에 static 이란 키워드를 사용할 수 있습니다. static 변수는 함수내에 지역변수로 선언 되더라도 스택이 아닌 힙 영역에 위치합니다. 그래서 한번 사용하고 값이 사라지는 일반 지역변수와는 달리 계속 그 값을 유지하고 있습니다.

#include <stdio.h>

void test1()
{
    int n = 0;
    printf("test1: %d\n", n);

    n = n + 1;
}

void test2()
{
    static int n = 0;
    printf("test2: %d\n", n);
   
    n = n + 1;
}

int main(int argc, char* argv[])
{
    test1();
    test1();
    test1();

    test2();
    test2();
    test2();

    return 0;
}

위의 소스코드를 컴파일하고 실행하면, 아래와 같은 결과를 확인할 수 있습니다.
사용자 삽입 이미지
test1 함수의 지역변수 n은 함수가 호출될 때마다 스택에 새로 생성되며, 0으로 초기화 됩니다. 그래서 함수 마지막에 1을 더 해주어도 항상 0으로 출력됩니다.

test2 함수의 static 변수 n은  어플리케이션 실행 시에 0으로 초기화되어 힙영역에 위치하기 때문에, 함수가 재호출되어도 항상 그 값을 유지하고 있습니다.

이상 변수에 관해서 알아 보았는데, 몇 가지 언급 되지 않은 내용이 있습니다. 전역 변수에서 static 사용, extern 키워드 등이 있습니다. 이는 여러 소스 파일을 사용할 경우에 사용되며, 추후에 다시 언급하겠습니다.

'프로그래밍 강좌 > C 언어 기초' 카테고리의 다른 글

6. 제어문  (0) 2007.06.14
5. 연산자  (0) 2007.06.13
3. C 기초문법  (0) 2007.06.05
2. 소스코드, 컴파일, 링크  (6) 2007.06.04
1. C언어 공부를 위한 준비  (9) 2007.06.03
AND