티스토리 뷰

C++

[C++] 함수의 사용

devbelly 2020. 10. 24. 00:04

함수사용의 조건


함수를 사용하기 위해선 함수정의와 원형을 제공하고 호출코드를 작성해야합니다. 라이브러리 함수를 사용한다면 이미 해당함수는 정의되어 컴파일이 되어있습니다. 그 원형을 제공하기 위해 우리는 헤더파일을 사용합니다.

 

함수원형의 필요성


함수의 정의안에 이미 원형이 포함되어 있는데 왜 우리는 굳이 정의와 원형을 나누어 제공을 해야할까요? 

첫번째 이유를 이해하기 위해선 함수의 작동방식에 대해 이해할 필요가 있습니다. 호출된 함수는 자신의 리턴값을 CPU의 레지스터나 메모리에 복사하는 방식으로 값을 리턴합니다. 호출된 함수는 함수의 정의를 확인하여 해당 위치에 어떤 값을 리턴해야하는지 알게 됩니다. 그리고 호출한 함수는 함수의 원형을 확인하여 해당위치에서 어떤 값을 가져와야 하는지를 확인합니다. 해당 메모리로부터 몇바이트를 가져와야하는지를 확인한다는 뜻입니다.

두번째 이유는 함수의 정의를 컴파일러가 직접 찾으면 그동안 main함수는 컴파일을 중지해야합니다. 이러한 속도문제를 견딘다고 해도 만일 해당함수를 찾지 못하면 치명적인 오류를 발생하게 됩니다.

 

 

main 함수에 대하여


함수는 호출한 함수와 호출된 함수로 나눌 수 있습니다. 하지만 main함수는 main함수를 호출하는 함수라는 개념이 명확하지 않습니다. main은 프로그램과 운영체제를 중개하기 위해 컴파일러가 프로그램에 추가하는 시동코드에 의해 호출됩니다. 모든 C++은 main함수로부터 실행을 하며 만일 main함수가 없다면 컴파일러가 사용자에게 알려줍니다. dll과 같은 예외도 존재하긴합니다. 

일일이 함수의 마지막에 return 0을 다는 것을 번거로워 하는 사용자를 위해 ISO C++은 컴파일러가 리턴구문을 만나지 못한채로 main함수의 마지막에 도달하면 자동으로 return 0을 넣어줍니다. 이는 오로지 main함수에만 해당합니다.

 

Argument vs Parameter


어느 분야든 책을 읽어나갈 땐 용어의 정의를 명확히 하며 읽어야 합니다. 

#include <iostream>
using namespace std;

int CUBE(int); // 함수 원형에 굳이 변수 x를 적지 않아도 된다.
int main() {
    int val=3;
    cout << CUBE(val); // return 27, 제대로 작동한다.
    return 0;
}
int CUBE(int x) { return x * x * x; }

main함수에서 CUBE(val)를 호출하게 되면 호출된 함수는 val값을 x에 복사하여 사용합니다. 이는 원본데이터 val을 보호하여 프로그램의 무결성을 높여줍니다.  C++표준은 함수를 호출할때 사용하는 val를 argument라 부르고 호출된 함수 내에 있는 x를 parameter이라고 정의합니다. 우리나라 말로는 argument를 인수, parameter을 매개변수라고 합니다.

 

배열매개변수


배열 또한 새로운 매개변수에 대입 될 뿐 규칙을 위반하지 않습니다. 이 글에서 살펴보았듯 C나 C++은 배열을 내부적으로 포인터와 같이 처리합니다. 배열과 포인터간의 관계는 배열복사에 걸리는 메모리와 시간의 문제를 해결해주게 됩니다.

 

포인터와 const 제한자

원본 변경에 대한 문제는 const 제한자가 해결해줍니다. 일반적인 const 변수는 변경이 되지 않는다는 상수라는 점외에는 생각해볼 주제가 없지만, const 포인터는 사용방식이 다음 두가지가 있습니다.

 

  • const int* a
  • int* const b

첫번째 const int*a 의 경우는 a가 가리키는 변수가 상수라는 의미입니다. 실제 가리키는 변수가 상수가 아니더라도 a를 통해 해당 변수에 접근할 때는 상수처럼 취급합니다. 두번째 int* const b 의 경우는 포인터 변수인 b를 상수 취급하는 것입니다. 즉 자신의 변경을 막도록 합니다.

 

✔ const 배열

const 배열을 argument로 사용하면 함수의 parameter 작성시 const 가 아닌 일반 parameter로 작성을 하지 못하게 됩니다. 이유는 상수배열의 주소를 일반 포인터가 받게 되면 상수인 const를 변경할 위험이 있기 때문입니다. 즉 다음과 같은 상황은 허용되지 않습니다

 

#include <iostream>
using namespace std;
int sum(int arr[], int n) { // const int arr[]여야만 한다
    //do something ...
}
int main() {
    const int month[12]{ 1,2,3,4,5,6,7,8,9,10,11,12 };

    cout << sum(month, 5);
    return 0;
}

 

++

구조체를 매개변수로 받게 되면 복사본으로 작업을 하게 됩니다.

 

참고서적

Stephen Prata, 『C++ 기초플러스』, 성안당, 2012

'C++' 카테고리의 다른 글

[C++] namespace  (0) 2020.10.31
[C++] 포인터  (0) 2020.10.17
[C++] 함수 템플릿  (0) 2020.10.04
[C++] 디폴트 매개변수와 함수 오버로딩  (0) 2020.10.02
[C++] inline 함수  (0) 2020.10.01
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함