code

컴파일러는 여기서 무엇을합니까 : int a = b * (c * d * + e)?

codestyles 2020. 10. 23. 07:55
반응형

컴파일러는 여기서 무엇을합니까 : int a = b * (c * d * + e)?


이 질문에 이미 답변이 있습니다.

프로그램에 이상한 버그가 생겼고 몇 시간 동안 디버깅 한 후 다음과 같은 매우 멍청한 줄을 발견했습니다.

int a = b * (c * d *  + e)

당신은 그것을 표시되지 않는 경우 : 사이 de내가 쓴 * +단지는 어디 +예정되었다.

왜 이것이 컴파일되고 실제로 무엇을 의미합니까?


+단항 플러스 연산자로 해석됩니다. 단순히 피연산자 승격 된 값을 반환합니다 .


단항 +은 승격 된 값을 반환합니다.
단항 -은 부정을 반환합니다.

int a = 5;
int b = 6;
unsigned int c = 3;

std::cout << (a * +b); // = 30
std::cout << (a * -b); // = -30
std::cout << (1 * -c); // = 4294967293 (2^32 - 3)

+는 정수 또는 열거 유형에 대한 정수 승격을 수행하고 승격 된 피연산자의 유형을 갖는 단항 더하기로 해석 되기 때문에 컴파일됩니다 .

e정수 또는 범위가 지정되지 않은 열거 유형 이라고 가정하면 일반적인 산술 변환 을 피연산자에 *적용하여 정수 유형에 대한 정수 프로모션으로 끝나기 때문에 어쨌든 정수 프로모션이 적용 됩니다 .

초안 C ++ 표준 5.3.1 [expr.unary.op]에서 :

단항 + 연산자의 피연산자는 산술, 범위가 지정되지 않은 열거 또는 포인터 유형을 가져야하며 결과는 인수의 값입니다. 적분 승격은 적분 또는 열거 피연산자에서 수행됩니다. 결과 유형은 승격 된 피연산자의 유형입니다.

통합 프로모션은 4.5 [conv.prom] 섹션에서 다루고 변수 eint 이외의 유형 bool, char16_t, char32_t, or wchar_t이고 변환 순위가 int 보다 작은 경우 다음 단락으로 처리됩니다 1.

정수 변환 순위 (4.13)가 int의 순위보다 작은 bool, char16_t, char32_t 또는 wchar_t 이외의 정수 유형의 prvalue는 int가 소스 유형의 모든 값을 나타낼 수있는 경우 int 유형의 prvalue로 변환 될 수 있습니다. ; 그렇지 않으면 소스 prvalue를 unsigned int 유형의 prvalue로 변환 할 수 있습니다.

완전한 케이스 세트에 대해서는 cppreference를 볼 수 있습니다 .

단항 더하기는 모호성을 해결하기 위해 일부 경우에 유용 할 수도 있습니다. 흥미로운 경우는 +를 사용하여 람다에 대한 함수 포인터 및 std :: function에 대한 모호한 오버로드 해결 에서 찾을 수 있습니다 .

단항 -및 음수 값을 참조하는 해당 답변의 경우 다음 예제에서 볼 수 있듯이 잘못된 것입니다.

#include <iostream>

int main()
{
    unsigned  x1 = 1 ;

    std::cout <<  -x1 << std::endl ;
}

결과 :

4294967295

wandbox에서 gcc를 사용하여 실시간 으로 확인하세요 .

국제 표준에 대한 이론적 근거 — 프로그래밍 언어 —C :

C89위원회는 단항 마이너스와의 대칭을 위해 여러 구현에서 단항 플러스를 채택했습니다.

캐스팅만으로는 원하는 프로모션 / 전환을 달성하기에 충분하지 않은 좋은 사례를 찾을 수 없습니다. 위에서 인용 한 람다 예제는 단항 더하기를 사용하여 람다식이 함수 포인터로 변환되도록 강제합니다.

foo( +[](){} ); // not ambiguous (calls the function pointer overload)

