7-2-다.정적 함수

기억 부류는 주로 변수에 대해 적용되지만 함수도 기억 부류를 가진다. 함수에는 전역이니 지역이니 하는 개념은 존재하지 않으며 레지스터형 기억 부류도 당연히 없다. C의 함수는 모두 수평적인 평등 관계이며 어떤 함수를 다른 함수의 지역 함수로 선언하는 것은 허용하지 않는다(파스칼은 지역 함수를 허용한다). 따라서 C의 함수들은 원칙적으로 전역이다.

기억 부류 중에 함수에 적용되는 것은 정적(static) 기억 부류밖에 없다. 정적 함수는 특정 모듈에서만 사용할 수 있는데 앞에서 살펴본 외부 정적변수의 특성과 유사하다. 함수 정의문 앞에 static이라는 지정자만 붙이면 이 함수는 정적 함수가 된다.

 

static void func()

{

     ....

}

 

정적 함수와 반대되는 개념에 대해 별다른 명칭은 없고 굳이 이름을 붙인다면 비정적 함수나 외부 함수 정도가 될 것이다. 외부 함수는 별다른 지정이 없는 한 외부로 항상 알려지며 원형 선언만 하면 어떤 모듈에서나 이 함수를 호출할 수 있다.

그러나 정적 함수는 특정 모듈에서만 사용하도록 정의된 것이므로 외부에서 원형을 선언한다 하더라도 이 함수를 호출할 수 없다. 외부에서 그 존재를 알 수 없도록 해야 하는 이유는 외부 정적변수의 경우와 마찬가지로 이름 충돌을 방지하기 위해서이다. 재사용을 위해 작성한 모듈에서 ReadFile이라는 함수를 사용하는데 이 이름이 너무 일반적이어서 프로젝트내의 다른 함수명과 충돌될 것 같으면 이 함수를 static으로 선언하면 된다.

정적 함수가 필요한 실제 예를 들어 보자. 어떤 개발자가 혼신의 노력끝에 데이터를 압축하고 해제하는 일련의 함수들을 만들었다고 하자. 이 함수들을 다른 개발자들도 편하게 쓸 수 있도록 하려면 이 함수들을 별도의 모듈에 작성하고 헤더 파일에 함수 원형과 그 외 필요한 상수, 타입도 정의해야 할 것이다. 이렇게 해 놓으면 누구든지 Zip.cpp와 Zip.h를 자신의 프로젝트에 포함시켜 압축, 해제 함수를 편리하게 활용할 수 있다.

이 개발자는 또 네트워크로 데이터를 주고 받는 함수를 만들었으며 이 함수들도 다른 개발자를 위해 공개하고자 한다. 전송 함수들은 빠른 전송을 위해 압축해서 보내는 기능이 있어 메모리에서 압축 및 해제하는 Comp, Decomp 함수를 내부적으로 사용한다. 이렇게 만들어 놓으면 네트워크 전송 기능을 필요로 하는 누구든지 Network.cpp와 Network.h를 재사용할 수 있을 것이다.

문제는 두 모듈이 모두 필요할 때인데 만약 Zip과 Network를 동시에 프로젝트에 포함시켰다고 해 보자. 이렇게 되면 Comp, Decomp 함수를 이중으로 정의하는 꼴이 되어 제대로 컴파일되지 않을 것이다. 모듈 개발자가 원하는 것은 다음과 같다.

 

Zip과 Network는 개별적으로 원할 때만 포함시킬 수 있어야 한다.

Network가 Zip 모듈에 종속적이지 않아야 한다.

둘 다 포함하더라도 아무 문제가 없어야 한다.

 

이렇게 만들기 위한 해법이 바로 정적 함수이다. Network 모듈의 Comp, Decomp 함수를 정적으로 선언하면 외부로 알려지지 않으므로 Zip 모듈의 같은 이름을 가지는 함수와 충돌되지 않는다. 이런 이름 충돌 문제는 생각보다 빈번하게 발생하는 편인데 프로젝트의 규모가 조금만 커져도 이름끼리의 충돌 문제는 아주 심각해진다.

친구에게 대충 나누어줄 모듈이라면 아무래도 상관없다. Network모듈에 압축 함수를 빼고 이 모듈을 쓰고 싶으면 반드시 Zip도 포함하라고 일러 주면 된다. 그러나 상용으로 판매되는 라이브러리라면 이래서는 안된다. 고객들은 주의 사항이 많은 라이브러리를 좋아하지 않으며 사서 바로 쓸 수 있는 것을 좋아한다. 또한 가격 정책을 매기는데도 문제다. Network보다 Zip이 훨씬 더 비싼 모듈인데 Network를 사면 Zip도 같이 끼워 줘야 하는 문제가 있다. 정적 함수는 같은 코드가 중복되는 문제점이 있지만 그렇더라도 충돌이 발생하는 것보다는 훨씬 더 낫기 때문에 C언어는 이런 문법을 제공하는 것이다.