etc./StackOverFlow

malloc의 결과를 캐스팅합니까?

청렴결백한 만능 재주꾼 2021. 11. 19. 23:42
반응형

질문자 :Patrick McDonald


이 질문 에서 누군가 가 내가 malloc 의 결과 를 캐스팅 하지 말아야 한다고 주석 에서 제안 했습니다 . 즉, 나는 이것을해야합니다 :

 int *sieve = malloc(sizeof(int) * length);

보다는:

 int *sieve = (int *) malloc(sizeof(int) * length);

왜 그럴까요?



TL;DR

 int *sieve = (int *) malloc(sizeof(int) * length);

두 가지 문제가 있습니다. 캐스트하고 sizeof에 대한 인수로 변수 대신 유형을 사용하고 있습니다. 대신 다음과 같이 하십시오.

 int *sieve = malloc(sizeof *sieve * length);

긴 버전

아니요 ; 다음과 같은 이유로 결과를 캐스팅 하지 않습니다.

  • void * 는 자동으로 다른 포인터 유형으로 안전하게 승격되기 때문에 필요하지 않습니다.
  • 코드에 혼란을 더하고 캐스트를 읽기가 쉽지 않습니다(특히 포인터 유형이 긴 경우).
  • 그것은 일반적으로 나쁜 자신을 반복하게 만듭니다.
  • <stdlib.h> 를 포함하는 것을 잊은 경우 오류를 숨길 수 있습니다. 이것은 충돌을 일으킬 수 있습니다(또는 더 심하게는 코드의 완전히 다른 부분에서 나중에까지 충돌을 일으키지 않음). 포인터와 정수의 크기가 다른 경우 어떻게 되는지 고려하십시오. 그런 다음 캐스팅하여 경고를 숨기고 반환된 주소의 일부를 잃을 수 있습니다. 참고: C99부터 암시적 함수는 C에서 사라졌고 선언되지 않은 함수가 int 반환한다는 자동 가정이 없기 때문에 이 점은 더 이상 관련이 없습니다.

해명으로, 노트 내가 말한 것이 아니라 "당신이 캐스팅 할 필요가 없습니다" "당신은 캐스팅하지 않습니다." 제 생각에는 캐스트를 제대로 잡았다고 해도 캐스트를 포함하는 것은 실패입니다. 단순히 그렇게 하는 것의 이점은 없지만 잠재적인 위험이 많이 있으며 출연자를 포함하는 것은 위험에 대해 알지 못한다는 것을 나타냅니다.

또한 주석가가 지적한 것처럼 위의 내용은 C++가 아닌 스트레이트 C에 대해 이야기하고 있습니다. 저는 C와 C++가 별개의 언어라고 굳게 믿습니다.

더 추가하기 위해 코드는 오류를 일으킬 수 int 반환 값을 저장하는 데 사용되는 포인터를 역참조하여 둘을 함께 "고정"하는 것이 좋습니다.

 int *sieve = malloc(length * sizeof *sieve);

length 를 앞으로 이동하고 sizeof 중복 괄호를 삭제합니다. 인수가 유형 이름인 경우 에만 필요합니다. 많은 사람들이 이것을 모르는 것(또는 무시하는 것)이 코드를 더 장황하게 만듭니다. 기억하세요: sizeof 는 함수가 아닙니다! :)


length 를 앞으로 이동 하면 일부 드문 경우에 가시성이 증가할 수 있지만 일반적인 경우에는 다음과 같이 표현식을 작성하는 것이 좋습니다.

 int *sieve = malloc(sizeof *sieve * length);

sizeof 먼저 유지하기 때문에 이 경우 곱셈이 최소한 size_t 수학으로 수행되도록 합니다.

비교: malloc(sizeof *sieve * length * width)malloc(length * width * sizeof *sieve) widthlength size_t 보다 작은 유형일 때 length * width 오버플로할 수 있습니다.


unwind

malloc 의 반환 값을 캐스팅할 필요가 없습니다. malloc 에 의해 반환된 void에 대한 포인터는 자동으로 올바른 유형으로 변환됩니다. 그러나 C++ 컴파일러로 코드를 컴파일하려면 캐스트가 필요합니다. 커뮤니티에서 선호하는 대안은 다음을 사용하는 것입니다.

 int *sieve = malloc(sizeof *sieve * length);

sieve 의 유형을 변경할 경우 표현식의 오른쪽을 변경하는 것에 대해 걱정할 필요가 없습니다.

사람들이 지적했듯이 캐스트는 나쁩니다. 특히 포인터 캐스트.


dirkgently

