C ++ 연산자의 암시 적 유형 변환 규칙


167

언제 캐스팅해야하는지 알고 싶습니다. 더하기, 곱하기 등을 할 때 C ++의 암시 적 유형 변환 규칙은 무엇입니까?

int + float = ?
int * float = ?
float * int = ?
int / float = ?
float / int = ?
int / int = ?
int ^ float = ?

등등...

표현이 항상 더 정확한 유형으로 평가됩니까? Java에 대한 규칙이 다릅니 까? 이 질문에 부정확하게 표현한 경우 수정하십시오.


15
명심는 ^XOR입니다.
GManNickG

15
@int ^ float = 컴파일 오류 :)
Serge Dundich

답변:


223

C ++ 연산자 (POD 유형의 경우)는 항상 동일한 유형의 객체에서 작동합니다.
따라서 동일하지 않은 경우 다른 것과 일치하도록 승격됩니다.
연산 결과의 유형은 피연산자와 같습니다 (변환 후).

If either is      long          double the other is promoted to      long          double
If either is                    double the other is promoted to                    double
If either is                    float  the other is promoted to                    float
If either is long long unsigned int    the other is promoted to long long unsigned int
If either is long long          int    the other is promoted to long long          int
If either is long      unsigned int    the other is promoted to long      unsigned int
If either is long               int    the other is promoted to long               int
If either is           unsigned int    the other is promoted to           unsigned int
If either is                    int    the other is promoted to                    int
Both operands are promoted to int

노트. 작업의 최소 크기는입니다 int. 따라서 작업이 완료되기 전에 short/ char으로 승격 int됩니다.

모든 표현식 에서 작업이 수행되기 전에 int가로 승격됩니다 float. 작업 결과는 float입니다.

int + float =>  float + float = float
int * float =>  float * float = float
float * int =>  float * float = float
int / float =>  float / float = float
float / int =>  float / float = float
int / int                     = int
int ^ float =>  <compiler error>

1
"최소 작업 크기는 int입니다." -이것은 매우 이상합니다 (char / short 연산을 효율적으로 지원하는 아키텍처는 어떻습니까?) 이것은 실제로 C ++ 사양에 있습니까?
Rafał Dowgird

3
@Rafal : 그렇습니다. int는 특정 플랫폼에서 작동하기에 가장 효율적인 정수 유형이어야합니다. char은 항상 1이어야하지만 short는 int와 같은 크기 일 수 있습니다.
Martin York

1
@ Rafał : 예, 그것은 매우 이상하며 표준입니다. 대부분의 경우 설명하는 아키텍처는 매우 효율적인 char유형을 사용할 수 있습니다 . 의 값이 char + char에 할당 char되면 산술 char및 랩 어라운드 등을 수행 할 수 있습니다 . 그러나 결과가 할당 int되면보다 큰 경우 올바른 결과를 얻을 수있을 정도로 큰 유형으로 산술을 수행해야합니다 CHAR_MAX.
Steve Jessop

2
나는 단지 int가 unsigned int로 승격 된다는 사실을 강조하고 싶습니다 !!! 부정적인 결과가 언더 플로 / 랩 어라운드를 유발하지 않도록 둘 다 int 또는 long 으로 승격 될 것이라는 인상을 받았기 때문에 며칠 동안 버그로 어려움을 겪었습니다 .
nitsas

10
문제의 예 " INT는 부호없는 INT로 승격됩니다 " ((int) 4) - ((unsigned int) 5)가 발생합니다 429496729532 개 비트의 int 32 비트 부호의 int합니다.
nitsas

33

float결과 와 관련된 산술 연산 float.

int + float = float
int * float = float
float * int = float
int / float = float
float / int = float
int / int = int

자세한 내용은 답변을 참조하십시오. C ++ 표준의 §5 / 9 섹션에 나와있는 내용을보십시오

산술 또는 열거 유형의 피연산자를 기대하는 많은 이진 연산자는 비슷한 방식으로 변환을 유발하고 결과 유형을 생성합니다. 목적은 결과의 유형이기도 한 공통 유형을 생성하는 입니다.

이 패턴을 일반적인 산술 변환이라고하며 다음과 같이 정의됩니다.

— 피연산자 중 하나가 long double 유형 인 경우 다른 피연산자는 long double로 변환됩니다.

— 그렇지 않으면 두 피연산자가 두 배인 경우 다른 피연산자가 두 배로 변환됩니다.

