캐스팅과 강제의 차이점은 무엇입니까?


85

저는 두 용어가 다양한 온라인 설명에서 거의 같은 의미로 사용되는 것을 보았습니다. 그리고 제가 참조한 대부분의 교과서 역시 그 차이에 대해 완전히 명확하지 않습니다.

여러분이 알고있는 차이점을 명확하고 간단하게 설명 할 수있는 방법이 있습니까?

유형 변환 ( 유형 캐스트 라고도 함 )

다른 것을 예상하는 컨텍스트에서 한 유형의 값을 사용합니다.

비 변환 유형 캐스트 ( 유형 pun 이라고도 함 )

기본 비트를 변경하지 않는 변경입니다.

강제

주변 컨텍스트에서 두 번째 유형이 필요할 때 컴파일러가 한 유형의 값을 다른 유형의 값으로 자동 변환하는 프로세스입니다.


답변:


114

유형 변환 :

단어 변환 은 한 데이터 유형에서 다른 데이터 유형으로 값을 암시 적으로 또는 명시 적으로 변경하는 것을 말합니다 (예 : 16 비트 정수에서 32 비트 정수로).

강제 변환 이라는 단어 는 암시 적 변환을 나타내는 데 사용됩니다.

캐스트 라는 단어 일반적으로 이것이 비트 패턴의 재 해석인지 실제 변환인지에 관계없이 명시 적 형식 변환 (암시 적 변환과 반대)을 나타냅니다.

따라서 강제는 암시 적이며 캐스트는 명시 적이며 변환은 그들 중 하나입니다.


몇 가지 예 ( 동일한 소스에서 ) :

강제 (암시 적) :

double  d;
int     i;
if (d > i)      d = i;

캐스트 (노골적) :

double da = 3.3;
double db = 3.3;
double dc = 3.4;
int result = (int)da + (int)db + (int)dc; //result == 9

이것이 "암시 적 강제"를 중복되게 만들까요? 메모는 여기에 모두 "암시 강요"와 "명시 적으로 강제"를 사용
데이브 Cousineau

1
암시 적 변환은 정밀도를 잃지 않거나 의미가 없을 때만 수행 할 수 있습니다 (예 : Int-> double). 대부분의 현대 언어에서는 정밀도를 잃기 때문에 double-> int를 수행 할 수 없습니다. 유형 강제를 사용하면 "문제"가 아닙니다.
Maxime Rouiller 16.04.14

이 답변은 CIL에 대한 ecma 335에 정의 된 사양과 일치하지 않습니다. 내 대답에 예제와 함께 사양 정의를 배치했습니다.
P.Brian.Mackey

24

아시다시피 사용법은 다양합니다.

내 개인적인 용도는 다음과 같습니다.

  • "캐스트"는 캐스트 연산자 의 사용법입니다 . 캐스트 연산자는 컴파일러에게 (1)이 표현식이 주어진 유형으로 알려져 있지 않다고 알려줍니다.하지만 런타임에 값이 해당 유형이 될 것이라고 약속합니다. 컴파일러는 표현식을 주어진 유형으로 처리하고 그렇지 않은 경우 런타임에서 오류를 생성합니다. 또는 (2) 표현식이 완전히 다른 유형이지만 인스턴스를 연결하는 잘 알려진 방법이 있습니다. 캐스트 대상 유형의 인스턴스가있는 표현식 유형의. 컴파일러는 변환을 수행하는 코드를 생성하도록 지시됩니다. 세심한 독자는 이것들이 정반대라는 점에 주목할 것입니다.

  • "변환"은 한 유형의 값이 다른 유형의 값으로 처리되는 작업입니다. 일반적으로 다른 유형의 값으로 처리되지만 "ID 변환"은 기술적으로는 여전히 변환입니다. 변환은 int에서 double 로의 "표현 변경"이거나 문자열에서 객체로의 "표현 보존"일 수 있습니다. 변환은 캐스트가 필요하지 않은 "암시 적"이거나 캐스트가 필요한 "명시 적"일 수 있습니다.

  • "강제"는 표현을 변경하는 암시 적 변환입니다.


1
이 답변의 첫 번째 문장이 가장 중요한 것이라고 생각합니다. 다른 언어에서는이 용어를 사용하여 매우 다른 의미를 갖습니다. 예를 들어 Haskell에서 "강제" 표현을 변경 하지 않습니다 . 안전한 강제, Data.Coerce.coerce :: Coercible a b => a -> b동일한 표현을 갖는 것으로 입증 된 유형에 대해 작동합니다. Unsafe.Coerce.unsafeCoerce :: a -> b두 가지 유형에 대해 작동합니다 (잘못 사용하면 악마가 코에서 나오게합니다).
dfeuer 2014-10-22

