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

Mar 03 2009

에서 이 질문에 , 누군가가에서 제안 코멘트 내가해야 하지 의 결과 캐스트 malloc, 즉

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

보다는 :

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

왜 그럴까요?

답변

2285 unwind Mar 03 2009 at 17:17

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

  • 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)번째는 오버 플로우 수 length * widthwidthlength보다 작은 유형입니다 size_t.

387 dirkgently Mar 03 2009 at 17:17

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

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

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

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

360 RonBurk Feb 14 2013 at 23:15

당신은 않습니다 , 캐스팅 이유는

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

다른 사람들이 언급했듯이 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 ++ 용으로 컴파일됩니다.

146 ashiquzzaman33 Oct 10 2015 at 04:23

보내는 사람 위키 백과 :

캐스팅의 장점

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

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

  • 캐스팅은 특히 포인터가 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.

108 PaulJWilliams Mar 03 2009 at 17:18

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

104 Lundin Mar 20 2014 at 22:53

결과는 캐스트하지 않습니다. malloc그렇게하면 코드에 무의미한 혼란이 추가되기 때문입니다.

사람들이 결과를 캐스팅하는 가장 일반적인 이유 malloc는 C 언어가 어떻게 작동하는지 잘 모르기 때문입니다. 그것은 경고 신호입니다. 특정 언어 메커니즘이 어떻게 작동하는지 모른다 면 추측 하지 마십시오 . 찾아 보거나 Stack Overflow에 문의하세요.

몇 가지 의견 :

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

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

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

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

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

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

95 EFraim Mar 03 2009 at 17:16

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

72 YuHao Jun 10 2013 at 00:31

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

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

참조 : C FAQ

55 user3079666 Mar 29 2014 at 01:21

내 경험을 더하고 컴퓨터 공학을 공부하는 것만으로도 C로 쓴 것을 본 두 세 명의 교수가 항상 malloc을 던지는 것을 보았지만 내가 요청한 (엄청난 CV와 C에 대한 이해로) 절대적으로 불필요하다고 말했지만 예전에는 절대적으로 구체적이고 학생들이 절대적으로 구체적이라는 사고 방식을 갖도록했습니다. 본질적으로 캐스팅은 그것이 작동하는 방식에 어떤 변화도주지 않으며, 정확히 말한대로 수행하고, 메모리를 할당하고, 캐스팅이 영향을주지 않고, 동일한 메모리를 얻습니다. 실수로 다른 것으로 캐스팅하더라도 (그리고 어떻게 든 컴파일러를 피합니다. 오류) C는 동일한 방식으로 액세스합니다.

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

53 user968000 Feb 08 2013 at 05:22

malloc반환 void*하고 a void*는 모든 데이터 유형을 가리킬 수 있으므로 의 결과를 반드시 캐스팅 할 필요는 없습니다.

37 Slothworks Oct 10 2015 at 00:47

다음은 GNU C Library Reference 매뉴얼이 말하는 것입니다.

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

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

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

35 Endeavour Jul 13 2014 at 13:42

void 포인터는 제네릭 객체 포인터이고 C는 void 포인터 유형에서 다른 유형으로의 암시 적 변환을 지원하므로 명시 적으로 유형 캐스팅 할 필요가 없습니다.

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

30 swaps Apr 26 2013 at 23:43

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

29 Jeyamaran Mar 17 2014 at 20:16

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

28 AugustKarlstrom Sep 04 2015 at 18:52

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++) {
   ...
}
18 StephenG Dec 05 2015 at 00:27

GCC와 Clang에 익숙한 사람들은 버릇이 없습니다. 밖에서 그렇게 좋지는 않습니다.

나는 내가 사용하도록 요구받은 엄청나게 오래된 컴파일러에 의해 수년 동안 꽤 끔찍했습니다. 종종 회사와 관리자는 컴파일러 변경에 대해 매우 보수적 인 접근 방식을 채택 하고 새로운 컴파일러 (더 나은 표준 준수 및 코드 최적화 기능 포함)가 시스템에서 작동하는지 테스트 하지도 않습니다 . 일하는 개발자를위한 실질적인 현실은 코딩 할 때 기반을 다룰 필요가 있으며, 불행히도 어떤 컴파일러가 코드에 적용될 수 있는지 제어 할 수 없다면 malloc을 캐스팅하는 것이 좋은 습관이라는 것입니다.

많은 조직들이 자신의 코딩 표준을 적용하는 것이 또한 제안 것을 가 정의되어있는 경우 방법 사람들이 수행해야합니다. 명시적인 지침이없는 경우에는 표준을 철저히 준수하기보다는 모든 곳에서 컴파일하는 경향이 있습니다.

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

YMMV.

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