— 그렇지 않으면, 피연산자 중 하나가 float이면 다른 피연산자가 float로 변환됩니다.

— 그렇지 않으면, 적분 프로모션 (4.5)은 두 피연산자 모두에서 수행되어야합니다 .54)

— 그런 다음 어느 피연산자가 부호없는 long이면 다른 피연산자는 부호없는 long으로 변환됩니다.

— 그렇지 않으면, 하나의 피연산자가 long int이고 다른 피연산자가 int이면 long int가 unsigned int의 모든 값을 나타낼 수 있으면 unsigned int는 long int로 변환됩니다. 그렇지 않으면 두 피연산자가 부호없는 long int로 변환됩니다.

— 그렇지 않으면, 피연산자가 길면 다른 피연산자는 long으로 변환됩니다.

— 그렇지 않으면, 피연산자가 서명되지 않은 경우, 다른 피연산자는 서명되지 않은 것으로 변환됩니다.

[참고 : 그렇지 않으면, 남은 유일한 경우는 두 피연산자가 모두 int입니다]


3
... 너무 오래 다른 유형도 같이 double아니다 long double.
CB Bailey

1
@ 찰스 : 맞습니다. 더 명확하게하기 위해 표준에서 관련 섹션을 인용했습니다.
Nawaz

그렇다면 데이터 손실없이 항상 정수를 부동 소수점으로 변환 할 수 있습니까? (예를 들어 지수를 0으로하고 가수를 위해 모든 것을 사용함으로써)?
Marco A.

1
답변이 오래되었습니다. 업데이트 제안. 특히, long long그리고 unsigned long바로 여기에 언급되지.
chux-복원 Monica Monica

@MarcoA. 32 비트 float는 32 비트에 대한 가수에 충분한 비트 ( IEEE-754의 경우 24 비트 ) int가 없으므로 일부 데이터가 손실 될 수 있습니다. 64 비트 double는 괜찮습니다.
마크 랜섬

17

다른 답변은 C ++ 11의 규칙에 대해 이야기하지 않기 때문에 여기에 하나가 있습니다. C ++ 11 표준 (초안 n3337) §5 / 9 (차이를 강조)에서 :

이 패턴을 일반적인 산술 변환 이라고 하며 다음과 같이 정의됩니다.

— 피연산자가 범위 열거 유형 인 경우 변환이 수행되지 않습니다. 다른 피연산자가 동일한 유형을 가지지 않으면 표현식의 형식이 잘못됩니다.

— 피연산자 중 하나가 long double 유형 인 경우 다른 피연산자는 long double로 변환됩니다.

— 그렇지 않으면 두 피연산자가 두 배인 경우 다른 피연산자가 두 배로 변환됩니다.

— 그렇지 않으면, 피연산자 중 하나가 float이면 다른 피연산자가 float로 변환됩니다.

— 그렇지 않으면, 적분 프로모션은 두 피연산자 모두에서 수행되어야합니다. 그런 다음 승격 된 피연산자에 다음 규칙이 적용됩니다.

— 두 피연산자의 유형이 모두 같으면 더 이상 변환 할 필요가 없습니다.

— 그렇지 않으면 두 피연산자가 부호있는 정수 유형을 가지거나 부호없는 정수 유형을 갖는 경우, 정수 변환 순위가 낮은 유형의 피연산자는 순위가 더 큰 피연산자의 유형으로 변환됩니다.

— 그렇지 않으면 부호없는 정수 유형을 가진 피연산자가 다른 피연산자의 유형 순위보다 크거나 같은 경우 부호있는 정수 유형을 가진 피연산자는 부호없는 정수 유형을 가진 피연산자의 유형으로 변환됩니다.

— 그렇지 않으면 부호있는 정수 유형의 피연산자 유형이 부호없는 정수 유형의 피연산자 유형의 모든 값을 나타낼 수 있으면 부호없는 정수 유형의 피연산자는 부호있는 정수 유형의 피연산자 유형으로 변환됩니다.

— 그렇지 않으면 두 피연산자는 부호있는 정수 유형의 피연산자 유형에 해당하는 부호없는 정수 유형으로 변환됩니다.

자주 업데이트되는 목록 은 여기 를 참조 하십시오 .


1
물론 C ++ 11에 추가 된 범위 열거를 제외하고는 모든 버전의 C ++에서이 규칙이 동일했습니다.
MM

