나는 매크로 개념을 잘 이해하지 못한다. 매크로 란 무엇입니까? 기능과 다른 점을 이해하지 못합니까? 함수와 매크로 모두 코드 블록을 포함합니다. 매크로와 기능은 어떻게 다릅니 까?
나는 매크로 개념을 잘 이해하지 못한다. 매크로 란 무엇입니까? 기능과 다른 점을 이해하지 못합니까? 함수와 매크로 모두 코드 블록을 포함합니다. 매크로와 기능은 어떻게 다릅니 까?
답변:
이 답변에서 편광 투표 패턴을 관찰 한 후 다음 설명을 추가하고 싶습니다.
기술적 정확성과 광범위한 일반화를 염두에두고 답변을 작성하지 않았습니다. 완전하거나 정확하게 (실제로 정확하지는 않음) 시도하지 않고 간단한 언어로, 매크로와 함수의 차이점을 프로그래밍 초보자와 설명하려는 겸손한 시도였습니다. 답변을 작성할 때 C 프로그래밍 언어가 마음에 들었습니다. 그러나 명확하게 언급하지 않고 (잠재적) 혼란을 초래 한 것에 대해 사과드립니다.
Jörg W Mittag가 공유 한 답변을 정말 고려합니다 . 통찰력이있는 책을 읽고 (내가 아는 것이 적음) 게시 된 직후에 그것을 올렸습니다. 방금 Software Engineering Stack Exchange를 시작했으며 지금까지의 경험과 토론은 정말 통찰력이 있습니다.
이 답변은 다른 소프트웨어 개발 초보자에게 도움이 될 수 있으므로 기술적 정확성에 얽매이지 않고 개념을 이해하려고 노력하므로 여기에 남겨 두겠습니다.
매크로와 함수는 모두 자체 포함 된 코드 단위를 나타냅니다. 둘 다 프로그램의 모듈 식 설계를 돕는 도구입니다. 소스 코드를 작성하는 프로그래머의 관점에서 보면 그들은 매우 비슷하게 보입니다. 그러나 프로그램 실행 수명주기 동안 처리 방식이 다릅니다.
매크로는 한 번만 정의되며 프로그램의 많은 곳에서 사용됩니다. 사전 처리 단계에서 매크로가 인라인으로 확장됩니다. 따라서 소스 코드가 컴파일되면 기술적으로 별도의 엔티티로 유지되지 않습니다. 매크로 정의의 명령문은 다른 명령문과 마찬가지로 프로그램 명령의 일부가됩니다.
매크로 작성의 동기는 프로그래머가 소스 코드를보다 쉽게 작성하고 관리 할 수 있도록하는 것입니다. 본격적인 기능을 작성하는 것이 성능 오버 헤드 / 런타임 패널티가되는 간단한 작업에는 일반적으로 매크로가 필요합니다. 매크로가 기능보다 선호되는 상황의 예는 다음과 같습니다.
상수 값 (수학적 또는 과학적 값과 같은) 또는 일부 프로그램 특정 매개 변수를 사용합니다.
로그 메시지 인쇄 또는 어설 션 처리
간단한 계산 또는 조건 확인 수행
매크로를 사용할 때 프로그램에서 매크로가 사용되는 모든 곳에서 즉시 사용할 수있는 한 곳에서 변경 / 수정을 쉽게 수행 할 수 있습니다. 변경 사항을 적용하려면 간단한 프로그램 재 컴파일이 필요합니다.
반면에 기능 코드는 프로그램 내에서 별도의 단위로 컴파일되며 필요한 경우에만 프로그램 실행 중에 메모리에로드됩니다. 함수 코드는 프로그램의 나머지 부분과 독립된 ID를 유지합니다. 함수가 두 번 이상 호출되면로드 된 코드가 재사용됩니다. 실행중인 프로그램에서 함수 호출이 발생하면 런타임 서브 시스템이 제어를 전달하고 실행중인 프로그램의 컨텍스트 (반환 명령 주소)가 유지됩니다.
그러나 함수를 호출 할 때 (컨텍스트 전환, 주 프로그램 명령어의 리턴 주소 유지, 매개 변수 전달 및 리턴 값 처리 등) 약간의 성능 저하가 발생합니다. 따라서 함수의 사용은 복잡한 코드 블록 (단순한 경우를 처리하는 매크로에 대해서만)에만 필요합니다.
경험을 가진 프로그래머는 코드 조각이 전체 프로그램 아키텍처에서 매크로 또는 함수로 적합한 지 여부를 신중하게 결정합니다.
불행히도, 프로그래밍에서 "매크로"라는 용어는 여러 가지로 사용됩니다.
Lisp 계열 언어와 그 언어에서 영감을 얻은 언어뿐만 아니라 Scala 및 Haskell과 같은 많은 현대적 기능 또는 기능에서 영감을 얻은 언어와 Boo와 같은 명령형 언어에서 매크로는 컴파일 타임에 실행 되는 코드 조각입니다. (또는 컴파일러가없는 구현의 경우 적어도 런타임 전에) 추상 구문 트리 (또는 특정 언어의 동등한 것이 무엇이든간에, 예를 들어 Lisp에서는 S- 표현식)를 컴파일하는 동안 다른 것으로 변환 할 수 있습니다. 예를 들어, 많은 Scheme 구현 for
에서 본문에 대한 여러 호출로 확장되는 매크로가 있습니다. 정적으로 형식화 된 언어에서 매크로는 종종 형식에 안전합니다. 즉, 형식이 잘못된 코드를 생성 할 수 없습니다.
C 언어 군에서 매크로는 텍스트 대체와 비슷합니다. 또한 형식이 잘못되었거나 구문 적으로 합법적이지 않은 코드를 생성 할 수 있습니다.
매크로 어셈블러에서 "매크로"는 "가상 명령어", 즉 CPU가 기본적으로 지원하지 않지만 유용하다는 명령어를 참조하므로 어셈블러에서는 이러한 명령어를 사용할 수 있으며 CPU가 이해하는 여러 명령어로 확장 할 수 있습니다 .
응용 프로그램 스크립팅에서 "매크로"는 사용자가 "기록"및 "재생"할 수있는 일련의 작업을 나타냅니다.
그것들 모두는 어떤 의미에서 실행 가능한 코드이며, 어떤 의미에서는 함수로 볼 수 있습니다. 그러나 Lisp 매크로의 경우 입력 및 출력은 프로그램 조각입니다. C의 경우 입력 및 출력은 토큰입니다. 처음 세 개는 또한 컴파일 타임에 실행된다는 매우 중요한 차이점이 있습니다 . 실제로 이름에서 알 수 있듯이 C 전 처리기 매크로는 실제로 코드가 컴파일러에 도달하기 전에 실행 됩니다 .
C 언어 제품군에서 매크로 정의 , 전 처리기 명령 은 정의에서 컴파일되지 않고 매크로 호출 에서 대체되는 매개 변수화 된 코드 템플릿을 지정합니다 . 즉, 모든 자유 변수는 매크로 호출 컨텍스트에서 바인딩되어야합니다. 매개 변수를 여러 번 사용하여 부작용이있는 매개 변수 인수를 i++
반복 할 수 있습니다. 1 + 2
일부 매개 변수 의 인수 를 텍스트로 대체 x
하면 컴파일 전에 발생하며 예기치 않은 동작 x * 3
( 7
io 9
) 이 발생할 수 있습니다 . 매크로 정의에서 매크로 본문의 오류는 매크로 호출에서 컴파일 할 때만 표시됩니다.
함수 정의 함수 본문 컨텍스트 결합 자유 변수로 지정 코드; 함수 호출이 아닙니다 .
그러나 매크로는 음수 인 것처럼 보이기 때문에 호출, 행 번호 및 소스 파일, 인수를 string으로 액세스 할 수 있습니다.
좀 더 추상적 인 용어로, 매크로는 함수가 데이터에 대한 것이므로 구문을 분석하는 것입니다. 함수 (추상)는 데이터의 일부 변환을 캡슐화합니다. 인수를 평가 된 데이터로 사용하고 일부 조작을 수행하며 데이터이기도 한 결과를 리턴합니다.
대조적으로 매크로는 평가되지 않은 구문을 사용 하여 작동합니다. C와 유사한 언어의 경우 구문은 토큰 수준에서 제공됩니다. LISP와 유사한 매크로가있는 언어의 경우 구문이 AST로 표시됩니다. 매크로는 새로운 구문을 반환해야합니다.
매크로는 일반적으로 무언가를 의미 장소에서 확장 컴파일 또는 대상 언어의 개별 지침 - 사전 처리하는 동안 매크로 "전화를"대체. 런타임에는 일반적으로 매크로가 시작하고 끝나는 위치가 표시되지 않습니다.
이것은 서브 루틴 과 는 별개입니다. 서브 루틴 은 메모리에 별도로 위치한 재사용 가능한 코드 조각으로 런타임에 제어가 전달됩니다 . 대부분의 프로그래밍 언어에서 "기능", "프로 시저"및 "방법"이이 범주에 속합니다.
Jörg W Mittag의 답변 에서 알 수 있듯이 정확한 세부 사항은 언어마다 다릅니다. C와 같은 일부 언어에서는 매크로가 소스 코드에서 텍스트 대체를 수행합니다. Lisp와 같은 일부에서는 추상 구문 트리와 같은 중개 양식의 조작을 수행합니다. 회색 영역도 있습니다. 일부 언어에는 함수와 같이 정의되지만 매크로와 같이 컴파일 된 프로그램으로 확장되는 "인라인 함수"에 대한 표기법이 있습니다.
대부분의 언어는 프로그래머가 입력 및 출력에 대한 유형 계약을 정의하고 호출 코드에 대한 기타 정보를 숨기고 각 서브 루틴에 대해 추론하도록 권장합니다. 매크로가 발생하지 않는 서브 루틴을 호출하면 성능에 영향을주는 경우가 많으며 매크로는 서브 루틴이 할 수없는 방식으로 프로그램을 조작 할 수 있습니다. 따라서 매크로는 덜 추상적 인 방식으로 작동하기 때문에 서브 루틴보다 "낮은 수준"으로 간주 될 수 있습니다.
컴파일 중에 매크로가 실행되고 런타임에 기능이 실행됩니다.
예:
#include <stdio.h>
#define macro_sum(x,y) (x+y)
int func_sum(x,y) {
return x+y;
}
int main(void) {
printf("%d\n", macro_sum(2,3));
printf("%d\n", func_sum(2,3));
return 0;
}
따라서 컴파일하는 동안 코드는 실제로 다음과 같이 변경됩니다.
#include <stdio.h>
int func_sum(x,y) {
return x+y;
}
int main(void) {
printf("%d\n", (2+3));
printf("%d\n", func_sum(2,3));
return 0;
}