programing

C의 매크로에 괄호가 필요합니다.

oldcodes 2023. 9. 16. 09:53
반응형

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:

  1. 매크로 본문에 매크로의 인수를 괄호 안에 넣지 마십시오. 따라서 해당 인수가 식인 경우 해당 식에 다른 우선 순위가 있는 연산자가 문제를 일으킬 수 있습니다.여기 이 문제를 해결한 버전이 있습니다.

    #define SQR(x) ((x)*(x))
    
  2. 매크로의 인수를 한 번 이상 평가합니다. 그래서 만약 그러한 인수가 부작용이 있는 표현이라면, 그러한 부작용은 한 번 이상 취할 수 있습니다.예를 들어, 다음의 결과를 고려합니다.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

반응형