가장 음의 int 값이 모호한 함수 오버로드에 대한 오류를 일으키는 이유는 무엇입니까?


91

나는 C ++에서 함수 오버로딩에 대해 배우고 있는데 이것을 발견했습니다.

void display(int a)
{
    cout << "int" << endl;
}

void display(unsigned a)
{
    cout << "unsigned" << endl;
}

int main()
{
    int i = -2147483648;
    cout << i << endl; //will display -2147483648
    display(-2147483648);
}

내가 이해 한 바에 따르면 int범위 (제 경우 int에는 4 바이트) 에 제공된 모든 값 이 호출 display(int)되고이 범위를 벗어난 값은 모호합니다 (컴파일러가 호출 할 함수를 결정할 수 없기 때문에). int최소값을 제외한 전체 값 범위에 대해 유효합니다. 즉 -2147483648컴파일이 오류와 함께 실패하는 경우

과부하 호출 display(long int)이 모호합니다.

그러나 동일한 값을 an에 취하고 값을 int인쇄하면 2147483648. 나는이 행동과 문자 그대로 혼동된다.

이 동작은 가장 많은 음수가 전달 될 때만 관찰되는 이유는 무엇입니까? ( 사실 음수와 양수가 동일한 이진 표현을 갖는 경우에 a short와 함께 사용되는 경우 동작은 동일합니다. -32768)

사용 된 컴파일러 : g ++ (GCC) 4.8.5


4
Int의 최소값은 "컴파일러 오류 발생"입니다. 무슨 오류? 질문에 포함시켜야합니다
Justin

11
알겠습니다 call of overloaded ‘display(long int)’ is ambiguous.
crashmstr

6
관련이 없지만 컴파일러를 업데이트해야합니다. 이미 GCC 7.1이 있습니다.
HolyBlackCat

4
내 추측은 다음과 같습니다 typeof(-2147483648) != int. 리터럴은 2147483648이며 int, 그래서 a long이고 부정됩니다
Justin

3
흥미롭게도 g ++ (적어도 6.4 및 7.1)은 int j{-2147483648};축소 변환 이라고 불평하지 않습니다 . 그 자체로 질문의 가치가 거의 있습니다. 이는 아마도 초기화에서 좁혀지는 long long것과 같은 constexpr 값 을 허용하는 것과 관련이있을 것입니다 2147483647LL.
Toby Speight

답변:


145

이것은 매우 미묘한 오류입니다. 지금보고있는 것은 C ++에 음의 정수 리터럴이 없기 때문입니다. [lex.icon]을 보면 정수 리터럴을 얻습니다 .

정수 리터럴
        10 진수 리터럴 정수 접미사 opt
        [...]

10 진수 리터럴 일 수 있습니다.

decimal-literal :
        0이 아닌
        10 진수 리터럴 ' opt digit

여기서 자리 이다 [0-9]0이 아닌 숫자는 이다 [1-9]접미사 파 중 하나 일 수있다 u, U, l, L, ll, 또는 LL. 여기 어디에도 -십진 리터럴의 일부가 포함 되어 있지 않습니다 .

§2.13.2에는 다음도 포함됩니다.

정수 리터럴은 그 값을 결정할 때 무시됩니다 선택적 분리 따옴표로, 어떤 기간 또는 지수 부분이없는 숫자의 순서입니다. 정수 리터럴에는 기본을 지정하는 접두사와 유형을 지정하는 접미사가있을 수 있습니다. 숫자 시퀀스의 어휘 첫 번째 숫자가 가장 중요합니다. 진수 정수 리터럴 (베이스 열)는 0이 아닌 숫자로 시작 및 십진수의 시퀀스로 구성된다.

(강조 내)

이는 -in -2147483648이 단항 임을 의미합니다 operator -. 즉, -2147483648실제로 -1 * (2147483648). 2147483648하나가 너무 많기 때문에 inta로 승격되고 long int모호성은 일치하지 않는 것에서 비롯됩니다.

이식 가능한 방식으로 유형의 최소 또는 최대 값을 얻으려면 다음을 사용할 수 있습니다.

std::numeric_limits<type>::min();  // or max()

2
-2147483647 - 1음의 문자 표현으로 경고없이 작업도 것
쾨르

2
또는 INT_MIN가장 간단한 옵션을 선택하십시오. 하지만 덜 일반적입니다.
MSalters

@NathanOliver,이 사건을 친절하게 설명해 주시겠습니까 display(2147483649);? 이 경우 서명되지 않은 int func를 호출 할 수없는 이유는 무엇입니까? 왜 2147483649unsigned int 대신에 arg 를 long int로 취급 합니까?
무한 루프

2
@infiniteloop 십진 정수 리터럴은에서 int으로 이동 long int합니다 long long int. u/ U접미사 를 사용하지 않는 한 십진 리터럴에 대해 서명되지 않은 유형을 얻지 못합니다 .
NathanOliver

2
이 예에서는 그렇습니다. 호출 방법은 display(unsigned a)당신도 필요 display(1234u);하거나 display(static_cast<unsigned>(1234));또는unsigned foo = 1234; display(foo);
NathanOliver

36

표현식 -2147483648은 실제로 -연산자를 상수에 적용합니다 2147483648. 플랫폼에서 int저장할 수 없으며 2147483648더 큰 유형으로 표시되어야합니다. 따라서 식은 더 큰 부호있는 유형으로 -2147483648추론되지 않습니다 signed int.signed long int .

long컴파일러에 대한 오버로드를 제공하지 않기 때문에 똑같이 유효한 두 오버로드 중에서 선택해야합니다. 컴파일러는 모호한 오버로드에 대한 컴파일러 오류를 발행해야합니다.


4

타인의 답변 확대


OP가 혼란스러운 이유를 명확히하기 위해 먼저 아래 의 signed int이진 표현을 고려하십시오 2147483647.

가장 큰 부호있는 정수




다음으로,이 번호에 1을 추가 : 또 다른주기 signed int-2147483648(영업 이익이 사용하고자하는) 가장 작은 부호있는 정수



마지막으로 , OP가 -2147483648a long int대신 a로 컴파일 될 때 왜 혼란 스러울 지 알 수 있습니다 signed int. 32 비트에 확실히 들어 맞기 때문입니다.

현재 답변들을 언급하지만, 단항 연산자 ( -)인가 이후 해결 2147483648을 인 long int32 비트에 맞지 않는다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.