6

이 답변은 @ RafałDowgird의 의견에서 대부분 지시됩니다.

"최소 작업 크기는 int입니다." -이것은 매우 이상합니다 (char / short 연산을 효율적으로 지원하는 아키텍처는 어떻습니까?) 이것은 실제로 C ++ 사양에 있습니까?

C ++ 표준에는 모든 "as-if"규칙이 있습니다. 섹션 1.8 : 프로그램 실행 참조 :

3)이 규정은 때때로 "현상태대로"규칙이라고 불리우는 데, 그 결과는 관찰 가능한 것으로부터 결정될 수있는 한, 요구 사항이 준수 된 것처럼 결과가 표준의 요구 사항을 자유롭게 무시할 수 있기 때문이다. 프로그램의 행동.

int표준에서 최소 16 비트를 요구하므로 컴파일러는 가장 빠르더라도 크기를 8 비트로 설정할 수 없습니다 int.

따라서 초고속 8 비트 연산을 사용하는 이론적 인 컴퓨터의 경우 int산술 에 대한 암시 적 승격 이 중요 할 수 있습니다. 그러나 많은 연산의 경우 컴파일러가 실제로 연산을 정밀 정밀도로 수행 한 int다음 char변수로 저장 하기 위해 변환 하여 변수가 char 인지 여부를 알 수 없습니다 .

예를 들어, unsigned char = unsigned char + unsigned char + unsigned char더하기가 오버플로되는 곳을 고려하십시오 (각각 200의 값으로 가정). 로 승격 int하면 600을 얻습니다. 이로 암시 적으로 다운로 캐스팅되어 unsigned char모듈로 256을 래핑하여 최종 결과는 88이됩니다. 그러한 승격을하지 않은 경우 첫 번째 사이를 래핑해야합니다 에서 문제를 줄일 두 개의 추가, 200 + 200 + 200144 + 200컴파일러에 중간 작업을 수행 할 의무를 무시하는 무료 그래서 즉 88로 줄일 수 344 인,,, 프로그램은 그 차이를 알 수없는 int피연산자가있는 경우 보다 낮은 순위 int입니다.

이것은 일반적으로 더하기, 빼기 및 곱셈에 해당됩니다. 분할 또는 계수에 대해서는 일반적으로 사실이 아닙니다.


4

부호없는 유형을 제외하면 부호있는 char, short, int, long, long long, float, double, long double의 순서가있는 계층이 있습니다. 먼저 위의 int 앞에 오는 것은 int로 변환됩니다. 그런 다음 이진 연산에서 순위가 ​​낮은 유형이 더 높은 유형으로 변환되고 결과가 더 높은 유형이됩니다. (계층 구조에서 부동 소수점 및 정수 유형이 포함될 때마다 정수 유형이 부동 소수점 유형으로 변환됩니다.)

Unsigned는 상황을 조금 복잡하게 만듭니다. 순위를 혼란스럽게 만들고 순위의 일부가 정의 된 구현이됩니다. 이 때문에 부호있는 것과 부호없는 것을 같은 식으로 혼합하지 않는 것이 가장 좋습니다. (대부분의 C ++ 전문가는 비트 단위 연산이 포함되지 않으면 서명되지 않은 것으로 보입니다. 즉, Stroustrup이 권장하는 것입니다.)


3
Stroustrup은 자신이 좋아하는 것을 추천 할 수 있지만 int음수가 될 필요가없는 숫자에 부호를 사용하는 것은 사용 가능한 범위의 50 %를 완전히 낭비하는 것입니다. 나는 Stroustrup은 아니지만 unsigned기본적 signed으로 이유가있을 때만 사용 합니다 .
underscore_d