당신은 캐스트 때문에 않습니다 :

  • 그것은 C와 C++ 사이에서 코드를 더 이식 가능 하게 만들고 SO 경험에서 알 수 있듯이 많은 프로그래머가 실제로 C++(또는 C와 로컬 컴파일러 확장)로 작성할 때 C로 작성한다고 주장합니다.
  • 그렇게 하지 않으면 오류를 숨길 수 있습니다 . type * type ** 유형을 쓸 때 혼동을 일으키는 모든 SO 예에 유의하십시오.
  • 적절한 헤더 파일 #include 하는 데 실패했다는 사실을 눈치채지 못하게 한다는 생각 은 나무의 숲을 놓치는 것입니다. "프로토타입이 보이지 않는 것에 대해 컴파일러에게 불평하도록 요청하지 않았다는 사실에 대해 걱정하지 마십시오. 성가신 stdlib.h가 기억해야 할 정말 중요한 것입니다!"라고 말하는 것과 같습니다.
  • 이것은 추가적인 인지적 교차 점검을 강제합니다. 해당 변수의 원시 크기에 대해 수행 중인 산술 바로 옆에 원하는 유형을 배치합니다. malloc() 버그가 훨씬 빨리 포착된다는 것을 보여주는 SO 연구를 할 수 있다고 확신합니다. 주장과 마찬가지로 의도를 나타내는 주석은 버그를 줄입니다.
  • 기계가 확인할 수 있는 방식으로 자신을 반복하는 것은 종종 좋은 생각입니다. 사실, 그것이 주장이고 이 캐스트 사용이 주장입니다. 수년 전에 Turing이 아이디어를 내놓았기 때문에 Assertion은 여전히 코드를 수정하는 가장 일반적인 기술입니다.

Ron Burk

다른 사람들이 말했듯이 C에는 필요하지 않지만 C++에는 필요합니다. 어떤 이유로든 C++ 컴파일러로 C 코드를 컴파일할 생각이라면 다음과 같은 매크로를 대신 사용할 수 있습니다.

 #ifdef __cplusplus # define NEW(type, count) ((type *)calloc(count, sizeof(type))) #else # define NEW(type, count) (calloc(count, sizeof(type))) #endif

그렇게 하면 여전히 매우 간결한 방식으로 작성할 수 있습니다.

 int *sieve = NEW(int, 1);

C 및 C++용으로 컴파일됩니다.


quinmars

위키피디아에서 :

캐스팅의 장점

  • 캐스트를 포함하면 C 프로그램이나 함수를 C++로 컴파일할 수 있습니다.

  • 캐스트는 원래 char *를 반환했던 1989년 이전 버전의 malloc을 허용합니다.

  • 캐스팅은 개발자가 대상 포인터 유형이 변경되는 경우 유형 크기 조정의 불일치를 식별하는 데 도움이 될 수 있습니다. 특히 포인터가 malloc() 호출에서 멀리 선언된 경우(현대 컴파일러 및 정적 분석기는 캐스트를 요구하지 않고도 이러한 동작에 대해 경고할 수 있음)

캐스팅의 단점

  • ANSI C 표준에서는 캐스트가 중복됩니다.

  • 캐스트를 추가하면 malloc의 프로토타입이 있는 헤더 stdlib.h 를 포함하지 못하는 것을 마스킹할 수 있습니다. malloc에 대한 프로토타입이 없는 경우 표준에서는 C 컴파일러에서 malloc이 int를 반환한다고 가정해야 합니다. 캐스트가 없으면 이 정수가 포인터에 할당될 때 경고가 발행됩니다. 그러나 캐스트를 사용하면 이 경고가 생성되지 않고 버그가 숨겨집니다. 특정 아키텍처 및 데이터 모델(예: long 및 포인터가 64비트이고 int가 32비트인 64비트 시스템의 LP64)에서는 암시적으로 선언된 malloc이 32비트를 반환하므로 이 오류가 실제로 정의되지 않은 동작을 초래할 수 있습니다. 실제로 정의된 함수는 64비트 값을 반환합니다. 호출 규칙 및 메모리 레이아웃에 따라 스택 스매싱이 발생할 수 있습니다. 이 문제는 선언되지 않은 함수가 사용되었다는 경고를 균일하게 생성하여 경고가 계속 표시되기 때문에 최신 컴파일러에서 눈에 띄지 않을 가능성이 적습니다. 예를 들어, GCC의 기본 동작은 캐스트가 있는지 여부에 관계없이 "내장 함수의 암시적 선언과 호환되지 않음"이라는 경고를 표시하는 것입니다.

  • 포인터의 유형이 선언 시 변경되면 malloc이 호출되고 캐스트되는 모든 행을 변경해야 할 수도 있습니다.

캐스팅 없는 malloc이 선호되는 방법이고 대부분의 숙련된 프로그래머가 선택하지만 문제를 알고 있는 원하는 방법을 사용해야 합니다.

즉, C 프로그램을 C++로 컴파일해야 하는 경우(비록 별도의 언어이지만) malloc 을 사용한 결과를 캐스팅해야 합니다.


ashiquzzaman33

void 포인터를 다른 종류의 포인터로 암시적으로 변환할 수 있으므로 캐스트가 필요하지 않습니다. 하나를 사용하는 것은 우연한 관찰자에게 하나가 필요한 이유가 있다는 것을 암시할 수 있으며, 이는 오해의 소지가 있습니다.


PaulJWilliams

당신은 당신의 코드에 무의미한 혼란을 추가하기 때문에 malloc 의 결과를 캐스팅하지 않습니다.

malloc 의 결과를 캐스팅하는 가장 일반적인 이유는 C 언어가 어떻게 작동하는지 확신할 수 없기 때문입니다. 이것은 경고 신호입니다. 특정 언어 메커니즘이 어떻게 작동하는지 모른다면 추측 하지 마십시오. 그것을 찾거나 스택 오버플로에 문의하십시오.

