C ++에서`void *`가 암시 적으로 캐스트되지 않는 이유는 무엇입니까? 안전하게 승격됩니다. 그러나 C ++에서는 그렇지

C에서는 void *다른 포인터 유형으로 a 를 캐스트 할 필요가 없으며 항상 안전하게 승격됩니다. 그러나 C ++에서는 그렇지 않습니다. 예 :

int *a = malloc(sizeof(int));

C에서는 작동하지만 C ++에서는 작동하지 않습니다. (참고 : mallocC ++ 또는 그 문제 new를 사용해서는 안되며 대신 스마트 포인터 및 / 또는 STL을 선호해야한다는 것을 알고 있습니다. 이것은 순전히 호기심에서 비롯됩니다.) C ++ 표준 이이 암시 적 캐스트를 허용하지 않는 이유는 무엇입니까? C 표준이하는 동안?



답변

암시 적 유형 변환은 일반적으로 안전하지 않기 때문에 C ++는 C보다 입력에 더 안전한 자세를 취합니다.

대부분의 경우 변환에 오류가있는 경우에도 C는 일반적으로 암시 적 변환을 허용합니다. 왜냐하면 C는 프로그래머가 자신이하는 일을 정확히 알고 있다고 가정하기 때문입니다. 그렇지 않은 경우 컴파일러의 문제가 아니라 프로그래머의 문제입니다.

C ++은 일반적으로 오류가 될 수있는 것을 허용하지 않으며 타입 캐스트로 의도를 명시 적으로 명시해야합니다. C ++은 프로그래머 친화적이려고하기 때문입니다.

실제로 더 많이 입력해야 할 때 얼마나 친숙한 지 묻습니다.

글쎄, 당신은 어떤 프로그램, 어떤 프로그래밍 언어로든 주어진 코드 줄은 일반적으로 쓰여질 것보다 많은 시간을 읽을 것입니다 (*). 따라서 읽기 쉬움은 쓰기 쉬움보다 훨씬 중요합니다. 그리고 읽을 때 잠재적으로 안전하지 않은 변환이 명시 적 유형 캐스트를 통해 눈에 띄면 진행 상황을 이해하고 진행 상황이 실제로 무슨 일이 일어나고 있는지 확실하게 알 수 있습니다.

또한, 명시 적 캐스트를 입력해야하는 불편 함은 경고를 받았지만 결코 본 적이없는 잘못된 할당으로 인해 발생하는 버그를 찾기 위해 몇 시간의 문제 해결 시간의 불편함에 비해 사소한 것입니다.

(*) 이상적으로는 한 번만 작성되지만 재사용에 대한 적합성을 결정하기 위해 누군가가 그것을 검토해야 할 때마다, 그리고 문제 해결이 진행될 때마다 그리고 누군가가 근처에 코드를 추가해야 할 때마다 읽습니다. 그런 다음 근처 코드에 대한 문제 해결이 발생할 때마다. 이것은 “한 번만 쓰고 실행 한 다음 폐기”스크립트를 제외한 모든 경우에 해당되므로 대부분의 스크립팅 언어는 읽기 쉬운 것을 완전히 무시하고 쉽게 작성하는 데 도움이되는 구문을 가지고 있습니다. 펄이 완전히 이해할 수 없다고 생각한 적이 있습니까? 당신은 혼자가 아닙니다. 이러한 언어를 “쓰기 전용”언어로 생각하십시오.


답변

Stroustrup이 말한 내용은 다음과 같습니다. .

C에서는 void *를 T *로 암시 적으로 변환 할 수 있습니다. 이것은 안전하지 않다

그런 다음 void *가 어떻게 위험 할 수 있는지에 대한 예를 보여주고 다음과 같이 말합니다.

… 결과적으로 C ++에서 void *에서 T *를 얻으려면 명시 적 캐스트가 필요합니다. …

마지막으로 그는 다음과 같이 지적합니다.

C에서이 안전하지 않은 변환의 가장 일반적인 용도 중 하나는 malloc ()의 결과를 적절한 포인터에 할당하는 것입니다. 예를 들면 다음과 같습니다.

int * p = malloc (sizeof (int));

C ++에서 typesafe new 연산자를 사용하십시오.

int * p = 새로운 int;

그는 C ++의 디자인과 진화 에서 이것에 대해 더 자세히 설명합니다 .

따라서 언어 디자이너는 이것이 안전하지 않은 패턴이라고 생각하여 불법적으로 만들었고 패턴이 일반적으로 사용되는 방식을 대체하는 다른 방법을 제공했습니다.


답변

C에서는 다른 포인터 유형으로 void *를 캐스트 할 필요가 없으며 항상 안전하게 승격됩니다.

항상 홍보되지만, 거의 안전 하지는 않습니다. .

C ++는 C보다 안전한 유형 시스템을 사용하려고하기 때문에이 동작을 정확하게 비활성화합니다 . 이 동작은 안전 하지 않습니다 .


일반적으로 유형 변환에 대한 다음 3 가지 접근 방식을 고려하십시오.

  1. 사용자가 모든 것을 쓰도록 강요하므로 모든 전환이 명시 적입니다.
  2. 사용자가 자신이하는 일을 알고 있다고 가정하고 모든 유형을 다른 유형으로 변환
  3. 형식이 안전한 제네릭 (템플릿, 새로운 식), 명시적인 사용자 정의 변환 연산자를 사용하여 컴파일러가 완벽하게 볼 수없는 것만 명시 적으로 변환하도록하는 완전한 형식 시스템을 구현합니다.

글쎄, 1은 못 생겼고 어떤 일을하는 데 실질적인 장애물이지만, 큰주의가 필요한 곳에 진정으로 사용될 수 있습니다. C는 구현하기가 더 쉬운 2와 3을 구현하기는 어렵지만 더 안전한 3을 선택했습니다.


답변

정의상, void 포인터는 무엇이든 가리킬 수 있습니다. 모든 포인터를 빈 포인터로 변환 할 수 있으므로 동일한 값에 도달하면 다시 변환 할 수 있습니다. 그러나 다른 유형에 대한 포인터에는 정렬 제한과 같은 제약 조건이있을 수 있습니다. 예를 들어, 문자가 메모리 주소를 점유 할 수 있지만 주소 경계에서 정수를 시작해야하는 아키텍처를 상상해보십시오. 특정 아키텍처에서 정수 포인터는 한 번에 16, 32 또는 64 비트를 계산하여 char *가 실제로 메모리의 동일한 위치를 가리키는 동안 int *의 배수를 가질 수 있습니다. 이 경우, void *에서 변환하면 실제로 복구 할 수없는 비트를 반올림하므로 되돌릴 수 없습니다.

간단히 말해서, void 포인터는 다른 포인터가 가리킬 수없는 것을 포함하여 무엇이든 가리킬 수 있습니다. 따라서 void 포인터로의 변환은 안전하지만 다른 방법은 아닙니다.