16 Noname Aug 16 2017 at 19:25

아니요, 결과는 캐스트하지 않습니다 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;

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

tl; dr

한마디로 : C에서, 때문에 어떤 의 발생 포인터 캐스트는 특별한주의를 필요로하는 코드에 대한 붉은 깃발을 제기해야합니다, 당신은 쓸 안 불필요한 포인터 캐스트를.


참고 사항 :

  • 실제로 캐스트가 필요한 경우가 있습니다 void *. 예를 들어 포인터를 인쇄하려는 경우 :

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

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

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

15 Kaz Mar 30 2016 at 07:23

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

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

나는 그것이 존재하지 않았 으면 좋겠다 (그리고 그것은 C ++에 있지 않다) 그래서 나는 캐스팅한다. 그것은 나의 취향과 나의 프로그래밍 정치를 나타냅니다. 나는 포인터를 던질뿐만 아니라 효과적으로 투표를하고 어리석은 악마를 쫓아 내고있다 . 내가 실제로 어리 석음을 쫓아 낼 수 없다면 , 적어도 항의하는 몸짓으로 그렇게하고 싶다는 소망을 표현할 수 있도록하자.

사실, 좋은 방법은를 malloc반환하는 함수 로 랩핑 (및 친구)하는 unsigned char *것이며 기본적으로 void *코드에서 사용하지 않는 것 입니다. 당신이 일반적인 포인터 - 투 - 어떤 객체를 필요로한다면,를 사용 char *하거나 unsigned char *, 두 방향으로 캐스트를 가지고있다. 탐닉 할 수있는 한 가지 이완은 아마도 캐스트 memset와 같은 기능을 사용 하거나 사용 memcpy하지 않는 것입니다.

당신이 이렇게 코드를 작성하는 경우 주조 및 C ++ 호환성의 주제에, 그것은 C와 C ++에서 (이 경우 당신이로 컴파일하는 것이 필요 의 반환 값 캐스트 malloc가 아닌 다른 뭔가를 할당 할 때를 void *), 당신은 매우 유용 할 수 있습니다 자신을위한 것 : 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 ++로 코드를 정기적으로 컴파일하면 적절한 캐스트 사용이 강제됩니다. 예를 들어, 당신이 사용하는 경우 strip_qual단지를 제거 const하거나 volatile하지만, 형식 변환은 이제 포함되는 방식으로 프로그램 변경, 당신은 진단을 얻을 것이다, 당신은 원하는 변환을 얻을 캐스트의 조합을 사용해야합니다.

이러한 매크로를 준수 할 수 있도록 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)하여 코드에 포함될 수 있는 캐스팅 구문 의 모든 발생을 찾고 위의 매크로 (또는 a) 중에서 적절한 선택 항목으로 대체하여 이러한 진단을 추적 할 수 있습니다. 필요한 경우 조합).

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

15 proski Jun 29 2016 at 14:30

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

14 user877329 Jun 12 2015 at 22:23

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

  1. 모든 경고를 켠 상태에서 C 컴파일러를 통해 프로그램을 컴파일 -Wall하고 모든 오류 및 경고를 수정합니다.
  2. 다음과 같이 선언 된 변수가 없는지 확인하십시오. auto
  3. 그 다음으로 C ++ 컴파일러를 사용하여 컴파일 -Wall하고 -std=c++11. 모든 오류 및 경고를 수정합니다.
  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...
12 Noname Sep 10 2015 at 22:58

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

10 Aashish Oct 03 2017 at 20:13

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

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

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

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

9 iec2011007 Jul 29 2015 at 12:53

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

9 dhanagovindarajan Jul 18 2016 at 17:36

void 포인터는 제네릭 포인터이고 C는 void 포인터 형식에서 다른 형식으로의 암시 적 변환을 지원하므로 명시 적으로 형식 변환 할 필요가 없습니다.

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

9 Mohit Nov 08 2016 at 17:09
  1. 다른 언급과 같이 C에는 필요하지 않지만 C ++에는 필요합니다.

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

  3. C에서는 void *가 자동으로 안전하게 다른 포인터 유형으로 승격되므로 불필요합니다.

  4. 그러나 캐스팅하면 stdlib.h 포함하는 것을 잊은 경우 오류를 숨길 수 있습니다 . 이로 인해 충돌이 발생할 수 있습니다 (또는 코드의 완전히 다른 부분에서 나중에 충돌을 일으키지 않음).

    stdlib.h 에 malloc의 프로토 타입이 포함되어 있기 때문에 발견되었습니다. malloc에 ​​대한 프로토 타입이없는 경우 표준은 C 컴파일러가 malloc이 int를 리턴한다고 가정하도록 요구합니다. 캐스트가 없으면이 정수가 포인터에 할당 될 때 경고가 발생합니다. 그러나 캐스트를 사용하면이 경고가 생성되지 않아 버그가 숨겨집니다.