일부 의견:

  • void 포인터는 명시적 캐스트 없이 다른 포인터 유형으로/에서 변환될 수 있습니다(C11 6.3.2.3 및 6.5.16.1).

  • void* 와 다른 포인터 유형 간의 암시적 캐스트를 허용하지 않습니다. 따라서 C++에서는 캐스트가 정확했을 것입니다. 그러나 C++로 프로그래밍한다면 malloc() 아닌 new 를 사용해야 합니다. 그리고 C++ 컴파일러를 사용하여 C 코드를 컴파일해서는 안 됩니다.

    동일한 소스 코드로 C와 C++를 모두 지원해야 하는 경우 컴파일러 스위치를 사용하여 차이점을 표시합니다. 두 언어 표준이 호환되지 않으므로 동일한 코드로 두 언어 표준을 모두 만족시키려고 하지 마십시오.

  • 헤더를 포함하는 것을 잊었기 때문에 C 컴파일러가 함수를 찾을 수 없다면 이에 대한 컴파일러/링커 오류가 발생합니다. <stdlib.h> 를 포함하는 것을 잊었다면 큰 문제가 되지 않습니다. 프로그램을 빌드할 수 없습니다.

  • 25년 이상 된 표준 버전을 따르는 고대 컴파일러에서 <stdlib.h> 를 포함하는 것을 잊어버리면 위험한 동작이 발생합니다. 고대 표준에서 보이는 프로토타입이 없는 함수는 암시적으로 반환 유형을 int 로 변환했기 때문입니다. malloc 에서 결과를 명시적으로 캐스팅하면 이 버그가 숨겨집니다.

    그러나 그것은 정말로 문제가 되지 않습니다. 25년 된 컴퓨터를 사용하지 않는데 왜 25년 된 컴파일러를 사용하겠습니까?


Lundin

void * 에서 다른 (데이터) 포인터로의 암시적 변환을 얻습니다.


EFraim

malloc() 이 반환한 값을 캐스팅할 필요가 없지만 아무도 지적하지 않은 것 같은 한 가지 사항을 추가하고 싶습니다.

고대에, 즉 ANSI Cvoid * 를 포인터의 제네릭 유형으로 char * 가 그러한 용도의 유형이었습니다. 이 경우 캐스트는 컴파일러 경고를 종료할 수 있습니다.

참조: C FAQ


Yu Hao

컴퓨터 공학을 공부하면서 내 경험을 추가하면 C로 작성하는 것을 본 두세 명의 교수가 항상 malloc을 캐스팅하지만 내가 요청한 한 사람은 (엄청난 이력서와 C에 대한 이해와 함께) 절대적으로 필요하지 않다고 말했습니다. 절대적으로 구체적이고 학생들이 절대적으로 구체적이라는 사고방식을 갖도록 하기 위해서만 사용되었습니다. 본질적으로 캐스팅은 작동 방식에 있어 아무 것도 변경하지 않으며, 정확히 말한 대로 수행하고, 메모리를 할당하고, 캐스팅에 영향을 미치지 않으며, 동일한 메모리를 얻고, 실수로 다른 것으로 캐스팅하더라도(그리고 어떻게든 컴파일러를 회피합니다. 오류) C는 동일한 방식으로 액세스합니다.

편집: 캐스팅에는 특정 포인트가 있습니다. 배열 표기법을 사용할 때 생성된 코드는 다음 요소의 시작 부분에 도달하기 위해 얼마나 많은 메모리 위치를 이동해야 하는지 알아야 하며 이는 캐스팅을 통해 달성됩니다. 이렇게 하면 double의 경우 8바이트 앞으로 이동하고 int의 경우 4로 이동하는 식으로 진행된다는 것을 알 수 있습니다. 따라서 포인터 표기법을 사용하면 효과가 없으며 배열 표기법에서는 필요하게 됩니다.


user3079666

void* 반환하고 void* 는 모든 데이터 유형을 가리킬 수 있기 때문에 malloc 의 결과를 캐스팅해야 하는 것은 아닙니다.


user968000

GNU C 라이브러리 참조 매뉴얼은 다음과 같이 말합니다.

void * 유형을 자동으로 다른 유형의 포인터 malloc 의 결과를 캐스트 없이 모든 포인터 변수에 저장할 수 있습니다. 그러나 캐스트는 할당 연산자 이외의 컨텍스트에서 또는 코드를 기존 C에서 실행하려는 경우에 필요합니다.

그리고 실제로 ISO C11 표준 (p347)은 다음과 같이 말합니다.

할당이 성공하면 반환된 포인터는 기본 정렬 요구 사항이 있는 모든 유형의 개체에 대한 포인터에 할당될 수 있도록 적절하게 정렬된 다음 할당된 공간에서 이러한 개체 또는 이러한 개체의 배열에 액세스하는 데 사용됩니다. 공간이 명시적으로 할당 해제됨)


Slothworks

무효 포인터는 일반 객체 포인터이고 C는 무효 포인터 유형에서 다른 유형으로의 암시적 변환을 지원하므로 명시적으로 유형 변환할 필요가 없습니다.

