C언어 | 선택문, 반복문, 함수 (JavaScript와의 차이점)

설탕·2024년 3월 20일
0
post-thumbnail

📖 혼자 공부하는 C언어 책의 선택문, 반복문, 함수 파트를 읽고 정리한 글입니다.

JavaScript를 먼저 배운 입장에서 C언어의 기본 문법은 JavaScript와 매우 유사했기 때문에, 이 글에서는 C언어에서 기억할 만한 차이점 위주로 작성하고자 한다.

선택문, 반복문

C언어의 선택문과 반복문은 JavaScript와 거의 동일하다.

  • 선택문: if, switch ~ case
  • 반복문: while, for, do ~ while

다만 동적 타입 언어인 JavaScript와 달리 정적 타입의 C언어에서는 자료형에 유의해야 한다.

⭐️ switch ~ case문을 쓸 때 조건식으로 정수식만 사용해야 한다.

조건식에 정수형 상수나 변수 또는 결과값이 정수인 수식만 사용할 수 있고, case 상수식 역시 정수만 가능하다.

#include <stdio.h>

int main(void)
{
  int rank = 2, money = 0;

  switch (rank) // 정수
  {
  case 1: // 정수
    money = 300;
    break;
  case 2:
    money = 200;
    break;
  case 3:
    money = 100;
    break;
  default:
    money = 10;
    break;
  }

  printf("상금: %d\n", money); // 상금: 200 출력

  return 0;
}

함수

함수는 컴파일러가 알 수 있도록 (1) 선언하고, 함수 기능을 (2) 정의한 것을 (3) 호출하여 사용한다.

  • 함수 선언: 컴파일러가 새로 만든 함수를 인식할 수 있도록 정보를 주는 역할
  • 함수 정의: 함수의 기능 구현
  • 함수 호출: 함수 사용
#include <stdio.h>

int sum(int x, int y); // sum 함수 선언

int main(void)
{
  int a = 10, b = 20;
  int result;

  result = sum(a, b); // sum 함수 호출
  printf("%d\n", result); // 30 출력

  return 0;
}

int sum(int x, int y) // sum 함수 정의
{
  return x + y;
}

함수 선언(Function Declaration)과 함수 정의(Function Definition)

함수 선언(Function Declaration)

함수를 선언하려면 함수명, 매개변수, 반환형으로 이루어진 함수 프로토타입에 세미콜론을 붙인다.

int sum(int x, int y); // 함수 프로토타입으로 함수 선언

매개변수 이름은 생략할 수 있다.

int sum(int, int); // 매개변수 이름 생략

함수 정의(Function Definition)

⭐️ 함수를 다른 함수 안에 정의할 수 없다.

따라서 sum 함수는 main 함수 바깥에서 정의해야 한다.

⭐️ 함수 선언이 없으면 함수 정의는 항상 함수 호출 이전에 있어야 한다.

프로그램은 항상 main 함수부터 시작하며 그 이후에는 호출 순서에 따라 실행된다. 함수를 미리 선언하지 않으려면 항상 호출하는 함수 앞에 정의해야 하는데, 호출 관계가 엉켜 있으면 순서에 맞게 정의하기 쉽지 않다. 따라서 main 함수 앞에 모든 함수를 선언해서 함수 프로토타입을 파악하고, main 함수 아래에 함수 정의를 쭉 작성하여 자유롭게 호출할 수 있도록 하는 것이 좋다.

만약 함수 선언을 안 하고 함수 정의를 main 함수 아래에서 하면, 즉 함수 호출 다음에 하면 어떻게 될까?

ex.c:8:12: error: call to undeclared function 'sum'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
  result = sum(a, b);
           ^

선언되지 않은 함수를 호출할 수 없다는 에러가 발생한다.

🤔 함수 정의가 있는데 함수 선언이 왜 필요할까?

이유 1. 함수 선언에서 반환값의 형태를 확인한다.

컴파일러는 컴파일할 때 함수를 호출한 자리에 반환값과 같은 형태의 저장 공간을 준비한다. 즉, 정수를 반환하면 호출한 자리에 int형 공간을 확보하고 실수를 반환하면 double형 공간을 확보한다. 따라서 함수를 호출하기 전에 선언을 통해 반환형을 미리 컴파일러에 알릴 필요가 있다.

이유 2. 함수의 호출 형식에 문제가 없는지 검사한다.

함수 선언문에는 매개변수의 개수와 형태에 대한 정보가 있으므로 호출할 때 정확한 값을 넘겨주는지 검사할 수 있다.

sum 함수에 인수를 하나만 넣고 호출한다면?

ex.c:10:17: error: too few arguments to function call, expected 2, have 1
  result = sum(a); // sum 함수 호출
           ~~~  ^
ex.c:3:5: note: 'sum' declared here
int sum(int x, int y); // sum 함수 선언
    ^

선언된 함수 프로토타입과 비교해서 인자가 적게 들어왔다고 에러 메시지로 알려준다.

매개변수 또는 반환값이 없는 함수: void

다음 say_hello 함수는 매개변수도, 반환값도 없이 단순히 Hello!를 출력하는 함수이다.
매개변수 또는 반환값이 없는 함수는 void를 사용해서 선언/정의한다.

#include <stdio.h>

void say_hello(void);

int main(void)
{
  say_hello();

  return 0;
}

void say_hello(void)
{
  printf("Hello!\n");
}

매개변수 자리의 void는 생략할 수 있지만 반환형 자리의 void는 생략할 수 없다.
(C99 이전에는 반환형을 생략하면 컴파일러가 반환형을 암시적으로 int로 해석해줬지만, C99부터는 반환형을 생략할 수 없게 되었다. 컴파일러가 여전히 int로 해석한다 하더라도 생략하면 안 된다는 뜻.)

void say_hello(); // 가능
say_hello(void); // 불가

반환형이 void인 함수는 컴파일러가 반환값이 없다고 가정해 호출한 위치에 반환값을 저장할 공간을 준비하지 않는다. 따라서 return문에 값을 사용하면...

ex.c:16:3: error: void function 'say_hello' should not return a value [-Wreturn-type]
  return "Hello!\n";
  ^      ~~~~~~~~~~

컴파일러가 값 반환하면 안 된다고 에러 메시지로 알려준다.

TypeScript에서 아무것도 반환하지 않는다는 의미로 사용해왔던 void의 정체를 알게 되었다!

참고
C Functions - GeeksforGeeks

profile
공부 기록

0개의 댓글