C의 매크로에 괄호가 필요합니다.
매크로의 정의를 사용해 보았습니다.SQR
다음 코드로.
#define SQR(x) (x*x)
int main()
{
int a, b=3;
a = SQR(b+5); // Ideally should be replaced with (3+5*5+3), though not sure.
printf("%d\n",a);
return 0;
}
인쇄합니다.23
. 매크로 정의를 다음으로 변경하는 경우SQR(x) ((x)*(x))
결과는 예상대로입니다.64
. C의 매크로에 대한 호출이 매크로의 정의로 호출을 대체하는 것은 알고 있지만, 아직도 어떻게 계산되었는지 이해할 수 없습니다.23
.
전처리기 매크로는 코드가 컴파일되기 전에 텍스트 교체를 수행합니다.SQR(b+5)
(b+5*b+5) = (6b+5) = 6*3+5 = 23으로 변환
정규 함수 호출은 함수에 전달하기 전에 매개 변수(b+3)의 값을 계산하지만 매크로는 미리 컴파일된 대체이므로 대수적 연산 순서가 매우 중요해집니다.
이 매크로를 사용한 매크로 교체를 고려해 보십시오.
#define SQR(x) (x*x)
사용.b+5
의론으로는교체는 본인이 하세요.당신 코드에 의하면,SQR(b+5)
다음이 됩니다:(b+5*b+5)
, 아니면(3+5*3+5)
. 이제 연산자 우선 순위 규칙을 기억하십시오.*
전에+
. 따라서 이는 다음과 같이 평가됩니다.(3+15+5)
, 아니면23
.
매크로의 두 번째 버전:
#define SQR(x) ((x) * (x))
괄호를 사용하여 연산자 우선 순위의 영향으로부터 매크로 인수를 보호하고 있으므로 정확합니다.
C에 대한 연산자 선호도를 설명하는 이 페이지에는 멋진 차트가 있습니다.다음은 C11 참조 문서의 관련 부분입니다.
여기서 기억해야 할 점은 매크로에서 항상 부모를 사용하여 논쟁을 차단하는 습관을 들여야 한다는 것입니다.
왜냐면(3+5*3+5 == 23)
.
반면에.((3+5)*(3+5)) == 64
.
가장 좋은 방법은 매크로를 사용하지 않는 것입니다.
inline int SQR(int x) { return x*x; }
아니면 그냥 쓰기x*x
.
매크로가 다음으로 확장됩니다.
a = b+5*b+5;
예.
a = b + (5*b) + 5;
그래서 23살.
전처리를 한 후,SQR(b+5)
로 확장될 예정입니다.(b+5*b+5)
. 이것은 분명히 옳지 않습니다.
의 정의에는 두 가지 일반적인 오류가 있습니다.SQR
:
매크로 본문에 매크로의 인수를 괄호 안에 넣지 마십시오. 따라서 해당 인수가 식인 경우 해당 식에 다른 우선 순위가 있는 연산자가 문제를 일으킬 수 있습니다.여기 이 문제를 해결한 버전이 있습니다.
#define SQR(x) ((x)*(x))
매크로의 인수를 한 번 이상 평가합니다. 그래서 만약 그러한 인수가 부작용이 있는 표현이라면, 그러한 부작용은 한 번 이상 취할 수 있습니다.예를 들어, 다음의 결과를 고려합니다.
SQR(++x)
.GCC 타입의 확장을 사용하면 이 문제를 이렇게 해결할 수 있습니다.
#define SQR(x) ({ typeof (x) _x = (x); _x * _x; })
이 두 가지 문제는 매크로를 인라인 함수로 대체하여 해결할 수 있습니다.
inline int SQR(x) { return x * x; }
이를 위해서는 GCC 인라인 확장 또는 C99가 필요합니다. 6.40 인라인 기능은 매크로만큼 빠릅니다.
매크로는 단순한 텍스트 대체입니다.사전 처리 후 코드는 다음과 같습니다.
int main()
{
int a, b=3;
a = b+5*b+5;
printf("%d\n",a);
return 0;
}
덧셈보다 Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ,a
를 추가하면 과 같이 매크로 정의에 괄호를 추가하면 다음과 같이 문제가 해결됩니다.
int main()
{
int a, b=3;
a = (b+5)*(b+5);
printf("%d\n",a);
return 0;
}
곱셈 이 먼저 로 되기 에 에 이 은 을 은 은 을 은 로 은 a = 64
당신이 기대하는 결과.
매크로는 문자열 교체일 뿐이며 완료 프로세스 전에 수행되기 때문입니다.컴파일러는 매크로 변수와 그 값을 볼 기회를 갖지 못합니다.예를 들어, 매크로가 다음과 같이 정의되는 경우
#define BAD_SQUARE(x) x * x
그리고 이렇게 전화를 했습니다.
BAD_SQUARE(2+1)
컴파일러는 이것을 볼 것입니다.
2 + 1 * 2 + 1
예상치 못한 결과가 나올 겁니다
5
이 동작을 수정하려면 항상 다음과 같은 괄호로 매크로 변수를 둘러싸야 합니다.
#define GOOD_SQUARE(x) (x) * (x)
예를 들어, 이 매크로가 이렇게 불릴 때
GOOD_SQUARE(2+1)
컴파일러는 이것을 볼 것입니다.
(2 + 1) * (2 + 1)
결과적으로
9
추가적으로, 여기에 요점을 더 자세히 설명하기 위한 전체 예시가 있습니다.
#include <stdio.h>
#define BAD_SQUARE(x) x * x
// In macros alsways srround the variables with parenthesis
#define GOOD_SQUARE(x) (x) * (x)
int main(int argc, char const *argv[])
{
printf("BAD_SQUARE(2) = : %d \n", BAD_SQUARE(2) );
printf("GOOD_SQUARE(2) = : %d \n", GOOD_SQUARE(2) );
printf("BAD_SQUARE(2+1) = : %d ; because the macro will be \
subsituted as 2 + 1 * 2 + 1 \n", BAD_SQUARE(2+1) );
printf("GOOD_SQUARE(2+1) = : %d ; because the macro will be \
subsituted as (2 + 1) * (2 + 1) \n", GOOD_SQUARE(2+1) );
return 0;
}
매크로 확장에 있는 각 인수를 괄호로 묶기만 하면 됩니다.
#define SQR(x) ((x)*(x))
이것은 당신이 어떤 논쟁이나 가치를 전달하든 효과가 있을 것입니다.
언급URL : https://stackoverflow.com/questions/10820340/the-need-for-parentheses-in-macros-in-c
'programing' 카테고리의 다른 글
예상치 못한 쿼리 성공 (0) | 2023.09.16 |
---|---|
구체화된 뷰의 커밋 시 빠른 새로 고침 (0) | 2023.09.16 |
Watch file for changes and run command with powershell (0) | 2023.09.16 |
프로그래밍 방식으로 "select file(파일 선택)" 대화 상자 트리거 (0) | 2023.09.16 |
Angular2 - 앱 외부에서 컴포넌트 기능 호출 방법 (0) | 2023.09.16 |