그러나 암시적 변환을 지원하지 않는 C++ 플랫폼에서 동일한 코드가 완벽하게 호환되도록 하려면 유형 변환을 수행해야 하므로 모두 사용성에 달려 있습니다.


Endeavour

반환된 유형은 void*이며 역참조 가능하도록 원하는 데이터 포인터 유형으로 캐스트될 수 있습니다.


swaps

프로그래밍 언어와 컴파일러에 따라 다릅니다. malloc 을 사용하는 경우 자동으로 형변환을 입력하므로 형변환을 입력할 필요가 없습니다. 그러나 C++를 사용하는 경우 mallocvoid* 유형을 반환하므로 캐스트를 입력해야 합니다.


Jeyamaran

C 언어에서 void 포인터는 모든 포인터에 할당될 수 있으므로 유형 캐스트를 사용하지 않아야 합니다. "유형 안전" 할당을 원하면 C 프로젝트에서 항상 사용하는 다음 매크로 함수를 추천할 수 있습니다.

 #include <stdlib.h> #define NEW_ARRAY(ptr, n) (ptr) = malloc((n) * sizeof *(ptr)) #define NEW(ptr) NEW_ARRAY((ptr), 1)

이것들이 제자리에 있으면 간단히 말할 수 있습니다.

 NEW_ARRAY(sieve, length);

비동적 배열의 경우 세 번째 필수 기능 매크로는 다음과 같습니다.

 #define LEN(arr) (sizeof (arr) / sizeof (arr)[0])

배열 루프를 더 안전하고 편리하게 만듭니다.

 int i, a[100]; for (i = 0; i < LEN(a); i++) { ... }

August Karlstrom

GCC와 Clang에 익숙한 사람들은 버릇이 있습니다. 그렇게 좋은 것만은 아닙니다.

나는 내가 사용해야 하는 엄청나게 오래된 컴파일러에 의해 몇 년 동안 꽤 소름이 돋았다. 종종 회사와 관리자는 컴파일러를 변경할 때 매우 보수적인 접근 방식을 채택하고 새로운 컴파일러(더 나은 표준 준수 및 코드 최적화 포함)가 시스템에서 작동하는지 테스트조차 하지 않습니다. 일하는 개발자의 실제 현실은 코딩할 때 기반을 덮어야 하고 불행히도 코드에 적용할 컴파일러를 제어할 수 없는 경우 malloc을 캐스팅하는 것이 좋은 습관이라는 것입니다.

또한 많은 조직에서 자체 코딩 표준을 적용하고 정의된 경우 사람들이 따라야 하는 방법 을 제안합니다. 명시적인 지침이 없을 때 나는 표준을 맹목적으로 준수하기보다는 어디에서나 컴파일하는 경향이 있습니다.

현재 기준에서는 필요하지 않다는 주장은 상당히 타당합니다. 그러나 그 주장은 현실 세계의 실용성을 생략합니다. 우리는 그 시대의 기준에 의해서만 지배되는 세상이 아니라 내가 "현지 경영의 현실 분야"라고 부르는 것의 실용성에 의해 코딩되는 세상에서 코딩합니다. 그리고 그것은 시공간보다 더 많이 구부러지고 뒤틀렸습니다. :-)

YMMV.

나는 malloc 캐스팅을 방어적인 작업으로 생각하는 경향이 있습니다. 예쁘지도 않고 완벽하지도 않지만 일반적으로 안전합니다. (당신이 그 다음 인 stdlib.h 포함되지 않은 한 경우 솔직히, 당신은 malloc에 캐스팅보다 훨씬 더 많은 문제를했습니다!).


StephenG

malloc() 의 결과를 캐스팅하지 않습니다.

일반적으로 void * 캐스팅하지 않습니다 .

그렇게 하지 않는 일반적인 이유는 #include <stdlib.h> 실패가 눈에 띄지 않을 수 있기 때문입니다. 이것은 C99가 암시적 함수 선언을 불법으로 만들었기 때문에 이제 더 이상 문제가 되지 않습니다. 따라서 컴파일러가 C99 이상을 준수하면 진단 메시지를 받게 됩니다.

그러나 불필요한 포인터 캐스트를 도입하지 않는 훨씬 더 강력한 이유가 있습니다.

C에서 포인터 캐스트는 거의 항상 오류 입니다. 이는 다음 규칙 때문입니다( N1570의 §6.5 p7 , C11의 최신 초안).

객체는 다음 유형 중 하나를 갖는 lvalue 표현식에 의해서만 액세스되는 저장된 값을 가져야 합니다.
— 객체의 유효 유형과 호환되는 유형,
— 객체의 유효 유형과 호환되는 유형의 정규화된 버전,
— 객체의 유효 유형에 해당하는 서명되거나 서명되지 않은 유형인 유형,
— 객체의 유효 유형의 한정된 버전에 해당하는 서명된 또는 서명되지 않은 유형인 유형,
- 멤버 중 앞서 언급한 유형 중 하나를 포함하는 집합체 또는 공용체 유형(재귀적으로 하위 집합체 또는 포함된 공용체의 구성원 포함), 또는
— 문자 유형.

이것은 엄격한 앨리어싱 규칙 이라고도 합니다. 따라서 다음 코드는 정의되지 않은 동작입니다 .

 long x = 5; double *p = (double *)&x; double y = *p;