@dfeuer 흥미로운 데이터 포인트, 감사합니다! C # spec은 "강제"를 정의하지 않습니다. 제 제안은 제가 개인적으로 의미하는 것입니다. 용어가 잘못 정의 된 것처럼 보이므로 일반적으로 사용하지 않습니다.
Eric Lippert 2014 년

8

캐스팅은 개체 유형을 다른 유형으로 취급하는 프로세스이며 Coercing은 한 개체를 다른 개체로 변환합니다.

이전 프로세스에서는 변환이 필요하지 않습니다. 예를 들어 기본 유형에서 상속하는 3 개의 다른 객체가 있고이를 취할 메서드가있는 경우와 같이 다른 유형으로 처리하려는 유형이 있습니다. 특정 자식 유형을 알고있는 경우 언제든지 기본 유형을 CAST 할 수 있으며 해당 개체의 모든 특정 메서드와 속성을 사용할 수 있으며 개체의 새 인스턴스를 만들지 않습니다.

반면에 강제는 새 유형의 메모리에 새 객체를 생성 한 다음 원래 유형이 새 유형에 복사되어 두 객체를 메모리에 남겨 두는 것을 의미합니다 (가비지 수집기가 둘 중 하나 또는 둘 다를 제거 할 때까지). .

예를 들어 다음 코드를 고려하십시오.

class baseClass {}
class childClass : baseClass {}
class otherClass {}

public void doSomethingWithBase(baseClass item) {}

public void mainMethod()
{
    var obj1 = new baseClass();
    var obj2 = new childClass();
    var obj3 = new otherClass();

    doSomethingWithBase(obj1); //not a problem, obj1 is already of type baseClass
    doSomethingWithBase(obj2); //not a problem, obj2 is implicitly casted to baseClass
    doSomethingWithBase(obj3); //won't compile without additional code
}
  • obj1은 이미 동일한 유형이므로 캐스팅 또는 강제 변환 (변환)없이 전달됩니다. baseClass
  • obj2는 암시 적으로 base로 캐스트됩니다. 즉, obj2는 이미 생성 될 수 있기 때문에 새 개체를 만들지 않습니다. baseClass
  • OBJ3 필요가베이스에 어떻게 든 변환하려면 변환하는 자신 만의 방법을 제공해야 otherClass하는 baseClass타입의 base class의 새로운 객체를 생성하고 OBJ3에서 데이터를 복사하여 작성 포함 것이다.

좋은 예는 Convert C # 클래스 로, 다양한 유형간에 변환 할 수있는 사용자 지정 코드를 제공합니다.


3
예는 당신이 만들고자하는 구별을 명확히하는 데 도움이 될 것입니다.
Oliver Charlesworth 2012 년

2

캐스팅은 개체 유형을 유지합니다. 강제는 그렇지 않습니다.

Coercion 은 할당 호환되지 않는 유형의 값을 취하고 할당 호환 가능한 유형으로 변환합니다. 여기서 Int32상속하지 않기 때문에 강제 Int64할당을 수행하므로 할당과 호환되지 않습니다. 이것은 확장 강제입니다 (데이터 손실 없음). 확대 강제는 일명 암시 적 변환 입니다. 강제 변환은 변환을 수행합니다.

void Main()
{
    System.Int32 a = 100;
    System.Int64 b = a;
    b.GetType();//The type is System.Int64.  
}

캐스팅을 사용하면 유형을 보존하면서 유형을 다른 유형 인 것처럼 처리 할 수 ​​있습니다 .

    void Main()
    {
        Derived d = new Derived();
        Base bb = d;
        //b.N();//INVALID.  Calls to the type Derived are not possible because bb is of type Base
        bb.GetType();//The type is Derived.  bb is still of type Derived despite not being able to call members of Test
    }

    class Base 
    {
        public void M() {}
    }

    class Derived: Base
    {
        public void N() {}
    }

출처 : James S. Miller의 The Common Language Infrastructure Annotated Standard

이제 이상한 점은 Casting 에 대한 Microsoft의 문서가 Casting 의 ecma-335 사양 정의와 일치하지 않는다는 것입니다.

명시 적 변환 (캐스트) : 명시 적 변환에는 캐스트 연산자가 필요합니다. 변환에서 정보가 손실되거나 다른 이유로 변환이 성공하지 못할 때 캐스팅이 필요합니다. 일반적인 예로는 정밀도가 낮거나 범위가 더 작은 형식으로의 숫자 변환과 기본 클래스 인스턴스를 파생 클래스로 변환하는 것이 있습니다.

