왜 (int) x 대신 static_cast <int> (x)를 사용합니까?


667

static_cast함수는 C 스타일 또는 간단한 함수 스타일 캐스팅보다 선호되어야한다고 들었습니다 . 이것이 사실입니까? 왜?


36
당신의 명예를 거부하고 물었다 .
Graeme Perrow

25
동의하지 않습니다.이 다른 질문은 C ++에서 캐스트 도입의 차이점을 설명하는 것이 었습니다. 이 질문은 static_cast의 실제 유용성에 관한 것인데 약간 다릅니다.
Vincent Robert

2
우리는 분명히 두 가지 질문을 병합 할 수 있지만이 스레드에서 보존해야 할 것은 현재 C 스타일 캐스팅보다 함수를 사용하는 이점입니다. .
Tommy Herbert

6
이 질문은 int와 같은 "내장 된"유형에 관한 것이지만 그 질문은 클래스 유형에 관한 것입니다. 그것은 별도의 설명을 할만한 충분한 차이가있는 것 같습니다.

9
static_cast는 실제로 함수가 아닌 연산자입니다.
ThomasMcLeod

답변:


633

주된 이유는 고전적인 C 캐스트는 우리가 부르는 사이에 구분하지 않습니다이다 static_cast<>(), reinterpret_cast<>(), const_cast<>(),와 dynamic_cast<>(). 이 네 가지가 완전히 다릅니다.

A static_cast<>()는 일반적으로 안전합니다. 언어의 유효한 변환 또는 가능하게하는 적절한 생성자가 있습니다. 약간 위험한 유일한 시간은 상속 된 클래스로 캐스트 할 때입니다. 객체가 실제로 언어의 외부 (예 : 객체의 플래그)와 같은 객체라고 주장하는 자손인지 확인해야합니다. A dynamic_cast<>()는 결과가 확인되거나 (포인터) 가능한 예외가 고려되는 한 (참조) 안전합니다.

반면에 reinterpret_cast<>()(또는 a const_cast<>())는 항상 위험합니다. 당신은 컴파일러에게 다음과 같이 말합니다 : "믿어주세요 : 이것이 마치 마치 변하지 않는 것처럼 foo보이지만 그것이 그렇다는 것을 알고 있습니다."

첫 번째 문제는 크고 분산 된 코드를 보지 않고 모든 규칙을 알지 못하면 C 스타일 캐스트에서 어떤 것이 발생하는지 알 수 없다는 것입니다.

이것을 가정 해 봅시다 :

class CDerivedClass : public CMyBase {...};
class CMyOtherStuff {...} ;

CMyBase  *pSomething; // filled somewhere

이제이 두 방법은 같은 방식으로 컴파일됩니다.

CDerivedClass *pMyObject;
pMyObject = static_cast<CDerivedClass*>(pSomething); // Safe; as long as we checked

pMyObject = (CDerivedClass*)(pSomething); // Same as static_cast<>
                                     // Safe; as long as we checked
                                     // but harder to read

그러나 거의 동일한 코드를 보자.

CMyOtherStuff *pOther;
pOther = static_cast<CMyOtherStuff*>(pSomething); // Compiler error: Can't convert

pOther = (CMyOtherStuff*)(pSomething);            // No compiler error.
                                                  // Same as reinterpret_cast<>
                                                  // and it's wrong!!!

보시다시피, 관련된 모든 수업에 대해 많이 몰라도 두 상황을 쉽게 구별 할 수있는 방법은 없습니다.

두 번째 문제는 C 스타일 캐스트를 찾기가 너무 어렵다는 것입니다. 복잡한 표현에서는 C 스타일 캐스트를보기가 매우 어려울 수 있습니다. 완전한 C ++ 컴파일러 프론트 엔드없이 C 스타일 캐스트 (예 : 검색 도구)를 찾아야하는 자동화 된 도구를 작성하는 것은 사실상 불가능합니다. 한편, "static_cast <"또는 "reinterpret_cast <"를 쉽게 검색 할 수 있습니다.