명시 적 캐스트를 사용하여 수행 할 수 있습니다.

foo( static_cast<void (*)()>( [](){} ) );

의도가 명시 적이기 때문에이 코드가 더 낫다고 주장 할 수 있습니다.

가치 지적이 주석 C ++ 참조 설명서 ( ARM ) 는 다음과 같은 해설이 있습니다 :

단항 플러스는 역사적인 사고이며 일반적으로 쓸모가 없습니다.


그들이 설명했듯이 (+)와 (-)는 단항 연산자로 사용되었습니다.

단항 연산자 는 표현식에서 하나의 피연산자에만 작동합니다.

int value = 6;
int negativeInt = -5;
int positiveInt = +5;

cout << (value * negativeInt); // 6 * -5 = -30
cout << (value * positiveInt); // 6 * +5 = 30

cout << (value * - negativeInt); // 6 * -(-5) = 30
cout << (value * + negativeInt); // 6 * +(-5) = -30

cout << (value * - positiveInt); // 6 * -(+5) = -30
cout << (value * + positiveInt); // 6 * +(+5) = 30

그래서 당신의 코드에서 :

int b = 2;
int c = 3;
int d = 4;
int e = 5;

int a = b * (c * d *  + e)

//result: 2 * (3 * 4 * (+5) ) = 120

왜 컴파일됩니까? +더하기 연산자가 아니라 단항 더하기 연산자로 구문 분석 되기 때문에 컴파일됩니다 . 컴파일러는 구문 오류를 생성하지 않고 가능한 한 많이 구문 분석을 시도합니다. 그래서 이거:

d * + e

다음과 같이 구문 분석됩니다.

  • d (피연산자)
  • * (곱하기 연산자)
  • + (단항 더하기 연산자)
    • e (피연산자)

반면, 이것은 :

d*++e;

다음과 같이 구문 분석됩니다.

  • d (피연산자)
  • * (곱하기 연산자)
  • ++ (사전 증분 연산자)
    • e (피연산자)

또한 이것은 :

d*+++e;

다음과 같이 구문 분석됩니다.

  • d (피연산자)
  • * (곱하기 연산자)
  • ++ (사전 증분 연산자)
    • + (단항 더하기 연산자)
      • e (피연산자)

구문 오류가 아니라 "LValue requrired"컴파일러 오류가 발생합니다.


To put a further twist on the correct answers already given here, if you compile with the -s flag, the C compiler will output an assembly file in which actual the instructions generated can be examined. With the following C code:

int b=1, c=2, d=3, e=4;
int a = b * (c * d *  + e);

The generated assembly (using gcc, compiling for amd64) begins with:

    movl    $1, -20(%ebp)
    movl    $2, -16(%ebp)
    movl    $3, -12(%ebp)
    movl    $4, -8(%ebp)

so we can identify individual memory positions -20(%ebp) as variable b, down to -8(%ebp) as variable e. -4(%epp) is variable a. Now, the calculation is rendered as:

    movl    -16(%ebp), %eax
    imull   -12(%ebp), %eax
    imull   -8(%ebp), %eax
    imull   -20(%ebp), %eax
    movl    %eax, -4(%ebp)

So, as has been commented by other people replying, the compiler simply treats "+e" as the unary positive operation. The first movl instruction places the contents of variable e into the EAX accumulator register, which is then promptly multiplied by the contents of variable d or -12(%ebp), etc.


This is just basic math. For example:

5 * -4 = -20

5 * +4 = 5 * 4 = 20 

-5 * -4 = 20

Negative * Negative = Positive

Positive * Negative = Negative

Positive * Positive = Positive

This is the easiest explanation there is.

The minus(-) and plus(+) just tell if the number is positive or negative.


The + operator between d and e will be treated as an unary + operator which will determine only sign of e. So the compiler will see this statement as follow:

int a = b*(c*d*e) ;

참고URL : https://stackoverflow.com/questions/30361112/what-does-the-compiler-do-here-int-a-b-c-d-e

반응형