C++가 변 매개 변수의 실현 방법

가 변 매개 변수의 실현 은 세 가지 문 제 를 해결 해 야 한다.
1.가 변 매개 변 수 를 가 진 함 수 를 어떻게 호출 합 니까?
두 번 째 문 제 는 컴 파일 러 가 컴 파일 할 때 느슨 한 검사 방안 을 사용 해 야 하 는데 이것 은 프로 그래 밍 오류 에 불리 한 문 제 를 가 져 올 수 있다.
세 번 째 는 제 가 여기 서 관심 을 가 져 야 할 문제 입 니 다.먼저 C 언어 를 예 로 들 어 그 실현 원 리 를 분석 하 겠 습 니 다.
printf 와 scanf 는 C 언어 표준 라 이브 러 리 에서 가장 흔히 볼 수 있 는 가 변 매개 변수 함수 입 니 다.printf 의 서명 은?

int printf(const char* format, ...);
그 중에서...가 변 적 인 파 라 메 터 를 표시 합 니 다.지금 은 printf 를 모방 하여 간단 한 예 를 쓰 겠 습 니 다.
하나,간단 한 예:

#include <windows.h>
#include <stdio.h>

void VariableArgumentMethod(int argc, ...);

int main(){
    VariableArgumentMethod(6, 4, 7, 3, 0, 7, 9);
    return 0;
}

void VariableArgumentMethod(int argc, ...){
    // ,
    va_list pArg;
    // pArg
    va_start(pArg, argc);
    //
  for(int i = 0; i != argc; ++i){
        // pArg
        printf("%d, ", va_arg(pArg, int) );
    }

    va_end(pArg);
}

void VariableArgument Method(int argc,...)는 가 변 매개 변수 함수 입 니 다.이 함 수 는 argc 가 지정 한 개수 의 가 변 매개 변 수 를 출력 하 는 데 사 용 됩 니 다.VariableArgumentMethod(6, 4, 7, 3, 0, 7, 9); 이 함수 에 대한 호출 입 니 다.첫 번 째 실 삼 6 은 뒤에 6 개의 인 자 를 따 랐 음 을 나타 냅 니 다.
VariableArgument Method 의 함수 체 에서:
1. va_list pArg;
가 변 매개 변 수 를 가 진 지침 을 정의 합 니 다.이 지침 을 들 어 오 는 가 변 매개 변수 표 에서 이동 하면 첫 번 째 가 변 매개 변 수 를 가 질 수 있 습 니 다.
2. va_start(pArg, argc);
pArg 로 하여 금 가 변 매개 변수 목록 의 첫 번 째 매개 변 수 를 가리 키 게 합 니 다.argc 는 포 지 셔 닝 에 사용 되 는 매개 변수 입 니 다.가 변 매개 변 수 는 argc 이후 부터 시작 되 었 기 때문에 나중에 왜 이렇게 포 지 셔 닝 을 해 야 하 는 지 설명 할 것 입 니 다.
3. va_arg(pArg, int);
이 말 은 순환 체 에 놓 여 가 변 매개 변수 표 의 인 자 를 추출 하 는 데 사용 된다.또한,pArg 를 다음 가 변 매개 변수 로 이동 시 킵 니 다.(끝 에 도착 하면 의미 없 는 주 소 를 가리 킵 니 다.)
4. va_end(pArg);
pArg 에 0 을 주 고 개인 적 으로 여기 있 으 나 마 나 하 다 고 생각 합 니 다.왜냐하면 pArg 는 이미 필요 하지 않 기 때 문 입 니 다.
 