... 이것은 캐스팅 이 아닌 강제 변환 처럼 들립니다 .

예를 들면

  object o = 1;
  int i = (int)o;//Explicit conversions require a cast operator
  i.GetType();//The type has been explicitly converted to System.Int32.  Object type is not preserved.  This meets the definition of Coercion not casting.

누가 알아? 아마도 마이크로 소프트는이 글을 읽는 사람이 있는지 확인하고있을 것입니다.


1

아래는 다음 기사 의 게시물입니다 .

강제와 캐스팅의 차이는 종종 무시됩니다. 이유를 알 수 있습니다. 많은 언어가 두 작업에 대해 동일한 (또는 유사한) 구문과 용어를 사용합니다. 일부 언어는 모든 변환을 '캐스트'라고도 할 수 있지만 다음 설명은 CTS의 개념을 참조합니다.

특정 유형의 값을 다른 유형의 위치에 할당하려는 경우 원본과 유사한 의미를 가진 새 유형의 값을 생성 할 수 있습니다. 이것은 강압입니다. 강제 변환을 사용하면 어떤 방식 으로든 원본과 유사한 새 값을 생성하여 새 유형을 사용할 수 있습니다. 일부 강제 변환은 데이터를 버릴 수 있지만 (예 : int 0x12345678을 짧은 0x5678로 변환) 다른 변환은 데이터를 버릴 수 있지만 (예 : int 0x00000008을 짧은 0x0008 또는 긴 0x0000000000000008로 변환).

값은 여러 유형을 가질 수 있습니다. 상황이 약간 다르고 값 유형 중 다른 유형 만 선택하려는 경우 캐스팅이 작업 도구입니다. 캐스트는 단순히 값에 포함 된 특정 유형에 대해 작업하고자 함을 나타냅니다.

코드 수준의 차이는 C #에서 IL에 따라 다릅니다. C #에서 캐스팅과 강제 변환은 모두 상당히 유사합니다.

static void ChangeTypes(int number, System.IO.Stream stream)
{
    long longNumber = number;
    short shortNumber = (short)number;

    IDisposable disposableStream = stream;
    System.IO.FileStream fileStream = (System.IO.FileStream)stream;
}

IL 수준에서는 상당히 다릅니다.

ldarg.0
 conv.i8
 stloc.0

ldarg.0
 conv.i2
 stloc.1


ldarg.1
 stloc.2

ldarg.1
 castclass [mscorlib]System.IO.FileStream
 stloc.3

논리적 수준에는 몇 가지 중요한 차이점이 있습니다. 기억해야 할 가장 중요한 것은 강압은 새로운 가치를 창출하지만 캐스팅은 그렇지 않다는 것입니다. 원래 값의 ID와 캐스팅 후 값은 동일하지만 강제 된 값의 ID는 원래 값과 다릅니다. 강제 변환은 새롭고 고유 한 인스턴스를 생성하지만 캐스팅은 생성하지 않습니다. 추론은 캐스팅의 결과와 원본은 항상 동일하지만 (정체성과 동등성 모두에서) 강제 된 값은 원본과 같을 수도 있고 같지 않을 수도 있으며 원래의 정체성을 공유하지 않습니다.

숫자 유형은 항상 값으로 복사되므로 위의 예에서 강제 변환의 의미를 쉽게 확인할 수 있습니다. 참조 유형으로 작업 할 때 상황이 조금 더 까다로워집니다.

class Name : Tuple<string, string>
{
    public Name(string first, string last)
        : base(first, last)
    {
    }

    public static implicit operator string[](Name name)
    {
        return new string[] { name.Item1, name.Item2 };
    }
}

아래 예에서 하나의 변환은 캐스트이고 다른 하나는 강제입니다.

Tuple<string, string> tuple = name;
string[] strings = name;

이러한 변환 후에 튜플과 이름은 동일하지만 문자열은 둘 중 어느 쪽과도 동일하지 않습니다. Name 클래스에서 Name과 string []을 비교하기 위해 Equals () 및 operator == ()를 구현하여 상황을 약간 개선하거나 약간 더 혼란스럽게 만들 수 있습니다. 이러한 연산자는 비교 문제를 "수정"하지만 여전히 두 개의 개별 인스턴스가 있습니다. 문자열에 대한 수정 사항은 이름이나 튜플에 반영되지 않고 이름이나 튜플 중 하나에 대한 변경 사항은 이름과 튜플에 반영되지만 문자열에는 반영되지 않습니다.

