카테고리 보관물: C#

C#

malloc의 결과를 캐스트합니까? 제안 코멘트 내가해야

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

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

오히려

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


답변

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

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

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

사람들이 지적한 것처럼 캐스트는 좋지 않습니다. 특히 포인터 캐스트.


답변

다음 과 같은 이유로 캐스트를 수행합니다 .

  • C와 C ++ 사이에서 코드의 이식성 을 높이고 SO 경험이 보여 주듯이 많은 프로그래머들은 실제로 C ++ (또는 C + 로컬 컴파일러 확장)로 작성할 때 C로 작성한다고 주장합니다.
  • 그렇게하지 않으면 오류를 숨길 수 있습니다 . 쓸 때 type *대 혼란을 일으키는 모든 SO 예제를 주목하십시오 type **.
  • #include적절한 헤더 파일 을 찾지 못했다는 생각 으로 인해 나무의 숲이 사라 집니다. “컴파일러에게 프로토 타입이 보이지 않는다는 불만을 제기하지 않았다는 사실에 대해 걱정하지 마십시오. pesky stdlib.h는 반드시 기억해야 할 중요한 사실입니다.”라고 말하는 것과 같습니다.
  • 추가적인인지 검사를 강제합니다 . 해당 변수의 원시 크기에 대해 수행중인 산술 옆에 (알려진) 원하는 유형을 넣습니다. malloc()캐스트가있을 때 버그가 훨씬 빨리 잡히는 것을 보여주는 SO 연구를 할 수 있습니다. 어설 션과 마찬가지로 의도를 나타내는 주석은 버그를 줄입니다.
  • 기계가 점검 할 수있는 방식으로 자신을 반복하는 것이 종종 좋은 생각입니다. 사실, 그것이 어서 트의 정의이고, 캐스트의 사용은 어서 트입니다. 튜링은 수년 전에 아이디어를 생각해 냈기 때문에 어설 션은 코드를 올바르게 얻는 가장 일반적인 기술입니다.

답변

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


답변

보내는 사람 위키 백과 :

주조의 장점

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

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

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

캐스팅의 단점

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

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

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

하지만 캐스팅이없는 malloc에이 선호되는 방법이며, 가장 경험이 풍부한 프로그래머를 선택 , 당신은 문제에 대해 알고있는 같이 쪽을 사용해야합니다.

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


답변

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


답변

malloc의 결과를 캐스트하지 마십시오. 그렇게하면 코드에 무의미한 혼란이 추가됩니다.

사람들이 malloc의 결과를 캐스팅하는 가장 일반적인 이유는 C 언어의 작동 방식에 대해 확신이 없기 때문입니다. 경고 표시입니다. 특정 언어 메커니즘이 어떻게 작동하는지 모르는 경우 경우 추측 . 그것을 보거나 스택 오버플로를 요청하십시오.

일부 의견 :

  • 빈 포인터는 명시 적 캐스트 (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 년 된 컴파일러를 사용하는 이유는 무엇입니까?