그리고 때로는 놀랍게도 다음도 있습니다.

 struct foo { int x; }; struct bar { int x; int y; }; struct bar b = { 1, 2}; struct foo *p = (struct foo *)&b; int z = p->x;

때때로, 당신은 캐스트 포인터에 필요하지만 엄격한 앨리어싱 규칙을 부여 할, 당신은 매우 신중해야합니다. 따라서 코드에서 포인터 캐스트가 발생하면 유효성을 다시 확인해야 합니다 . 따라서 불필요한 포인터 캐스트를 작성하지 마십시오.

헐 박사

한마디로 : C에서, 포인터 캐스트의 발생이 특별한 관심을 필요로하는 코드에 대한 붉은 깃발을 제기해야하기 때문에, 불필요한 포인터 캐스트를 작성해서는 안됩니다.


참고 사항:

  • 포인터를 인쇄하려는 경우와 같이 실제로 void * 대한 캐스트가 필요한 경우가 있습니다.

     int x = 5; printf("%p\n", (void *)&x);

    여기서 캐스트가 필요합니다. 왜냐하면 printf() 는 가변 함수이므로 암시적 변환이 작동하지 않기 때문입니다.

  • C++에서는 상황이 다릅니다. 포인터 유형 캐스팅은 파생 클래스의 개체를 다룰 때 다소 일반적이고 정확합니다. 따라서 C++에서 void * 로의 변환이 암시적이지 않다는 것은 의미가 있습니다. C++에는 다양한 캐스팅 방식이 있습니다.


user2371524

나는 단순히 유형 시스템의 못생긴 구멍에 대한 비승인을 보여주기 위해 캐스트를 넣었습니다. 그러면 잘못된 변환을 가져오는 데 캐스트가 사용되지 않더라도 다음 스니펫과 같은 코드를 진단 없이 컴파일할 수 있습니다.

 double d; void *p = &d; int *q = p;

나는 그것이 존재하지 않기를 원하고 (C++에는 없기 때문에) 캐스팅합니다. 내 취향과 프로그래밍 정책을 나타냅니다. 나는 포인터를 던질 뿐 아니라 효과적으로 투표를 하고 어리석은 악마를 쫓아내고 있습니다. 내가 실제로 어리석음을 내쫓을 수 없다면 적어도 항의의 몸짓으로 그렇게 하고 싶다는 의사를 표현하게 해주세요.

사실, 좋은 습관은 unsigned char * 를 반환하는 함수로 malloc (및 친구)을 감싸고 기본적으로 코드에서 void * 를 사용하지 않는 것입니다. 모든 객체에 대한 일반 포인터가 필요한 경우 char * 또는 unsigned char * 를 사용하고 양방향으로 캐스트하십시오. 탐닉할 수 있는 한 가지 휴식은 아마도 memsetmemcpy 와 같은 기능을 캐스트 없이 사용하는 것입니다.

캐스팅 및 C++ 호환성 주제에 대해 C 및 C++로 컴파일되도록 코드를 작성하면(이 경우 void * 이외의 다른 것에 할당할 때 malloc 의 반환 값 을 캐스팅해야 함 ) 다음을 수행할 수 있습니다. 자신에게 매우 유용한 것: C++로 컴파일할 때는 C++ 스타일 캐스트로 변환하는 캐스팅에 매크로를 사용할 수 있지만 C로 컴파일할 때는 C 캐스트로 줄일 수 있습니다.

 /* In a header somewhere */ #ifdef __cplusplus #define strip_qual(TYPE, EXPR) (const_cast<TYPE>(EXPR)) #define convert(TYPE, EXPR) (static_cast<TYPE>(EXPR)) #define coerce(TYPE, EXPR) (reinterpret_cast<TYPE>(EXPR)) #else #define strip_qual(TYPE, EXPR) ((TYPE) (EXPR)) #define convert(TYPE, EXPR) ((TYPE) (EXPR)) #define coerce(TYPE, EXPR) ((TYPE) (EXPR)) #endif

이러한 매크로를 준수하는 경우 grep 검색은 모든 캐스트의 위치를 표시하므로 잘못된 것이 있는지 검토할 수 있습니다.

그런 다음 앞으로 C++로 코드를 정기적으로 컴파일하면 적절한 캐스트를 사용해야 합니다. 예를 들어, 당신 const 또는 volatile 을 제거하기 strip_qual 을 사용하지만 프로그램이 유형 변환이 포함된 방식으로 변경되면 진단을 받게 되며 캐스트 조합을 사용하여 원하는 변환.

이러한 매크로를 준수하는 데 도움이 되도록 GNU C++(C가 아님!) 컴파일러에는 C 스타일 캐스트의 모든 발생에 대해 생성되는 선택적 진단이라는 아름다운 기능이 있습니다.

     -Wold-style-cast(C++ 및 Objective-C++만 해당)
         void가 아닌 유형으로의 이전 스타일(C 스타일) 캐스트가 사용되는 경우 경고
         C++ 프로그램 내에서. 새로운 스타일의 캐스트(dynamic_cast,
         static_cast, reinterpret_cast 및 const_cast)는 덜 취약합니다.
         의도하지 않은 효과에 훨씬 더 쉽게 검색할 수 있습니다.