pOther = reinterpret_cast<CMyOtherStuff*>(pSomething);
      // No compiler error.
      // but the presence of a reinterpret_cast<> is 
      // like a Siren with Red Flashing Lights in your code.
      // The mere typing of it should cause you to feel VERY uncomfortable.

즉, C 스타일 캐스트가 더 위험 할뿐만 아니라 모두 올바른지 확인하기가 훨씬 어렵습니다.


30
static_cast상속 계층 구조를 캐스트하는 데 사용하지 말고을 사용해야 합니다 dynamic_cast. null 포인터 또는 유효한 포인터를 반환합니다.
David Thornley

41
@David Thornley : 보통 동의합니다. 나는 static_cast그 상황에서 사용할주의 사항을 지적했다고 생각 합니다. dynamic_cast더 안전 할 수도 있지만 항상 최선의 방법은 아닙니다. 때로는 포인터가 주어진 하위 유형을 가리키는 것으로 컴파일러에 대해 불투명하고 a 가 더 빠르다 는 것을 알고static_cast 있습니다. 적어도 일부 환경 dynamic_cast에서는 선택적 컴파일러 지원 및 런타임 비용 (RTTI 사용)이 필요하며, 몇 가지 점검만으로 직접 사용하지 않을 수도 있습니다. C ++의 RTTI는이 문제를 해결할 수있는 유일한 솔루션입니다.
Euro Micelli

18
C 캐스트에 대한 귀하의 주장은 허위입니다. 모든 C 캐스트는 C ++과 거의 비슷한 값 변환 static_cast입니다. C에 해당하는 reinterpret_cast것은 *(destination_type *)&즉, 객체의 주소를 가져 와서 해당 주소를 다른 유형에 대한 포인터로 캐스트 한 다음 역 참조하는 것입니다. C는이 구조의 동작을 정의하는 문자 유형 또는 특정 구조체 타입의 경우를 제외하고는 일반적으로 정의되지 않은 동작에 C. 결과
R .. GitHub의 STOP은 ICE 돕기

11
정답은 게시물 본문을 처리합니다. "(int) x 대신 static_cast <int> (x)를 사용하는 이유"라는 제목의 답변을 찾고있었습니다. 즉, 유형 int(및 int단독)의 경우 static_cast<int>vs (int)를 유일한 장점으로 사용하는 이유 는 클래스 변수와 포인터에있는 것 같습니다. 이에 대해 자세히 설명하십시오.
chux-복원 Monica Monica

31
@chux int dynamic_cast는 적용되지 않지만 다른 모든 이유가 있습니다. 예를 들어 :하자 말은 v로 선언 된 함수 매개 변수는 float다음 (int)v이다 static_cast<int>(v). 당신의 매개 변수를 변경한다면 float*, (int)v조용히하게 reinterpret_cast<int>(v)하면서 static_cast<int>(v)불법 올바르게 컴파일러에 의해 잡힐 것입니다.
Euro Micelli

115

실용적인 팁 : 프로젝트를 정리하려는 경우 소스 코드에서 static_cast 키워드를 쉽게 검색 할 수 있습니다.


3
"(int)"와 같이 대괄호를 사용하여 검색 할 수 있지만 C ++ 스타일 캐스팅을 사용하는 적절한 대답과 유효한 이유가 있습니다.
Mike

4
@Mike는 오 탐지를 찾을 것입니다-단일 int매개 변수를 사용한 함수 선언 .
Nathan Osman

1
저자가 아닌 코드베이스를 검색하는 경우 다른 이유로 소개 한 C 스타일 캐스트를 찾지 못할 수 있습니다.
Ruslan

7
어떻게하면 프로젝트를 정리할 수 있을까요?
Bilow

