char (*Func(int (&)[3]))[3];
?????
int arr[3];
ARRAYSIZE(arr) : 어떻게 만들어야 할까?
사람 Version.
#define ARRAYSIZE sizeof(A) / sizeof((A)[0])
int* arr = new int[3];
ARRAYSIZE(arr)
64bit : 2 32bit : 1
64bit에서 (포인터의 크기가 8, 요소는 4)
외계인 Version.
template <typenmae T, size_t N> char (*RtlpNumberof(T (&)[N]))[N];
#define ARRAYSIZE(A) (sizeof(*RtlpNumberOf(A)))
문법을 제대로 배운적이 없다.
Right-Left Rule 외계인의 가르침
독해는 했지만 원하는 타입은 어떻게 파생할까?
타입 파생 규칙의 기본을 알아보자
- 이름 자리[NP]
각 Type마다 식별자가 놓이는 자리는 고정되어있다.
기본타입(char, int 등)의 이름자리는 type 의 바로 오른쪽에 있다.
이름자리에 식별자를 넣으면 객체를 정의할 수 있다.
1.1
배열 타입 파생 1
배열 요소의 타입에서 시작. 배열 요소의 수가 n일 때 n 을 [NP]옆에 붙인다. [NP]를 생락하면 최종 타입
int[NP] -> int[NP][3] -> int [3]
1.2
배열 타입 파생 2
int요소 3개인 배열이 요소로서 2개인 배열
int[NP] -> int [NP][3] -> int[NP][2][3] -> int [2][3]
2.1
포인터 타입 파생 1
포인터의 대상(가리키는)타입에서 시작. 간접연산자 (*)를 [NP]바로 왼쪽에 붙인다.
필요한 경우 [NP]와 결합 우선 순위를 높이기 위해 괄호로 묶는데 [NP]의 결합 우선순위 오른쪽 심볼 > 왼쪽 심볼
int요소 3개인 배열을 가리키는 포인터
int [NP] -> int [NP][3] -> int (*[NP])[3] -> int (*)[3]
2.2
포인터 타입 파생 2
배열명은 첫번째 배열 요소를 가리키는 상수 포인터
int* p1 = &arr;
int (*p3)[3] = &arr;
3.1
함수 타입 파생 1
함수의 반환 타입에서 시작한다. 인자열을 [NP] 바로 뒤에 붙인다
int 요소 3개인 배열을 가리키는 포인터를 반환하는 함수 (단, 함수 인자열은 (char))
여기까지가 c, 아래부터 c++
4.1
클래스 맴버를 가리키는 포인터 타입 파생
일반적으로 포인터란 메모리의 특저 영역을 가리키는 것이지만, 클래스 맴버를 가리키는 포인터는 비정적 맴버 그 자체를 가리킨다.
class CTest
{
public:
int m_Member; // 비정적 멤버
static int s_Member; // 정적 멤버
}
int CTest::s_Member
void main() {
CTest t;
&t.m_Member; //메모리영역
&CTest::s_Member; // 메모리영역
&CTest::m_Member; // m_Member 그자체 offset
}
4.2
클래스 맴버의 타입에서 시작한다. 클래스 범위 연산자(CLASS::)를 [NP] 바로 왼쪽에 붙인다
간접 연산자를 바로 왼쪽에 붙인다
필요한 경우 CLSS::*와 괄호로 묶는다. 생략하면 최종 타입을 얻는다
Class의 맴버인 int 요소 2개인 배열을 가리키는 포인터
int [NP] -> int [NP][2] -> int Class::[NP][2] -> int (Class::*[NP])[2]
왜 Class까지 묶었는가 -> Class:: 옆에는 [ 를 허용하지 않는다.
객채 정의
남아있던 [NP]를 객체 이름으로 바꾸고 ;를 붙여주면 정의가된다
typedef를 이용한 타입 정의
이름자리를 새로운 이름으로 변경하고 typedef 를 붙이면 기본타입으로 사용 할 수 있다.