1
빼야 할 날까지는 밑줄 _d로 충분합니다. C ++에서 부호없는 숫자의 주요 문제점은 빼기를 수행 할 때 부호없는 상태로 유지된다는 것입니다. 따라서 std :: vector가 올바른지 확인하는 함수를 작성한다고 가정하십시오. 당신은 작성할 수 있습니다 bool in_order(vector<T> vec) { for ( int i = 0; i < size() - 1; ++i) { if (vec[i + 1] < vec[i]) return false; } return true;비어 벡터에 대한 충돌이 있음을 발견 한 후 당신이 짜증 것 때문에 크기 () - 18446744073709551615. 1 명을 반환
jorgbrown

3

솔루션 받는 문제는 WA (잘못된 답변), 그럼 내가 중 하나 변경 얻었다 int로를 long long int그리고 준 AC는 (동의) . 이전에, 내가 뭘하려고했다 long long int += int * int, 나는 그것을 수습 후 long long int += long long int * int. 내가 찾은 인터넷 검색,

1. 산술 변환

타입 변환 조건 :

조건 충족 ---> 변환

  • 피연산자는 long double 유형 입니다 . ---> 다른 피연산자는 long double 유형으로 변환됩니다 .

  • 선행 조건이 충족되지 않고 두 피연산자가 double 유형 입니다. ---> 다른 피연산자는 double 유형으로 변환됩니다 .

  • 선행 조건이 충족되지 않고 피연산자가 float 유형 입니다. ---> 다른 피연산자는 float 유형으로 변환됩니다 .

  • 선행 조건이 충족되지 않았습니다 (피연산자 중 어느 것도 부동 유형이 아닙니다). ---> 다음과 같이 피연산자에 대해 전체 승격이 수행됩니다.

    • 두 피연산자가 unsigned long 유형 인 경우 다른 피연산자는 unsigned long 유형으로 변환됩니다 .
    • 선행 조건이 충족되지 않고 피연산자 중 하나가 long 유형 이고 다른 피연산자가 unsigned int 유형 인 경우 두 피연산자가 모두 unsigned long 유형으로 변환됩니다 .
    • 앞의 두 조건이 충족되지 않고 피연산자가 long 유형 인 경우 다른 피연산자가 long 유형으로 변환됩니다 .
    • 앞의 세 가지 조건이 충족되지 않고 피연산자가 unsigned int 유형 인 경우 다른 피연산자는 unsigned int 유형으로 변환됩니다 .
    • 위의 조건 중 어느 것도 충족되지 않으면 두 피연산자가 모두 int 유형으로 변환됩니다 .

2. 정수 변환 규칙

  • 정수 프로모션 :

int보다 작은 정수 유형은 조작이 수행 될 때 승격됩니다. 원래 유형의 모든 값을 int로 표시 할 수 있으면 작은 유형의 값은 int로 변환됩니다. 그렇지 않으면 부호없는 int로 변환됩니다. 정수 승격은 특정 인수 표현식에 대한 일반적인 산술 변환의 일부로 적용됩니다. 단항 +,-및 ~ 연산자의 피연산자; 및 시프트 연산자의 피연산자.

  • 정수 변환 순위 :

    • 부호가있는 두 정수 유형은 표시가 동일하더라도 순위가 동일하지 않아야합니다.
    • 부호있는 정수 유형의 순위는 정밀도가 낮은 부호있는 정수 유형의 순위보다 커야합니다.
    • 의 랭크 long long int의 계급보다 커야한다 long int계급보다 커야한다, int의 랭크보다 커야한다, short int의 랭크보다 커야한다 signed char.
    • 부호없는 정수 유형의 순위는 해당하는 부호있는 정수 유형의 순위와 같습니다 (있는 경우).
    • 표준 정수 유형의 순위는 너비가 동일한 확장 정수 유형의 순위보다 커야합니다.
    • 의 순위는 char의 순위 signed char와 같습니다 unsigned char.
    • 동일한 정밀도를 가진 다른 확장 부호있는 정수 유형에 대한 확장 부호있는 정수 유형의 순위는 구현에 따라 정의되지만 여전히 정수 변환 순위를 결정하는 다른 규칙을 따릅니다.
    • 모든 정수 유형 T1, T2 및 T3의 경우 T1이 T2보다 순위가 높고 T2가 T3보다 순위가 높으면 T1이 T3보다 순위가 높습니다.
  • 일반적인 산술 변환 :

    • 두 피연산자의 유형이 모두 같으면 더 이상 변환 할 필요가 없습니다.
    • 두 피연산자가 모두 동일한 정수 유형 (부호 또는 부호없는) 인 경우, 정수 변환 순위가 낮은 유형의 피연산자는 순위가 더 큰 피연산자의 유형으로 변환됩니다.
    • 부호없는 정수 유형을 가진 피연산자가 다른 피연산자 유형의 순위보다 크거나 같은 순위를 갖는 경우 부호있는 정수 유형을 가진 피연산자는 부호없는 정수 유형을 가진 피연산자의 유형으로 변환됩니다.
    • 부호있는 정수 유형의 피연산자 유형이 부호없는 정수 유형의 피연산자 유형의 모든 값을 나타낼 수 있으면 부호없는 정수 유형의 피연산자는 부호있는 정수 유형의 피연산자 유형으로 변환됩니다.
    • 그렇지 않으면 두 피연산자가 부호있는 정수 유형의 피연산자 유형에 해당하는 부호없는 정수 유형으로 변환됩니다. 특정 연산은 일반적인 산술 연산의 의미를 추가하거나 수정할 수 있습니다.

1

4 장 전체에서 전환에 대해 이야기하지만 대부분 다음에 관심이 있어야합니다.

4.5 통합 프로모션 [conv.prom]
char 유형의 rvalue, 부호있는 char, 부호없는 char, short int 또는 unsigned short int는 int가 소스 유형의 모든 값을 나타낼 수있는 경우 int 유형의 rvalue로 변환 될 수 있습니다. 그렇지
않으면 소스 rvalue를 unsigned int 유형의 rvalue로 변환 할 수 있습니다.
유형 wchar_t (3.9.1) 또는 열거 유형 (7.2)의 rvalue
는 기본 유형의 모든 값을 나타낼 수있는 다음 유형 중 첫 번째 유형의 rvalue로 변환 될 수 있습니다 . int, unsigned int,
long 또는 unsigned 긴.
정수 비트 필드 (9.6)에 대한 rvalue는 int가 모두를 나타낼 수있는 경우 int 유형의 rvalue로 변환 될 수 있습니다.
값은 비트 필드의 값을 값 . 그렇지 않으면 unsigned int가 응답 할 수 있으면 unsigned int로 변환 할 수 있습니다
비트 필드의 모든 값을 다시 보냅니다. 비트 필드가 더 큰 경우 일체형 프로모션이 적용되지 않습니다. 경우]
비트 필드를 열거 타입을 가지며,이를 촉진을 목적으로하는 형태의 임의의 다른 값으로 처리된다.
bool 유형의 rvalue는 int 유형의 rvalue로 변환 될 수 있으며, false는 0이되고 true
는 1이됩니다.
이러한 전환을 통합 프로모션이라고합니다.