위의 예제는 캐스팅과 강제 변환 간의 몇 가지 차이점을 설명하기위한 것이지만 C #에서 참조 형식과 함께 변환 연산자를 사용하는 데 매우주의해야하는 이유를 보여주는 좋은 예이기도합니다.


1

에서 CLI를 표준 :

I.8.3.2 강제 변환

때때로 위치에 할당 할 수없는 유형의 값을 가져 와서 위치 유형에 할당 할 수있는 유형으로 값을 변환하는 것이 바람직합니다. 이것은 가치의 강제 를 통해 이루어 집니다. Coercion은 특정 유형의 값과 원하는 유형을 취하고 원래 값과 동일한 의미를 갖는 원하는 유형의 값을 생성하려고합니다. 강제 변환은 유형 변경뿐만 아니라 표현 변경을 초래할 수 있습니다. 따라서 강제는 반드시 객체 신원을 보존하는 것은 아닙니다.

강압에는 두 가지 종류 가 있습니다. 정보를 잃지 않는 확대 와 정보가 손실 될 수있는 축소 가 있습니다. 확장 강제 변환의 예는 부호있는 32 비트 정수 값을 부호있는 64 비트 정수 값으로 강제 변환하는 것입니다. 축소 강제 변환의 예는 그 반대입니다. 부호있는 64 비트 정수를 부호있는 32 비트 정수로 강제 변환합니다. 프로그래밍 언어는 종종 확장 강제 변환을 암시 적 변환 으로 구현 하는 반면 축소 강제 변환에는 일반적 으로 명시 적 변환이 필요합니다 .

일부 강제는 내장 유형의 VES 작업에 직접 내장됩니다 (§I.12.1 참조). 다른 모든 강제는 명시 적으로 요청되어야합니다. 기본 제공 유형의 경우 CTS는 작업 의미 체계에 따라 런타임 확인없이 확장 강제를 수행하고 런타임 검사 또는 자르기를 사용하여 축소 강제를 수행하는 작업을 제공합니다.

I.8.3.3 캐스팅

값은 둘 이상의 유형이 될 수 있으므로 값을 사용하면 사용중인 유형을 명확하게 식별해야합니다. 입력 된 위치에서 값을 읽으므로 사용되는 값의 유형은 값을 읽은 위치의 유형입니다. 다른 유형을 사용할 경우 값은 다른 유형 중 하나로 캐스트 됩니다. 캐스팅은 일반적으로 컴파일 시간 작업이지만 컴파일러가 값이 대상 유형인지 정적으로 알 수없는 경우 런타임 캐스팅 검사가 수행됩니다. 강제와는 달리 캐스트는 객체의 실제 유형을 변경하지 않으며 표현도 변경하지 않습니다. 캐스팅은 개체의 정체성을 유지합니다.

예를 들어 특정 인터페이스의 값을 보유하는 것으로 입력 된 위치에서 읽은 값을 캐스팅 할 때 런타임 검사가 필요할 수 있습니다. 인터페이스는 값에 대한 불완전한 설명이므로 해당 값을 다른 인터페이스 유형으로 캐스팅하면 일반적으로 런타임 캐스팅 검사가 수행됩니다.


1

Wikipedia에 따르면

컴퓨터 과학에서 유형 변환, 유형 변환, 유형 강제 변환 및 유형 저글링은 한 데이터 유형에서 다른 데이터 유형으로 표현식을 변경하는 다른 방법입니다.

유형 캐스팅과 유형 강제 변환의 차이점은 다음과 같습니다.

           TYPE CASTING           |                   TYPE COERCION
                                  |
1. Explicit i.e., done by user    | 1. Implicit i.e., done by the compiler
                                  |
2. Types:                         | 2. Type:
    Static (done at compile time) |     Widening (conversion to higher data 
                                  |     type)
    Dynamic (done at run time)    |     Narrowing (conversion to lower data 
                                  |     type)
                                  |
3. Casting never changes the      | 3. Coercion can result in representation 
   the actual type of object      |    as well as type change.
   nor representation.            |

참고 : 캐스팅은 변환이 아닙니다. 객체 유형을 다른 유형으로 취급하는 프로세스 일뿐입니다. 따라서 실제 객체 유형과 표현은 캐스팅 중에 변경되지 않습니다.

@ PedroC88의 말에 동의합니다.

반면에 강제는 새 유형의 메모리에 새 객체를 생성 한 다음 원래 유형이 새 유형에 복사되어 두 객체를 메모리에 남겨 두는 것을 의미합니다 (가비지 수집기가 둘 중 하나 또는 둘 다를 제거 할 때까지). .

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