static_cast는 올바른 것이기 때문에 검색하지 않습니다. reinterpret_cast, const_cast 및 심지어 dynamic_cast를 검색하는 동안 static_cast를 필터링하여 재 설계 할 수있는 위치를 표시하려고합니다. C-cast는 모두 혼합되어 있으며 캐스팅 이유를 제공하지 않습니다.
Dragan

78

한마디로 :

  1. static_cast<>() 컴파일 시간 검사 기능을 제공하지만 C 스타일 캐스트는 그렇지 않습니다.
  2. static_cast<>()C ++ 소스 코드의 어느 곳에서나 쉽게 발견 할 수 있습니다. 반면에 C_Style 캐스트는 찾기가 더 어렵습니다.
  3. C ++ 캐스트를 사용하면 의도가 훨씬 더 잘 전달됩니다.

더 많은 설명 :

정적 캐스트는 호환 가능한 유형 간에 변환을 수행합니다 . C 스타일 캐스트와 비슷하지만 더 제한적입니다. 예를 들어 C 스타일 캐스트는 정수 포인터가 문자를 가리 키도록 허용합니다.

char c = 10;       // 1 byte
int *p = (int*)&c; // 4 bytes

이로 인해 1 바이트의 할당 된 메모리를 가리키는 4 바이트 포인터가 생성되므로이 포인터에 쓰면 런타임 오류가 발생하거나 일부 인접한 메모리를 덮어 씁니다.

*p = 5; // run-time error: stack corruption

C 스타일 캐스트와 달리 정적 캐스트는 컴파일러가 포인터 및 포인트 데이터 유형이 호환되는지 확인하여 프로그래머가 컴파일 중에이 잘못된 포인터 할당을 잡을 수있게합니다.

int *q = static_cast<int*>(&c); // compile-time error

자세한 내용 :
static_cast <> 및 C 스타일 캐스팅
일반 캐스트 대 static_cast 대 dynamic_cast 의 차이점은 무엇입니까?


21
나는 그것이 static_cast<>()더 읽기 쉽다는 것에 동의하지 않습니다 . 내 말은, 때로는 그렇습니다. 그러나 대부분의 경우, 특히 기본 정수 유형의 경우에는 끔찍하고 불필요하게 장황합니다. 예를 들면 다음과 같습니다. 32 비트 워드의 바이트를 바꾸는 함수입니다. static_cast<uint##>()캐스트를 사용하여 읽는 것은 거의 불가능 하지만 (uint##)캐스트를 사용하여 이해하기는 쉽습니다 . 코드 그림 : imgur.com/NoHbGve
Todd Lehman

3
@ToddLehman : 감사합니다.하지만 한마디도하지 않았습니다 always. (그러나 대부분의 경우 예) c 스타일 캐스트가 더 읽기 쉬운 경우가 있습니다. 그것이 c 스타일 캐스팅이 여전히 살아 있고 c ++ imho에서 발로 드는 이유 중 하나입니다. :) 그건 그렇고 아주 좋은 예였습니다
Rika

8
해당 이미지의 @ToddLehman 코드는 두 개의 캐스트 체인 ( (uint32_t)(uint8_t))을 사용하여 가장 낮은 바이트 이외의 바이트가 재설정되도록합니다. 이를 위해 비트와 ( 0xFF &)가 있습니다. 캐스트 사용은 의도를 혼란스럽게 만듭니다.
Öö Tiib

28

C 스타일 캐스트를 사용할 때 다른 일이 발생하기 때문에 wither static_cast 또는 C 스타일 캐스팅을 사용하는 것보다 문제가 더 큽니다. C ++ 캐스팅 연산자는 이러한 작업을보다 명확하게하기위한 것입니다.

표면에서 static_cast와 C 스타일 캐스트는 같은 것으로 보입니다 (예 : 하나의 값을 다른 값으로 캐스트 할 때).