4.6 부동 소수점 승격 [conv.fpprom]
float 유형의 rvalue를 double 유형의 rvalue로 변환 할 수 있습니다. 값은 변경되지 않습니다.
이 변환을 부동 소수점 승격이라고합니다.

따라서 float와 관련된 모든 변환-결과는 float입니다.

두 개의 int와 관련된 것만-결과는 int입니다 : int / int = int


1

두 부분이 모두 같은 유형이 아닌 경우 표현식의 유형은 둘 중 가장 큰 유형으로 변환됩니다 . 여기서 문제는 어느 것이 다른 것보다 큰지 이해하는 것입니다 (바이트 단위의 크기와 관련이 없음).

실수와 정수가 관련된 표현식에서 정수는 실수로 승격됩니다. 예를 들어, int + float에서 표현식의 유형은 float입니다.

다른 차이점은 유형의 기능과 관련이 있습니다. 예를 들어, int 및 long int와 관련된 표현식은 long int 유형의 결과입니다.


2
사실이 아닙니다. 플랫폼에서 a long는 a 보다 "더 큰" float것이지만 long+ 의 유형은 무엇 float입니까?
CB Bailey

1
-1 : 가장 큰 의미는 무엇입니까 ? 플로트가 더 큰 하는 int보다 더? 아니면 그 반대 입니까?
Paul R

2
귀하의 의견에 감사드립니다. 그러나 여기서 바이트 단위의 크기는 전혀 관심이 없습니다. 결과적으로, 이탤릭체로 가장 큰 것을 넣는 것만으로는 답을 설명하기에 충분하지 않습니다. 어쨌든, 다른 철저한 답변이 있기 때문에 더 깊이 설명하는 것은 이치에 맞지 않습니다.
Baltasarq

-2

경고!

왼쪽에서 오른쪽으로 변환됩니다.

이 시도:

int i = 3, j = 2;
double k = 33;
cout << k * j / i << endl; // prints 22
cout << j / i * k << endl; // prints 0

8
그것은 변환 때문이 아니라 연산자 우선 순위 때문입니다. j + i * k101에 결과가 될 것입니다.
gartenriese
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.