C++에서는 일반적인 함수포인터 선언방식 이외에 다른 함수포인터 선언방식을 지원한다. 사용방법은 다음과 같다. func라는 함수를 선언하였다. 11번째 줄은 함수 포인터 구조체를 사용하여 정의해주는 일반적인 방법이다. 구조체 내부에 함수포인터를 사용할 경우 대부분 이러한 방법을 이용하게 된다. 13번째 줄 또한 functype이라는 별명을 사용하여 함수포인터를 정의해주는 방법이다. 23번째 줄은 functional 라이브러리를 사용하여 함수 포인터를 선언하는 방법이다. functional 라이브러리를 사용하면 다양한 함수나 함수포인터를 객체로 간편하게 변환하거나 함수 객체를 조합하여 더 복잡한 동작을 수행하게 만들 수 있다.
C++에서 프로그래밍을 할 때 컴파일때는 오류가 발생하지 않다가. 프로그래밍 자체의 실수로 범위값 설정이 잘못되어 오류가 나타나는 경우가 생겨난다. 이는 코드 자체의 오류점이며, 컴파일 시에 확인되지 않기 때문에 프로그래머가 찾기가 힘든 경우가 매우 많다. 이때 사용하는 함수가 Assert 함수이다. 이는 프로그램이 실행중에 조건을 확인하고, 만일 Assert 함수에 지정된 조건일 경우 프로그램을 터트리고 오류를 출력한다. assert를 사용하기 위해서는, cassert 라이브러리 를 사용해야 한다. 다음은 assert 함수를 사용한 예시 코드이다. assert를 사용하면 특정 조건에 만족 할 경우 오류를 출력한다. 만약, 컴파일 전에 오류가 나도록 하고싶다면, assert를 static 처리해주면 된다..
C++에서는 함수 템플릿을 사용하여 함수 오버로딩 대신 사용할 수 있다. template를 통해 다양한 데이터타입에 대해 동일한 기능을 수행할 수 있도록 도와준다. template는 일반적으로 클래스나 함수를 정의할 때, 템플릿 매개변수를 사용하여 탕비정보를 전달하는 것이다. 이때 선언되는 템플릿 매개변수는 사용자가 입력하는 데이터 타입 으로 대체된다. 다음의 예시를 살펴보자. 위와 같이 T 문이 smax에 대해 형식이 자동으로 바뀌며 들어가는 것을 볼 수 있다. 이는 일반적인 함수선언과 다르게 하나의 함수 만 으로도 int와 double값을 자동으로 바꾸어주기 때문에 하나의 함수만으로 다양한 기능을 수행하게 할 수 있다. C++에서만 사용이 가능하다.
함수 오버로딩 은 하나의 함수 이름을 여러번 정의하여 사용하는 것을 이야기 한다. 함수 오버로딩은 같은 이름의 함수가 서로 다른 매개변수 목록을 가지는 경우 사용이 가능하다. 예를 들어, 동일한 이름을 가진 함수가 있을 때 매개변수의 데이터 타입이나 개수가 다른 경우, 각 함수는 함수의 이름을 기준으로 호출되는것 이 아닌, 매개변수나 데이터 타입을 기준으로 먼저 참조된 다음, 함수의 이름을 참조하여 불러내게 된다. 이렇게 함수 오버로딩을 사용하게 되면, 코드의 가독성과 유지보수성을 향상시킬 수 있다. 비슷한 기능을 가지는 함수가 서로 다른 이름을 가지지 않아도 됨으로, 이름을 유지하는것이 더 쉽기 때문이다. 다음은 함수 오버로딩 을 사용한 코드의 예시이다. print는 전부 이름이 같지만, 매개변수의 종..
인라인 함수는, C++에서 사용되는 일반적인 함수와 다르게, 함수 코드를 직접 삽입하는 방식으로 동작한다. 이를통해 함수 호출에 따른 오버헤드를 줄일 수 있으며, 실행속도가 빨라진다. 인라인 함수의 특징은 다음과 같다. 함수 호출이 아닌 코드 삽입 : 함수 호출문이 있는곳에 함수코드가 직접 삽입되는 방식으로 동작하게 된다. 실행속도 향상 : 함수호출 오버헤드를 제거함으로 ( 함수가 코드에 직접 삽입됨으로 호출되지않는다 ) 실행속도가 빨라진다. 함수 크기 제한 : 함수 코드가 컴파일 시점에 CODE삽입으로 대체됨으로 함수의 크기가 일정크기 이상이 되면 인라인 함수로 사용할 수 없다. 장점 실행속도가 빠르다. 함수 호출로 발생하는 오버헤드를 줄일 수 있다. 단점 인라인 함수의 크기가 일정 이상이면 인라인 함..
함수 호출 규약 이란? 함수가 호출될 때 매개변수와 반환값을 어떻게 전달하는지 정의하는 규칙이다. 함수 호출 규약은 컴퓨터 아키텍처, 운영체제, 컴파일러와 같은 요소에 따라 달라진다. 그러나, 대부분의 호출규약은 함수 호출 프로토콜을 다음과 같이 규정한다. 매개 변수 전달 방식 매개변수는 레지스터, 스텍, 메모리 또는 조합으로 전달된다. 매개변수 전달 순서 매개 변수는 왼쪽에서 오른쪽으로, 또는 오른쪽에서 왼쪽으로 전달된다. 반환값 처리 반환값은 레지스터, 스텍, 메모리 또는 조합으로 처리된다. 스택 처리 함수가 호출되고 반환될 때 스택 프레임이 생성되고 해제된다. 대표적인 함수 호출 규약으로는, C언어에서 사용되는 cdecl, stdcall, fastcall, this call, vectorcall, ..
대표적인 함수 호출 규약으로는, C언어에서 사용되는 cdecl, stdcall, fastcall, this call, vectorcall, Nacked call이 있고,
Microsoft의 x64 calling convention이 있다.
cdecl
cdecl은 "C declaration" 의 약자로, C언어의 기본 호출 규약이다. 이 규약은 함수 호출 시 매개변수를 스택에 푸시하고, 호출한 함수가 반환한 값도 스택에 푸시한다. 이러한 방식으로 매개변수와 반환값을 전달하기에, 스택공간이 상대적으로 많이 필요하다. 매개변수가 적은 함수에서 자주 사용된다.
stdcall은 WinAPI와 같은 WIndows 플랫폼에서 주로 사용되는 함수 호출 규약으로, cdecl과 마찬가지로 매개변수와 반환값을 스택에 푸시하고, 호출한 함수가 스택을 제거하는 것 이 아니라, 호출한 함수가 만든 스택 프레임을 호출한 함수에서 제거하게 된다. Windows API와 같은 매개변수가 많은 함수에서 사용된다.
cdecl은, 함수 호출 시 매개변수를 스택에 저장하고, 호출이 끝난 후 스택에서 매개변수를 제거한다. 이러한 방식은 매개변수의 개수가 많아질수록, 스택의 사용이 늘어나게되어 호출속도가 느려질 수 있다.
stdcall은, 함수 호출 시 매개변수를 스택에 저장하고, 호출이 끝난 후 스택에서 매개변수를 제거한다. 그럼으로, stdcall호출규약은 스텍의 제거를 호출 대상이 해야함으로 호출자는 호출대상에서 반환된 값을 쉽게 얻을 수 있다. 그러나, 호출 대상이 해야하기 때문에 호출대상에 대한 오버헤드가 발생할 수 있다.
fastcall
fastcall은 매개변수를 레지스터에 저장하고 많은 경우에 함수 호출시 매우 빠른 실행속도를 보장한다. 매개변수의 개수가 많을 경우에는 스택을 이용하여 전달하게 된다.
인라인 함수에서의 오버헤드가 발생할 수 있다. 멤버함수가 인라인 함수로 작성될 경우 'this'포인터 전달 및 호출 스택 관련 작업 때문에 오버헤드가 발생한다. [인라인 함수는 코드가 함수 호출문에 삽입되는 방식을 이야기 한다]
함수포인터 사용에 제한이 있다. 일반적인 함수 포인터와 호환되지 않아, 호출대상 함수가 __thiscall 호출규약을 사용하는 경우 해당 함수를 호출하는 함수포인터 도 __thiscall 호출 규약을 사용해야 한다.
표준이 아닌 호출규약 이기 때문에, C++표준이 아님으로 특정 컴파일러에서만 지원된다(Microsoft Visual C++ 컴파일러 에서만 지원) 그럼으로 이식성이 떨어질 수 있다.
vectorcall
vectorcall 호출규약은 Microsoft Visual C++ 2013부터 도입된 비표준(non-standard)호출규약 중 하나이다. 이 호출규약은 SSE(SIMD) 명령어를 이용한 고성능 연산을 위해 만들어 졌으며, 벡터 자료형의 인자 전달 및 반환을 위한 호출규약 이다.
vectorcall 의 특징은 다음과 같다.
인자 전달 순서: 왼쪽에서 오른쪽으로 전달된다.
인자 전달 방법: 레지스터에 저장된다. 첫번째부터 세번째까지는 XMM레지스터에, 네번쨰부터 여덟번째 까지는 일반 레지스터에 저장된다.
스택 프레임을 정리하는 부담이 호출자에게 들어가기 때문에, 함수 내에서 동적 메모리 할당을 수행하는경우 할당한 메모리를 호출자(예를들어 int main()같은 ) 가 스택 프레임을 정리하기 때문에 호출자가 동적 메모리를 반환하기전 에는 해당 메모리를 해제할 수 없다. 그럼으로 메모리누수가 발생할 가능성이 있으며, 이때문에 프로그래머는 메모리 해제 작업을 함수 외부에서 수행해야만 한다.
Nacked Call
Nacked Call 호출규약은 함수 진입점에서 컴파일러가 자동으로 함수 프롤로그와 에필로그 코드를 생성하지 않는 호출규약이다. 이 규약을 사용하면 호출된 함수가 진입점에서 스택 프레임을 생성하거나 삭제하지 않으며, 이에대한 방법은 전부 개발자가 작업해야 한다.