int i;
double d = (double)i;                  //C-style cast
double d2 = static_cast<double>( i );  //C++ cast

둘 다 정수 값을 두 배로 캐스트합니다. 그러나 포인터로 작업 할 때 상황이 더 복잡해집니다. 몇 가지 예 :

class A {};
class B : public A {};

A* a = new B;
B* b = (B*)a;                                  //(1) what is this supposed to do?

char* c = (char*)new int( 5 );                 //(2) that weird?
char* c1 = static_cast<char*>( new int( 5 ) ); //(3) compile time error

이 예제에서 (1) A가 가리키는 객체가 실제로 B의 인스턴스이기 때문에 OK 일 수 있습니다. 그러나 코드에서 그 시점에서 실제로 가리키는 것이 무엇인지 모른다면 어떻게 될까요? (2) 아마도 완벽하게 합법적 일 수 있습니다 (정수의 1 바이트 만보 고 싶을 수도 있음). (3)과 같이 오류가 좋을 수도 있습니다. C ++ 캐스팅 연산자는 가능한 경우 컴파일 타임 또는 런타임 오류를 제공하여 이러한 문제를 코드에 노출 시키려고합니다.

따라서 엄격한 "값 캐스팅"의 경우 static_cast를 사용할 수 있습니다. 포인터의 런타임 다형성 캐스팅을 원한다면 dynamic_cast를 사용하십시오. 실제로 유형을 잊고 싶다면 reintrepret_cast를 사용할 수 있습니다. 그리고 const를 창 밖으로 던지기 위해 const_cast가 있습니다.

그들은 당신이하고있는 일을 알고있는 것처럼 보이도록 코드를보다 명확하게 만듭니다.


26

static_cast실수로 const_cast또는 할 수 없다는 것을 의미합니다 reinterpret_cast.


4
C 스타일 캐스트에 비해 추가적이지만 (사소한) 장점은 더 눈에 띄는 것 (추악한 것으로 보이는 것이 추악하게 보일 것임)이며 더 grep 가능하다는 것입니다.
Michael Burr

4
내 책에서 grep-ability는 항상 플러스입니다.
Branan

7
  1. grep 또는 유사한 도구를 사용하여 코드에서 캐스트를 쉽게 찾을 수 있습니다.
  2. 어떤 종류의 캐스트를 수행하는지 명시하고 컴파일러의 도움을 받아 실행합니다. const-ness 만 버리려면 const_cast를 사용하면 다른 유형의 변환을 수행 할 수 없습니다.
  3. 캐스트는 본질적으로 추악합니다. 프로그래머는 컴파일러가 일반적으로 코드를 처리하는 방식을 무시하고 있습니다. 당신은 컴파일러에게 "나는 당신보다 더 잘 알고있다"고 말하고있다. 그렇기 때문에 캐스트를 수행하는 것은 적당히 고통스러운 일이며, 문제의 원인이 될 수 있기 때문에 코드에서 튀어 나와야한다는 것이 합리적입니다.

효과적인 C ++ 소개 참조


나는 클래스에 대해서는 이것에 완전히 동의하지만 POD 유형에 C ++ 스타일 캐스트를 사용하는 것이 의미가 있습니까?
Zachary Kraus

나도 그렇게 생각해. 3 가지 이유 모두 POD에 적용되며 클래스와 POD에 대한 별도의 규칙이 아닌 하나의 규칙 만 갖는 것이 좋습니다.
JohnMcG

흥미롭게도 향후 POD 유형 코드에서 캐스트를 수행하는 방법을 수정해야 할 수도 있습니다.
Zachary Kraus

7

얼마나 많은 유형 안전을 부과하고 있는지에 관한 것입니다.

쓸 때 (bar) foo( reinterpret_cast<bar> foo형식 변환 연산자를 제공하지 않은 경우 와 동일 ) 컴파일러는 형식 안전을 무시하고 지시대로 지시합니다.