C 코드가 C++로 컴파일되는 경우, 이 -Wold-style-cast (type) 캐스팅 구문의 모든 발생을 찾고 적절한 것으로 대체하여 이러한 진단에 후속 조치를 취할 수 있습니다. 위의 매크로(또는 필요한 경우 조합) 중에서 선택합니다.

이러한 변환 처리는 "Clean C"에서 작업하기 위한 가장 큰 단일 독립형 기술 정당화입니다. 결합된 C 및 C++ 방언은 차례로 malloc 의 반환 값 캐스팅을 기술적으로 정당화합니다.


Kaz

캐스트를 하는 것을 선호하지만 수동으로 하지 않습니다. 내가 가장 좋아하는 것은 glib의 g_newg_new0 glib가 사용되지 않는다면 비슷한 매크로를 추가할 것입니다. 이러한 매크로는 유형 안전성을 손상시키지 않으면서 코드 중복을 줄입니다. 유형이 잘못되면 void가 아닌 포인터 사이에 암시적 캐스트가 발생하여 경고(C++의 오류)가 발생합니다. g_newg_new0 을 정의하는 헤더를 포함하는 것을 잊으면 오류가 발생합니다. g_newg_new0 calloc 보다 적은 인수를 취하는 malloc 과 달리 동일한 인수를 취합니다. 0 을 추가하면 0으로 초기화된 메모리를 얻을 수 있습니다. 코드는 변경 없이 C++ 컴파일러로 컴파일할 수 있습니다.


proski

가능할 때마다 C로 프로그래밍할 때 가장 좋은 방법은 다음과 같습니다.

  1. 모든 경고가 켜져 있는 C 컴파일러를 통해 프로그램을 컴파일하고 -Wall 및 모든 오류 및 경고를 수정합니다.
  2. auto 선언된 변수가 없는지 확인하십시오.
  3. -Wall-std=c++11 과 함께 C++ 컴파일러를 사용하여 컴파일합니다. 모든 오류 및 경고를 수정합니다.
  4. 이제 C 컴파일러를 사용하여 다시 컴파일하십시오. 이제 프로그램이 경고 없이 컴파일되고 더 적은 수의 버그가 포함되어야 합니다.

이 절차를 통해 C++ 엄격한 유형 검사를 활용하여 버그 수를 줄일 수 있습니다. stdlib.h 를 포함하도록 강제합니다. 그렇지 않으면

malloc 이 선언되지 않았습니다.

malloc 의 결과를 캐스트하도록 강제합니다. 그렇지 않으면

void* 에서 T* 로의 잘못된 변환

또는 목표 유형이 무엇인지.

내가 찾을 수 있는 C++ 대신 C로 작성함으로써 얻을 수 있는 유일한 이점은 다음과 같습니다.

  1. C에는 잘 지정된 ABI가 있습니다.
  2. C++는 더 많은 코드를 생성할 수 있습니다[예외, RTTI, 템플릿, 런타임 다형성]

두 번째 단점은 정적 다형성 기능과 함께 C에 공통적인 부분 집합을 사용할 때 이상적인 경우 사라져야 합니다.

C++ 엄격한 규칙이 불편하다고 생각하는 사람들을 위해 유추된 유형과 함께 C++11 기능을 사용할 수 있습니다.

 auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...

user877329

이 질문은 의견 기반 남용의 대상입니다.

가끔 다음과 같은 댓글을 봅니다.

malloc의 결과를 캐스팅하지 마십시오.

또는

malloc의 결과를 캐스팅하지 않는 이유

OP가 캐스팅을 사용하는 질문에. 댓글 자체에는 이 질문에 대한 하이퍼링크가 포함되어 있습니다.

그것은 어떤 면에서도 부적절하고 올바르지 않습니다. 진정으로 자신의 코딩 스타일의 문제일 때 옳고 그름은 없습니다.


왜 이런 일이 발생합니까?

두 가지 이유를 기반으로 합니다.

  1. 이 질문은 실제로 의견 기반입니다. 기술적으로 질문은 몇 년 전에 의견 기반으로 마감되어야 했습니다. " 해야합니까? "또는 " 하지 마십시오 "또는 이에 상응하는 " 해야합니까 "또는 " 해야합니까? "라는 질문은 자신의 의견에 대한 태도 없이 집중적으로 대답할 수 없습니다. 질문을 닫는 이유 중 하나는 여기에 잘 표시된 것처럼 "의견 기반 답변으로 이어질 수 있기" 때문입니다.

  2. 많은 답변( @unwind 의 가장 명백하고 허용되는 답변 포함)은 완전히 또는 거의 전적으로 의견 기반입니다(캐스팅을 수행하거나 자신을 반복하는 경우 코드에 추가되는 신비한 "클러터"는 나쁠 것입니다). 캐스트를 생략하는 명확하고 집중된 경향. 그들은 한쪽에서 캐스트의 중복성에 대해 논쟁하지만 더 나쁜 것은 프로그래밍 자체의 버그/실패로 인한 버그를 해결하기 위해 - malloc() 을 사용하려면 #include <stdlib.h> 하지 않는 것입니다.