이렇게 해서 VariableArgument Method 함수 체 는 가 변 매개 변수 표 에 들 어 오 는 매개 변 수 를 옮 겨 다 니 며 printf("%d",vaarg(pArg,int)가 출력 되 었 습 니 다.
2.세부 사항 실현
1.먼저 컴 파일 러 가 전달 매개 변 수 를 어떻게 처리 하 는 지 알 아 보 세 요.
컴 파일 러 는 파 라 메 터 를 스 택 에 눌 러 전달 합 니 다.실제 인삼 을 전달 할 때 컴 파 일 러 는 실제 인삼 목록 에서 오른쪽 에서 왼쪽으로 매개 변 수 를 스 택 에 넣 고 VariableArgument Method(6,4,7,3,0,7,9)를 호출 하면 스 택 에 들 어 가 는 순 서 는 9,7,0,3,7,4,6(가 변 매개 변수 와 가 변 매개 변수의 구분 이 없 음 을 주의 하 십시오).스 택 의 주 소 는 높 은 것 에서 낮은 것 이기 때문에 스 택 에 실제 참여 한 후에 스 택 에 있 는 분 포 는 다음 과 같다.이 를 통 해 알 수 있 듯 이 실제 인삼 은 스 택 에 있 고 왼쪽 매개 변 수 는 낮은 주소 에 있 으 며 오른쪽 매개 변 수 는 높 은 주소 에 있 는 상 태 를 유지 합 니 다.OK,이 정도 면 충분해.
낮은 주소 높 은 주소
...
6
4
7
3
0
7
9
...
창고.
 
2. va_list, va_start, va_arg 와 vaend
va_list 는 정 의 된 포인터 형식 입 니 다.vastart, va_arg 와 vaend 는 모두 C 언어 가 가 변 적 인 파 라 메 터 를 처리 하 는 데 사용 되 는 매크로 로 stdarg.h 파일 에 있 습 니 다.하드웨어 플랫폼 이 다 르 기 때문에 컴 파 일 러 가 다 르 기 때문에 그들의 정의 도 다 르 지만 기본 적 인 사고방식 은 같다.다음은 매크로 에 대한 정의 입 니 다.

typedef char *  va_list;

#define _ADDRESSOF(v)   ( &(v) )

#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

#define va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )

#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

#define va_end(ap) ( ap = (va_list)0 )

이 곳 에 다른 두 개의 매크로 가 도입 되 었 음 을 알 수 있 습 니 다.ADDRESSOF 와INTSIZEOF。
_ADDRESSOF(v)는 변수 주 소 를 가 져 오 는 데 사 용 됩 니 다.한눈 에 알 수 있 습 니 다.
_INTSIZEOF(n)는 정렬 에 사 용 됩 니 다.(정렬 이란 무엇 입 니까?이것 은 스 택 의 구조 로 인해 발생 한 것 입 니 다.32 비트 기기 에서 스 택 의 모든 단원 은 4 개의 바이트 를 차지 합 니 다.이것 은 흔히 int 형의 길이 이지 만 실제 전 달 된 매개 변 수 는 4 개의 바이트 가 아니 거나 4 의 배수 바이트 일 수 있 습 니 다.마치 차 를 탈 때 반 개의 좌석 을 승객 에 게 팔 지 않 는 것 과 같 습 니 다.들 어 오 는 데이터 가 4 개 나 4 의 배수 바이트 에 딱 맞지 않 으 면 정렬(보완)이 필요 합 니 다.이 표현 식 이 왜 정렬 되 는 지 분석 이 필요 합 니 다).
va_start(ap,v)에서 ap 는 가 변 적 인 파 라 메 터 를 가 진 지침 이 고 v 는 마지막 가 변 적 이지 않 은 매개 변수 입 니 다.(valist)_ADDRESSOF(v)는 v 의 주 소 를 가 져 오고 va 로 전환 합 니 다.list 형식의,v 는 마지막 비 가 변 매개 변수 입 니 다.이 예 에서 6 이 어야 합 니 다.위의 그림 에서 스 택 의 낮은 주소 단 을 처리 합 니 다.INTSIZEOF(v)는 정렬 주 소 를 가 져 왔 습 니 다.여 기 는 4,두 개 를 더 한 다음 에 첫 번 째 가 변 매개 변수,즉 위의 그림 의 4 를 가리 키 고 이 값 을 ap 에 부여 한 후에 ap 가 첫 번 째 가 변 매개 변 수 를 가리 키 게 합 니 다.(여기 서 보 듯 이 바list 를 char*로 정의 하 는 것 은 매우 유용 합 니 다.char 길 이 는 하나의 바이트 이기 때문에 포인터 연산 에 편리 합 니 다).
 va_arg(ap,t)에서 ap 는 가 변 매개 변 수 를 가 진 지침 입 니 다.t 는 매개 변 수 를 가 져 올 형식 입 니 다.ap+=INTSIZEOF(t)는 ap 로 하여 금 다음 인 자 를 가리 키 게 합 니 다.그러나 현재 매개 변수의 값 을 가 져 와 야 하기 때문에 표현 식 을 줄 입 니 다.돌아 오 는 것 은 va 입 니 다.list(char*)형의 지침 이 므 로 t*로 전환 한 후 참조 연산 을 하여 현재 매개 변수의 값 을 얻 습 니 다.(여기 ap 를 다음 매개 변 수 를 다시 줄 이 는 작업 이 있 습 니 다.저 는 기분 이 좋 지 않 습 니 다.한편 으로 는 낭비 하 는 조작 이 있 고 성능 에 영향 을 줄 수 있 습 니 다.다른 한편,저 는 현재 값 을 가 져 온 조작 과 다음 작업 을 분리 시 키 고 싶 습 니 다.그러면 프로그래머 가 더 많은 통 제 를 하고 이해 하기 쉽 습 니 다.)
va_end(ap)는 ap 가 빈 주 소 를 가리 키 도록 합 니 다.
상기 분석 을 통 해 알 수 있 듯 이 C 언어 에서 가 변 적 인 파 라 메 터 는 스 택 에서 순서대로 방문 한 것 이 고 과정 에서 사용 하 는 세 개의 매크로 도 조작 에 대한 간단 한 포장 일 뿐 스스로 프로 그래 밍 하여 실현 할 수 있다.그리고 매개 변수의 유형 과 개 수 는 직접적 으로 확정 할 수 없습니다.이 예 에서 VariableArgument Method 의 첫 번 째 매개 변 수 는 매개 변수의 개 수 를 지정 하 는 데 사용 되 고 매개 변수의 유형 은 성형 으로 약정 되 어야 프로그램 이 정상적으로 실 행 될 수 있 습 니 다.그리고 printf 까지 매개 변수의 개 수 를 식별 할 수 있 는 이 유 는...첫 번 째 매개 변수 에서 뒤의 매개 변수의 형식 문자열 을 묘사 해 야 하기 때 문 입 니 다.이것 은 바로 처음에 언급 한 첫 번 째 문제 에서 주의해 야 할 문제 입 니 다.이것 도 많은 사람들 에 게 비난 을 받 는 원인 이지 만,본인 은 이런 방식 이 매우 좋다 고 생각 합 니 다.나중에 자바 와.net 의 실현 방식 과 비교 할 것 입 니 다.
3.자바 와.net 가 변 매개 변 수 를 실현 하 는 방식.
자바 1.5 이후 가 변 매개 변 수 를 지원 합 니 다.문법 은 다음 과 같 습 니 다.

void testMethod(String ... args)
이 방법 에 대해 이렇게 호출 할 수 있 습 니 다.testMethod("gly","zxy","ChenFei");
.net 도 가 변 매개 변 수 를 지원 합 니 다.문법 은 다음 과 같 습 니 다.

void TestMethod(params string[] args)
이 방법 에 대해 서 는 TestMethod("gly","zxy","ChenFei")를 이렇게 호출 할 수 있 습 니 다.
자바 와.net 에서 가 변 매개 변수 에 대한 실현 은 기본적으로 같다.컴 파일 러 는 컴 파일 할 때 방법 서명 중의 가 변 매개 변 수 를 해당 유형의 배열 로 보고 해당 하 는 호출 을 컴 파일 할 때 실제 인삼 에 따라 하나의 배열 을 생 성하 여 매개 변 수 를 배열 에 불 러 와 전달 하 며 가 변 매개 변수 방법의 방법 체 에 서 는 배열 을 사용 하 는 방식 으로 가 변 파 라미 터 를 사용한다.
4.두 가지 실현 방식 의 비교
C 언어의 실현 방식 은 자바.net 의 실현 방식 에 비해 C 언어 는 프로그래머 가 더 많은 일 을 해 야 합 니 다.또한 오류 의 기 회 를 증가 시 켰 습 니 다.자바.net 의 실현 방식 은 매개 변수의 유형 과 개 수 를 쉽게 확정 할 수 있 습 니 다.이러한 C 의 실현 에는 없 지만 자바.net 의 실현 방식 은 임시 배열 을 생 성 합 니 다.물론 자바.net 은 쓰레기 회수 메커니즘 이 있 지만 쓰레기 가 언제 회수 되 는 지 는 확실 하지 않 고 대가 가 매우 크다.쓰레기 수 거 는 좋 은 물건 이지 만 나 는 좋아 하지 않 는 다.나 는 필요 하지 않 은 물건 은 즉시 방출 해 야 한다 고 생각한다.이것 은 완벽 한 표현 이다.C 에 서 는 이 문제 가 없습니다.매개 변수의 개수 와 유형 문 제 는 약정 이나 지정 에 의 해 해결 할 수 있 습 니 다.이 두 문 제 는 자바 와.net 에서 매개 변수 개 수 는 간접 적 으로 전달 되 었 습 니 다(배열 의 길이).매개 변수 유형 은 방법 서명 에서 약정 되 었 습 니 다.물론 자바.net 의 디자인 목 표 는 C 언어 와 달리 말 이 많 습 니 다.

좋은 웹페이지 즐겨찾기