작성할 때 static_cast<bar> foo컴파일러가 최소한 형식 변환이 의미가 있는지 확인하고 정수 형식의 경우 변환 코드를 삽입하도록 요청합니다.


편집 2014-02-26

나는 5 년 전에이 답변을 썼는데, 틀렸다. (의견을 참조하십시오.) 그러나 여전히 공세를 얻습니다!


8
(bar) foo는 reinterpret_cast <bar> (foo)와 동일하지 않습니다. "(TYPE) expr"의 규칙은 reinterpret_cast를 포함하여 사용할 적절한 C ++ 스타일 캐스트를 선택한다는 것입니다.
Richard Corden

좋은 지적. Euro Micelli는이 질문에 대한 확실한 답을 주었다.
Pitarou

1
또한 static_cast<bar>(foo)괄호 안에 있습니다. 동일합니다 reinterpret_cast<bar>(foo).
LF

6

C 스타일 캐스트는 코드 블록에서 놓치기 쉽습니다. C ++ 스타일 캐스트는 더 나은 연습 일뿐만 아니라; 그들은 훨씬 더 큰 유연성을 제공합니다.

reinterpret_cast를 사용하면 포인터 유형 변환에 정수를 사용할 수 있지만 잘못 사용하면 안전하지 않을 수 있습니다.

static_cast는 숫자 형에 대해 열거 형에서 정수로 또는 정수에서 부동 소수점으로 또는 유형이 확실한 데이터 형식으로 변환하는 기능을 제공합니다. 런타임 검사는 수행하지 않습니다.

반면에 dynamic_cast는 모호한 할당 또는 변환을 표시하는 이러한 검사를 수행합니다. 포인터와 참조에서만 작동하며 오버 헤드가 발생합니다.

다른 몇 가지가 있지만 이것들은 당신이 보게 될 주요한 것입니다.


4

클래스에 대한 포인터 조작과 함께 static_cast를 사용하여 클래스에 명시 적으로 정의 된 변환을 수행하고 기본 유형 간의 표준 변환을 수행 할 수 있습니다.

double d = 3.14159265;
int    i = static_cast<int>(d);

4
왜 것 사람이 쓰기 static_cast<int>(d),하지만 때 (int)d훨씬 더 간결하고 읽기? (객체 포인터가 아닌 기본 유형의 경우를 의미합니다.)
Todd Lehman

@ gd1 — 왜 누군가가 일관성보다 가독성을 높이겠습니까? (실제 반 심각)
Todd Lehman

2
@ToddLehman : 나, 특정 유형에 대해 예외가 있다고 생각하면 나에게 특별한 의미가 없으며 나에게 이해가되지 않으며 가독성에 대한 귀하의 견해에 동의하지 않습니다. 다른 의견에 게시 한 이미지에서 볼 수 있듯이 짧아도 더 읽기 쉬운 것은 아닙니다.
gd1

2
static_cast는 매우 특정한 종류의 변환을하기위한 명확하고 의식적인 결정입니다. 따라서 의도가 명확 해집니다. 또한 코드 검토, 버그 또는 업그레이드 연습에서 변환을 위해 소스 파일을 검색하는 마커로 매우 편리합니다.
Persixty

1
@ToddLehman 대위법 : 왜 것 누구 쓰기 (int)d할 때 int{d}훨씬 더 읽을? 생성자 또는 함수와 같은 경우 ()구문은 복잡한 식에서 괄호의 악몽 같은 미로로 전환하기에는 그리 빠르지 않습니다. 이 경우에는 int i{d}대신에 사용 int i = (int)d됩니다. 훨씬 더 나은 IMO. 즉, 표현식에서 임시가 필요할 때 static_cast생성자를 사용하지 않았으며 결코 사용하지 않았습니다. 나는 (C)casts서둘러 디버그를 쓸 때만 사용합니다 cout...
underscore_d
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.