나는 개인적인 의견을 적게 가지고 논의 된 몇 가지 점에 대한 진정한 견해를 가져오고 싶습니다. 특히 다음과 같은 몇 가지 사항에 유의해야 합니다.

  1. 자신의 의견에 빠질 수 있는 매우 민감한 질문에는 중립적인 장단점이 있는 답변이 필요합니다. 단점이나 장점뿐만이 아닙니다.

    장단점에 대한 좋은 개요가 이 답변에 나열되어 있습니다.

    https://stackoverflow.com/a/33047365/12139179

    (개인적으로 그런 이유 때문에 지금까지 가장 좋은 답변이라고 생각합니다.)


  1. 캐스트의 누락을 추론하기 위해 접하게 되는 한 가지 이유는 캐스트가 버그를 숨길 수 있다는 것입니다.

    이 질문에 표시된 것처럼 int (암시적 함수는 C99 이후 표준에서 사라졌음) 및 sizeof(int) != sizeof(int*) 를 반환하는 암시적으로 선언된 malloc()

    이 코드가 64비트 아키텍처에서는 세그폴트하지만 32비트에서는 제대로 작동하는 이유는 무엇입니까?

    캐스트는 버그를 숨길 것입니다.

    malloc() 사용할 때 stdlib.h 포함하지 않는 더 큰 버그에 대한 전진적인 솔루션일 뿐이므로 이야기의 절반만 보여줍니다.

    이것은 결코 심각한 문제가 아닐 것입니다.

    1. C99 이상을 준수하는 컴파일러를 사용하고(권장되고 필수 사항이어야 함)

    2. malloc() 을 사용하려는 경우 stdlib.h 를 포함하는 것을 stdlib.h 됩니다. 이는 엄청난 버그입니다.


  1. 어떤 사람들은 C++에서 캐스트가 의무화되기 때문에 C 코드의 C++ 준수에 대해 논쟁합니다.

    우선 일반적으로 말하자면 C++ 컴파일러로 C 코드를 컴파일하는 것은 좋은 습관이 아닙니다.

    C와 C++는 사실 의미 체계가 다른 완전히 다른 두 언어입니다.

    그러나 정말로 C 코드를 C++와 호환되도록 만들고 싶거나 필요하다면 캐스트 대신 컴파일러 스위치를 사용하십시오.

    캐스트는 중복되거나 심지어 유해한 것으로 선언되는 경향이 있으므로 캐스팅이 유용하거나 심지어 필요한 이유를 제공하는 다음 질문에 초점을 맞추고 싶습니다.


  1. 할당된 포인터의 유형(그리고 그에 따라 캐스트의 유형)이 각각 변경될 때 캐스트가 유용하지 않을 수 있지만 대부분의 경우 그럴 가능성은 없습니다. 그런 다음 모든 캐스트도 유지/변경해야 하며 코드에서 메모리 관리 기능에 대한 수천 개의 호출이 있는 경우 실제로 요약하고 유지 관리 효율성을 감소시킬 수 있습니다.

요약:

사실, 할당된 포인터가 기본 정렬 요구 사항(모든 개체의 대부분을 포함)의 개체를 가리키는 경우 C 표준(이미 ANSI-C(C89/C90) 이후)에 따라 캐스트가 중복됩니다.

이 경우 포인터가 자동으로 정렬되므로 캐스트를 수행할 필요가 없습니다.

"aligned_alloc, calloc, malloc 및 realloc 함수에 대한 연속적인 호출에 의해 할당된 스토리지의 순서와 연속성은 지정되지 않았습니다. 할당이 성공하면 반환된 포인터는 적절하게 정렬되어 다음을 사용하는 모든 유형의 객체에 대한 포인터에 할당될 수 있습니다. 기본적인 정렬 요구 사항을 충족 한 다음 할당된 공간에서 이러한 객체 또는 이러한 객체의 배열에 액세스하는 데 사용됩니다(공간이 명시적으로 할당 해제될 때까지)."

출처: C18, §7.22.3/1


" 기본 정렬 _Alignof (max_align_t) 보다 작거나 같은 유효한 정렬입니다. 기본 정렬은 모든 저장 기간의 개체에 대한 구현에 의해 지원되어야 합니다. 다음 유형의 정렬 요구 사항은 기본 정렬이어야 합니다.

- 모든 원자, 한정 또는 비한정 기본 유형;

- 모든 원자적, 한정된 또는 한정되지 않은 열거형;

— 모든 원자, 규정 또는 규정되지 않은 포인터 유형;

— 요소 유형에 기본적인 정렬 요구 사항이 있는 모든 배열 유형;57)

- 완전한 객체 유형으로 7절에 명시된 모든 유형;

— 모든 요소에 기본 정렬 요구 사항이 있는 유형이 있고 요소에 기본 정렬이 아닌 정렬을 지정하는 정렬 지정자가 없는 모든 구조 또는 결합 유형.

  1. 6.2.1에 명시된 대로, 나중 선언은 이전 선언을 숨길 수 있습니다."

출처: C18, §6.2.8/2

그러나 확장된 정렬 요구 사항의 구현 정의 개체에 대해 메모리를 할당하는 경우 캐스트가 필요합니다.