4 RobertSsupportsMonicaCellio Jun 13 2020 at 02:20

이 질문은 의견 기반 학대의 주제입니다.

때때로 나는 다음과 같은 코멘트를 발견합니다.

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

또는

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

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

즉에 어떤 가능한 방법으로 부적절하고 잘못된뿐만 아니라. 자신의 코딩 스타일의 문제라면 옳고 그름이 없습니다.


왜 이런 일이 발생합니까?

그 이유는 다음 두 가지입니다.

  1. 이 질문은 실제로 의견 기반입니다. 기술적으로이 질문은 몇 년 전에 의견 기반으로 종결되었을 것입니다. A " Do I "또는 " Do n't I "또는 이에 상응하는 " Should I "또는 " Shouldn I "질문에 대해 자신의 의견에 대한 태도 없이는 집중적으로 대답 할 수 없습니다. 질문을 닫는 이유 중 하나는 여기에 잘 표시된 것처럼 "의견 기반 답변으로 이어질 수 있기 때문"입니다.

  2. (가장 명백한 허용 된 포함한 많은 답변 대답 의 @unwind )입니다 중 하나를 완전히 또는 거의 완전히 의견 기반 (당신이 나쁜 것이 자신을 반복 주조 또는 경우 코드에 추가됩니다 FE 신비 "혼란")와 쇼 캐스트를 생략하려는 명확하고 집중된 경향. 그들은 한쪽에서 캐스트의 중복성에 대해 주장하지만 더 나쁜 것은 프로그래밍 자체의 버그 / 실패로 인한 버그를 해결해야한다고 주장 #include <stdlib.h>합니다 malloc().


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

  1. 자신의 의견에 매우 민감한 질문은 중립적 인 찬반 양론으로 대답해야합니다. 단점이나 장점 만이 아닙니다.

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

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

    (개인적으로는 그 이유 때문에 지금까지 최고의 답변이라고 생각합니다.)


  1. 캐스트를 생략 한 이유 중 기껏해야 캐스트가 버그를 숨길 수 있기 때문입니다.

    누군가 가이 질문에 표시된 것처럼 (암시 적 함수는 C99 이후 표준에서 사라짐) 및를 malloc()반환 하는 암시 적 선언 을 사용하는 경우intsizeof(int) != sizeof(int*)

    이 코드가 64 비트 아키텍처에서는 segfault이지만 32 비트에서는 잘 작동하는 이유는 무엇입니까?

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

    이 사실이지만, 그것은 단지 캐스트의 생략으로 이야기의 절반은 더 큰 버그에 앞으로 가져 해결책이 될 것입니다 보여줍니다 - 포함되지 stdlib.h사용하는 경우 malloc().

    이것은 결코 심각한 문제가되지 않을 것입니다.

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

    2. 코드에서 stdlib.h사용하고 싶을 때 를 포함하는 것을 잊은 것은 그리 빠르지 않습니다 malloc(). 이는 그 자체로 거대한 버그입니다.


  1. 일부 사람들은 C ++에서 캐스트가 의무화되어 있으므로 C 코드의 C ++ 준수에 대해 논쟁합니다.

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

    C와 C ++는 실제로 서로 다른 의미를 가진 완전히 다른 두 언어입니다.

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

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

    • https://stackoverflow.com/a/34094068/12139179

    • https://stackoverflow.com/a/36297486/12139179

    • https://stackoverflow.com/a/33044300/12139179


  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)

Source. C18, §6.2.8/3

Everything else is a matter of the specific use case and one's own opinion.

Please be careful how you educate yourself.

I recommend you to read all of the answers made so far carefully first (as well as their comments which may point at a failure) and then build your own opinion if you or if you not cast the result of malloc() at a specific case.

Please note:

There is no right and wrong answer to that question. It is a matter of style and you yourself decide which way you choose (if you aren't forced to by education or job of course). Please be aware of that and don't let trick you.


Last note: I voted to lately close this question as opinion-based, which is indeed needed since years. If you got the close/reopen privilege I would like to invite you to do so, too.

pasignature Mar 05 2020 at 22:56

For me, the take home and conclusion here is that casting malloc in C is totally NOT necessary but if you however cast, it wont affect malloc as malloc will still allocate to you your requested blessed memory space. Another take home is the reason or one of the reasons people do casting and this is to enable them compile same program either in C or C++.

There may be other reasons but other reasons, almost certainly, would land you in serious trouble sooner or later.

ivan.ukr May 22 2020 at 14:03

You can, but don't need to cast in C. You have to cast if that code is compiled as C++.