확장 정렬 _Alignof (max_align_t) 보다 큰 정렬로 표시됩니다. 확장된 정렬이 지원되는지 여부와 지원되는 저장 기간은 구현에 따라 정의됩니다. 확장된 정렬 요구 사항이 있는 유형은 오버 정렬된 유형입니다.58)

원천. C18, §6.2.8/3

다른 모든 것은 특정 사용 사례와 자신의 의견의 문제입니다.

자신을 교육하는 방법에주의하십시오.

나는 당신이 지금까지 만들어진 모든 답변을 먼저 주의 깊게 읽고(실패를 가리킬 수 있는 댓글도 포함) 그런 다음 특정 경우 malloc() 의 결과를 캐스팅하거나 캐스팅하지 않은 경우 자신의 의견을 구축할 것을 권장합니다. .

참고:

그 질문에 옳고 그른 대답은 없습니다. 그것은 스타일의 문제이며 당신이 선택하는 방식을 스스로 결정합니다(물론 교육이나 직업에 의해 강요받지 않는 경우). 그 점을 인지하시고 속지 마시기 바랍니다 .


마지막 참고 사항: 저는 최근에 이 질문을 의견 기반으로 종료하기로 투표했습니다. 이는 수년 동안 실제로 필요했습니다. 닫기/재개방 권한이 있다면 저도 그렇게 하도록 초대하고 싶습니다.


RobertS supports Monica Cellio

캐스팅은 C가 아닌 C++ 전용입니다. C++ 컴파일러를 사용하는 경우 C 컴파일러로 변경하는 것이 좋습니다.


user3949394

malloc의 캐스팅은 C에서는 불필요하지만 C++에서는 필수입니다.

C에서는 다음과 같은 이유로 캐스팅이 필요하지 않습니다.

  • void * 는 C의 경우 다른 포인터 유형으로 자동으로 안전하게 승격됩니다.
  • <stdlib.h> 를 포함하는 것을 잊은 경우 오류를 숨길 수 있습니다. 이로 인해 충돌이 발생할 수 있습니다.
  • 포인터와 정수의 크기가 다른 경우 캐스팅하여 경고를 숨기고 반환된 주소의 일부를 잃을 수 있습니다.
  • malloc 이 호출되고 캐스트되는 모든 행을 변경해야 할 수도 있습니다.

반면에 캐스팅은 프로그램의 이식성을 높일 수 있습니다. 즉, C 프로그램이나 함수를 C++로 컴파일할 수 있습니다.


Aashish

void 포인터 뒤에 있는 개념은 모든 데이터 유형으로 캐스트될 수 있기 때문에 malloc이 void를 반환한다는 것입니다. 또한 자동 유형 변환에 대해 알고 있어야 합니다. 따라서 포인터를 캐스팅해야 하지만 반드시 캐스팅해야 하는 것은 아닙니다. 코드를 깨끗하게 유지하고 디버깅하는 데 도움이 됩니다.


iec2011007

무효 포인터는 일반 포인터이고 C는 무효 포인터 유형에서 다른 유형으로의 암시적 변환을 지원하므로 명시적으로 유형 변환할 필요가 없습니다.

그러나 암시적 변환을 지원하지 않는 C++ 플랫폼에서 동일한 코드가 완벽하게 호환되도록 하려면 유형 변환을 수행해야 하므로 모두 사용성에 달려 있습니다.


dhana govindarajan

  1. 다른 사람이 언급했듯이 C에는 필요하지 않지만 C++에는 필요합니다.

  2. 캐스트를 포함하면 C 프로그램이나 함수를 C++로 컴파일할 수 있습니다.

  3. C에서는 void *가 자동으로 안전하게 다른 포인터 유형으로 승격되기 때문에 필요하지 않습니다.

  4. 그러나 그런 다음 캐스트하면 stdlib.h 를 포함하는 것을 잊은 경우 오류를 숨길 수 있습니다. 이것은 충돌을 일으킬 수 있습니다(또는 더 심하게는 코드의 완전히 다른 부분에서 나중에까지 충돌을 일으키지 않음).

    stdlib.h 에 malloc의 프로토타입이 포함되어 있기 때문입니다. malloc에 대한 프로토타입이 없는 경우 표준에서는 C 컴파일러에서 malloc이 int를 반환한다고 가정해야 합니다. 캐스트가 없으면 이 정수가 포인터에 할당될 때 경고가 발행됩니다. 그러나 캐스트를 사용하면 이 경고가 생성되지 않고 버그가 숨겨집니다.


Mohit

나를 위해, 테이크 홈 여기 결론은 캐스팅이다 malloc C에서 완전히 필요는 없지만 당신은 그러나 캐스팅 경우, 그 영향을 실 거예요 mallocmalloc 여전히 귀하의 요청 축복 메모리 공간을 할당합니다. 또 다른 가정은 사람들이 캐스팅을 하는 이유 또는 이유 중 하나이며 C 또는 C++에서 동일한 프로그램을 컴파일할 수 있도록 하기 위한 것입니다.

다른 이유가 있지만 거의 확실하게 다른 이유 때문에 조만간 심각한 문제에 직면하게 될 것입니다.


pasignature

출처 : http:www.stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc

반응형