programing

말록의 결과를 섭외하는 건가요?

goodcopy 2022. 8. 13. 23:51
반응형

말록의 결과를 섭외하는 건가요?

질문에서 어떤 분이 댓글로 제가 그 결과를 캐스트하지 말 을 제안하셨습니다.malloc 하다, 하다, 하다, 하다.

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

대신:

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

왜 그래야 하죠?

TL;DR

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

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

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_tcontraction.contraction.

★★★★★★malloc(sizeof *sieve * length * width) ★★malloc(length * width * sizeof *sieve) 수 .length * widthwidth ★★★★★★★★★★★★★★★★★」length입니다.size_t.

C의 .malloc가 반환되었습니다.malloc올바른 유형으로 자동 변환됩니다. C커뮤니티 간에 바람직한 대안은 다음을 사용하는 것입니다.

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

''의 를 바꿀 마다 '을.sieve.

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

캐스팅을 하는 이유는 다음과 같습니다.

  • 이것은 C와 C++ 사이에서 코드를 보다 쉽게 이동시킬 수 있게 합니다.SO의 경험에서 알 수 있듯이, 많은 프로그래머들은 실제로 C++(또는 C+ 로컬 컴파일러 확장자)로 쓸 때 C로 쓰고 있다고 주장합니다.
  • 그렇지 않으면 오류가 숨겨질있습니다.기입 타이밍을 혼동하는 SO의 예를 모두 적어 둡니다.type *type **.
  • 실패했다는 걸 눈치채지 못하게 한다는 생각#include적절한 헤더 파일이 트리의 포리스트를 놓칩니다.이것은 "시제품을 보지 못한 것에 대해 컴파일러에게 불평을 하지 못한 것에 대해 걱정하지 마세요.그 성가신 stdlib.h는 기억해야 할 진짜 중요한 것입니다!"라고 말하는 것과 같습니다.
  • 추가적인 인지 교차 검사를 강요합니다.해당 변수의 원시 크기에 대해 수행하는 산술 바로 옆에 원하는 유형(알림)이 표시됩니다.SO 연구를 통해서도 알 수 있을 겁니다malloc()버그는 깁스가 있을 때 훨씬 더 빨리 잡힌다.어설션과 마찬가지로 의도를 나타내는 주석이 버그를 줄입니다.
  • 기계가 확인할 수 있는 방식으로 반복하는 것은 종종 좋은 생각이다.사실, 그것이 주장이고, 이러한 캐스팅의 사용은 주장입니다.튜링이 몇 년 전에 그 아이디어를 생각해 낸 이래로, 어설션은 여전히 우리가 가지고 있는 가장 일반적인 코드 수정 기술이다.

Wikipedia에서:

캐스팅의 장점

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

  • 캐스트에서는 원래 char *를 반환한1989년 이전 버전의 malloc을 사용할 수 있습니다.

  • 특히 포인터가 malloc() 콜에서 멀리 떨어진 것으로 선언된 경우(현대 컴파일러 및 스태틱아나라이저에서는 캐스트를 필요로 하지 않고 이러한 동작을 경고할 수 있지만)에는 캐스팅을 통해 개발자가 타입 사이징의 불일치를 식별할 수 있습니다.

캐스팅의 단점

  • ANSI C 표준에서는 캐스트는 장황합니다.

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

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

캐스팅을 하지 않는 malloc이 선호되고 경험이 풍부한 프로그래머가 대부분 이 방법을 선택하지만, 문제를 알고 있다면 원하는 방법을 사용해야 합니다.

예: C 프로그램을 C++로 컴파일해야 하는 경우(다른 언어이지만) 사용 결과를 캐스팅해야 합니다.malloc.

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

이 질문은 여론에 근거한 남용의 대상이다.

가끔 그런 댓글도 눈에 띄엄띄엄 있어요.

malloc의 결과를 캐스트하지 마세요.

또는

왜 말록의 결과를 캐스팅하지 않는거죠?

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

그것은 어떤 으로든 부적절하고 부정확하다.자기만의 코딩 방식의 문제라면 옳고 그름도 없다.


왜 이런 일이 생기는 건가요?

그 이유는 두 가지입니다.

  1. 이 질문은 사실 의견 기반이다.엄밀히 말하면, 그 질문은 몇 년 전에 의견 기반으로서 종결되었어야 했다."Do I", "Don't I" 또는 이에 상응하는 "Do I" 또는 "Do I" 또는 "Do I" 또는 "Do Not I" 질문은 자신의 의견의 태도 없이 집중해서 대답할 수 없습니다.질문을 닫는 이유 중 하나는 여기서 잘 나타나듯이 "여론 기반 답변"으로 이어질 수 있기 때문이다.

  2. 많은 답변(@unwind의 가장 명확하고 받아들여지는 답변 포함)은 완전히 또는 거의 전적으로 의견 기반이며(즉, 캐스팅을 하거나 반복할 경우 코드에 추가되는 미스터리한 "커터"가 좋지 않음), 캐스팅을 생략하는 명확하고 집중적인 경향을 보여줍니다.그들은 한쪽에 있는 출연자들의 중복성에 대해 주장하지만, 더 나쁜 것은 프로그램 자체의 버그/실패에 의해 야기된 버그를 해결하기 위해서이다.#include <stdlib.h>사용하고 싶다면malloc().


저는 제 개인적인 의견을 줄이지 않고 논의된 몇 가지 사항에 대한 진정한 견해를 가지고 싶습니다.특히 주의할 점이 몇 가지 있습니다.

  1. 그렇게 쉽게 자신의 의견에 빠질 수 있는 질문에는 중립적인 찬반 답이 필요하다.단점이나 장점뿐만이 아닙니다.

    이 답변에는 장점과 단점의 개요가 기재되어 있습니다.

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

    (그 때문에 저는 개인적으로 이것이 가장 좋은 답변이라고 생각합니다.)


  1. 캐스팅 누락의 가장 큰 이유는 출연자가 버그를 숨길 수 있기 때문입니다.

    암묵적 선언을 사용하는 경우malloc()그것이 돌아오다int(암묵적인 기능은 C99 이후 표준에서 사라짐) 및sizeof(int) != sizeof(int*)(이 질문에 나타나듯이

    이 코드 segfault는 64비트 아키텍처에서는 정상적으로 동작하지만 32비트에서는 정상적으로 동작하는 이유는 무엇입니까?

    출연자들은 벌레를 숨길 것이다.

    이것은 사실이지만, 출연자의 누락은 더 큰 버그에 대한 전진적인 해결책일 뿐이므로 이야기의 절반만을 보여준다.stdlib.h사용할 때malloc().

    이건 절대 심각한 문제가 되지 않을 거야, 만약 네가

    1. C99 이상에 준거한 컴파일러(권장 및 필수)를 사용합니다.

    2. 너무 부재중이어서 잊지 않고 포함시키지 않았나요?stdlib.h, 를 사용하고 싶은 경우malloc()큰 버그 그 자체입니다.


  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)기본적인 정렬은 모든 보관 기간의 오브젝트에 대한 구현에 의해 지원되어야 합니다.다음과 같은 유형의 정렬 요건은 기본 정렬이어야 한다.

: 모든 원자성, 적격 또는 부적격 기본 유형

: 모든 atomic, qualified 또는 unqualified 열거형

: 모든 atomic, qualified 또는 qualified 포인터 유형

- 요소 유형에 기본적인 정렬 요건이 있는 모든 어레이 유형(57)

: 조항 7에서 완전한 객체 유형으로 지정된 모든 유형

- 모든 요소가 기본 정렬 요건을 가진 유형을 가지며 기본 정렬이 아닌 정렬을 지정하는 정렬 지정자가 없는 모든 구조 또는 결합 유형.

  1. 6.2.1에 명시된 바와 같이, 이후의 선언은 이전 선언을 숨길 수 있습니다."

출처 : C18, © 6.2.8/2

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

확장된 정렬은 다음보다 큰 정렬로 표시됩니다._Alignof (max_align_t)확장 조정이 지원되는지 여부와 지원되는 스토리지 지속 시간이 구현에 정의됩니다.확장 얼라인먼트 요건이 있는 타입은 오버 얼라인먼트 타입이다.58)

출처: C18, § 6.2.8/3

그 외의 모든 것은 구체적인 사용 사례와 자신의 의견에 달려 있습니다.

당신은 스스로 교육하는 것에 주의하세요.

먼저 지금까지의 모든 답변을 주의 깊게 읽고(실패를 지적할 수 있는 코멘트도 읽어보고) 결과를 캐스트하거나 캐스트하지 않으면 자신의 의견을 세울 것을 권장합니다.malloc()특정 사건에서요

주의:

그 질문에는 옳고 그른 답이 없다. 이것은 스타일의 문제이고 여러분이 어느 쪽을 선택할지는 여러분 스스로 결정합니다(물론 교육이나 직업에 의해 강요받지 않는다면). 당신은 그것을 알고 속지 마세요.


마지막 메모:나는 의견 기반으로서 이 질문을 끝내기로 투표했는데, 이것은 몇 년 전부터 정말로 필요한 것이다.만약 폐업/재개업 특전이 있다면 저도 초대하고 싶습니다.

의 결과를 캐스팅하지 않는다.malloc그렇게 하면 코드에 무의미한 혼란이 생기기 때문입니다.

사람들이 의 결과를 캐스팅하는 가장 흔한 이유는mallocC언어가 어떻게 동작하는지에 대해 확신이 없기 때문입니다.그것은 경고의 표시입니다.특정 언어 메커니즘이 어떻게 작동하는지 모르면 추측하지 마세요.Stack Overflow에서 검색하거나 문의합니다.

코멘트:

  • 보이드 포인터는 명시적 캐스트 없이 다른 포인터 유형으로 변환하거나 변환할 수 있습니다(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년 된 컴파일러를 사용합니까?

C에서는 암묵적인 변환을 얻을 수 있습니다.void *다른 (데이터) 포인터에 접속합니다.

C에서는 암묵적으로 변환이 가능합니다.void다른 종류의 포인터에 대한 포인터이므로 캐스트는 필요 없습니다.이를 사용하면 관찰자에게 필요한 이유가 있음을 시사할 수 있으며, 이는 오해를 불러일으킬 수 있습니다.

GNU C 라이브러리 레퍼런스 매뉴얼은 다음과 같습니다.

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

ISO C11 표준(p347)에서는 다음과 같이 기술되어 있습니다.

할당이 성공했을 때 반환되는 포인터는 기본적인 정렬 요건이 있는 모든 유형의 오브젝트에 대한 포인터에 할당될 수 있도록 적절히 정렬되어 있으며, 그런 오브젝트 또는 할당된 공간 내의 해당 오브젝트 배열에 액세스하기 위해 사용됩니다(공간이 명시적으로 할당 해제될 때까지).

에 의해 반환된 값 캐스팅malloc()지금은 필요 없습니다만, 아무도 지적하지 않은 것 같은 점을 덧붙이고 싶습니다.

옛날에는, 즉 ANSI C가 ANSI C를 제공하기 에,void *일반적인 유형의 포인터로서char *는, 이러한 용도의 타입입니다.이 경우 캐스트는 컴파일러 경고를 셧다운할 수 있습니다.

참고 자료: C FAQ

컴퓨터 공학을 공부한 경험만 더하면 C로 글을 쓰는 것을 본 두세 명의 교수는 항상 malloc을 캐스팅하는 것을 알 수 있지만, 내가 질문한 교수(C에 대한 방대한 이력서와 이해력)는 전혀 필요없지만, 완전히 구체적이고, 학생들이 자신이 되고 싶다는 심리를 갖도록 하기 위해서였다.매우 특이합니다.기본적으로 캐스팅을 해도 동작방법은 바뀌지 않고 그대로 실행되며 메모리는 할당되지만 캐스팅에는 영향이 없습니다.또, 다른 것에 잘못 캐스팅 했을 경우(그리고 컴파일러 에러를 회피했을 경우)에도, C는 같은 방법으로 액세스 할 수 있습니다.

편집: 캐스팅에는 특정 요점이 있습니다.배열 표기법을 사용하는 경우 생성된 코드는 다음 요소의 선두에 도달하기 위해 몇 개의 메모리를 전진시켜야 하는지 알아야 합니다.이것은 캐스팅을 통해 실현됩니다.이렇게 하면 더블의 경우 8바이트 앞서가고 int의 경우 4바이트 앞서가는 것을 알 수 있습니다.따라서 포인터 표기법을 사용해도 효과가 없으며 배열 표기법에서는 이것이 필요합니다.

의 결과를 캐스트하는 것은 필수가 아닙니다.malloc다시 돌아오기 때문에void*, 및 avoid*모든 데이터 유형을 가리킬 수 있습니다.

프로그래밍 언어와 컴파일러에 따라 다릅니다.사용하시는 경우mallocC에서는 자동으로 cast를 입력하므로 cast를 입력할 필요가 없습니다.단, C++ 를 사용하고 있는 경우는, cast 라고 입력합니다.malloca를 반환한다.void*유형.

보이드 포인터는 범용 오브젝트 포인터이며 C는 보이드 포인터 타입에서 다른 타입으로의 암묵적인 변환을 지원하므로 명시적으로 타이핑할 필요가 없습니다.

단, 암묵적인 변환을 지원하지 않는 C++ 플랫폼에서 완전히 호환되는 동일한 코드를 사용하려면 타이프캐스팅을 수행해야 합니다.이렇게 하면 모든 것이 사용성에 따라 달라집니다.

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

C에서는 다음과 같은 이유로 주조할 필요가 없습니다.

  • void *는 C의 경우 다른 포인터 타입으로 자동적이고 안전하게 승격됩니다.
  • 포함을 잊은 경우 오류를 숨길 수 있습니다.<stdlib.h>이로 인해 크래시가 발생할 수 있습니다.
  • 포인터와 정수의 크기가 다를 경우 캐스팅으로 경고를 숨기고 반환된 주소의 비트를 잃을 수 있습니다.
  • 선언 시 포인터의 타입이 변경되면 모든 행을 변경해야 할 수도 있습니다.malloc불러서 섭외합니다.

한편, 캐스팅은 프로그램의 휴대성을 높일 수 있습니다.즉, C 프로그램 또는 함수를 C++로 컴파일할 수 있습니다.

GCC와 Clang에 익숙한 사람들은 버릇이 없다.밖은 별로 좋지 않아요.

나는 몇 년 동안 내가 사용해야 하는 엄청나게 오래된 컴파일러들에 상당히 겁을 먹었다.기업이나 매니저는 컴파일러 변경에 대해 매우 보수적인 접근법을 채택하고 있으며, 새로운 컴파일러(표준 준거 및 코드 최적화 기능)가 시스템에서 동작하는지 테스트조차 하지 않는 경우가 많습니다.작업 중인 개발자들에게 현실적인 현실은 코드에 적용할 수 있는 컴파일러를 제어할 수 없다면 코드에 적용할 수 있는 기반을 커버할 필요가 있다는 것입니다.불행하게도 mallocs를 캐스팅하는 것은 좋은 습관입니다.

또, 많은 조직이 독자적인 코딩 표준을 적용하고, 그것이 정의되어 있는 경우, 사람들이 따르는 방법이 되어야 한다고 제안합니다.명시적인 지침이 없을 때, 나는 기준에 대한 슬라브적인 고수보다는 모든 곳을 편찬하는 경향이 있다.

현재 기준으로는 필요하지 않다는 주장은 꽤 타당하다.하지만 그 주장은 현실 세계의 실용성을 배제한다.우리는 오늘날의 표준으로만 지배되는 세계에서 코드를 작성하지 않고, 내가 "지역 경영의 현실 분야"라고 부르는 것의 실용성에 따라 코드를 작성한다.그리고 그것은 지금까지의 공간보다 더 구부러지고 뒤틀린 것입니다. :-)

YMMV

나는 말록 캐스팅을 방어 작전이라고 생각하는 경향이 있다.예쁘지도 않고 완벽하지도 않지만 대체로 안전합니다. (솔직히 stdlib을 넣지 않았다면)h 그럼 malloc 캐스팅보다 훨씬 더 많은 문제가 생기겠네요! )

아니, 너는 그 결과를 캐스팅하지 않아.malloc().

일반적으로 로 또는 에서 캐스팅하지 않습니다.

그렇게 하지 않는 일반적인 이유는 다음과 같습니다.#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;

때로는 포인터를 던질 필요가 있지만, 엄격한 에일리어싱 규칙을 고려할 때 매우 주의해야 합니다.따라서 코드에 포인터가 삽입되면 해당 포인터의 유효성을 다시 확인해야 합니다.따라서 불필요한 포인터 캐스트는 절대 쓰지 않습니다.

dr;dr

한마디로 C에서는 포인터 캐스트가 발생하면 특별히 주의가 필요한 코드에 대해 빨간색 플래그가 표시되므로 불필요한 포인터 캐스트를 작성해서는 안 됩니다.


사이드 노트:

  • 실제로 깁스를 해야 하는 경우도 있고void *(예: 포인터를 인쇄하는 경우:

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

    여기 출연진들이 필요하거든요. 왜냐하면printf()는 가변 함수이기 때문에 암묵적인 변환은 기능하지 않습니다.

  • C++에서는 상황이 다릅니다.파생 클래스의 객체를 다룰 때 포인터 유형을 캐스팅하는 것이 다소 일반적이고 정확합니다.따라서 C++에서는, C++ 로의 변환과 C++ 로부터의 변환이 의미가 있습니다.void *는 암묵적이지 않습니다.C++에는 다양한 맛의 캐스팅이 준비되어 있습니다.

C 언어에서는 보이드 포인터를 임의의 포인터에 할당할 수 있으므로 타입 캐스트를 사용하지 마십시오."type safe" 할당을 원하는 경우 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++) {
   ...
}

반환되는 유형은 void*이며, 참조 해제하기 위해 원하는 유형의 데이터 포인터에 캐스팅할 수 있습니다.

가능한 한 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에는 AB가 올바르게 지정되어 있습니다.i
  2. C++는 더 많은 코드를 생성할 수 있습니다(예외, RTTI, 템플릿, 런타임 다형성).

C에 공통되는 서브셋을 정적 다형 기능과 함께 사용하는 경우 이상적인 경우 두 번째 단점은 사라집니다.

C++ 엄밀한 규칙이 불편하다고 생각되는 경우 C++11 기능을 유추형으로 사용할 수 있습니다.

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

잘못된 변환을 일으키기 위해 깁스를 사용하지 않아도 다음 코드 조각과 같은 코드를 진단 없이 컴파일할 수 있는 타입 시스템의 보기 흉한 구멍에 대해 거부감을 나타내기 위해 깁스를 넣었습니다.

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++ 한정)이전 스타일(C 스타일) 캐스트를 비포이드 형식으로 사용할 경우 경고C++ 프로그램 내에 있습니다.새로운 스타일의 캐스팅(dynamic_cast,static_cast, reactret_cast 및 const_cast)는 취약성이 낮다.검색하기가 훨씬 쉬워졌습니다.

C 코드가 C++로 컴파일 되어 있는 경우는, 이것을 사용할 수 있습니다.-Wold-style-cast의 모든 발생을 확인하는 옵션(type)코드에 슬금슬금 들어갈 수 있는 캐스팅 구문과 위의 매크로(또는 필요에 따라 조합) 중에서 적절한 선택으로 대체함으로써 이러한 진단에 후속 조치를 취할 수 있습니다.

이러한 변환 처리는 "Clean C" (C와 C++ 사투리를 조합한 것)로 작업하기 위한 가장 큰 독립 실행형 기술 정당화입니다.이러한 변환은 기술적으로 다음 번에는 C와 C++ 사투리의 반환 값을 주조하는 것이 정당화됩니다.malloc.

나는 캐스팅하는 것을 선호하지만, 수동으로 하는 것은 아니다.내가 가장 좋아하는 것은g_new그리고.g_new0glib로부터의 매크로.glib를 사용하지 않으면 비슷한 매크로를 추가합니다.이러한 매크로는 타입의 안전성에 영향을 주지 않고 코드 중복을 줄입니다.타입이 틀리면 비포이드의 포인터 사이에 암묵적인 캐스트를 얻을 수 있기 때문에 경고(C++의 에러)가 발생합니다.를 정의하는 헤더를 포함하는 것을 잊은g_new그리고.g_new0에러가 발생합니다. g_new그리고.g_new0둘 다 같은 주장을 받아들인다.malloc보다 적은 수의 논거를 필요로 하는calloc. 추가만 하면 됩니다.0초기화되지 않은 메모리를 가져옵니다.코드는 변경 없이 C++ 컴파일러를 사용하여 컴파일할 수 있습니다.

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

의 주요 문제malloc적당한 사이즈를 찾는 거야

메모리가 형식을 반환했습니다.malloc()타입이 되어 있지 않기 때문에 단순한 캐스트로 인해 마법처럼 효과적인 타입을 얻을 수 없습니다.

두 방법 모두 괜찮고 선택은 프로그래머의 의도에 따라 달라야 한다고 생각합니다.

  1. 타입에 메모리를 할당하는 경우는, 캐스트를 사용합니다.

ptr = (T*)malloc(sizeof(T));

  1. 지정된 포인터에 메모리를 할당하는 경우는, 캐스트를 사용하지 말아 주세요.

ptr = malloc(sizeof *ptr);

광고 1

첫 번째 방법에서는 특정 유형의 메모리를 할당한 후 올바른 포인터에 할당되도록 메모리를 캐스팅하여 올바른 크기를 보장합니다.타입이 올바르지 않은 경우ptr를 사용하면 컴파일러가 경고/오류를 발행합니다.의 타입이ptr변경되면 컴파일러는 코드가 리팩터링이 필요한 위치를 가리킵니다.

게다가, 첫 번째 방법은 다음과 같은 매크로로 결합될 수 있다.newC++의 연산자.

#define NEW(T) ((T*)malloc(sizeof(T)))
...
ptr = NEW(T);

게다가 이 방법은 다음과 같은 경우에 효과가 있다.ptrvoid*.

광고 2

두 번째 방법은 유형에 관계없이 포인터의 유형에서 가져와 올바른 크기를 보장합니다.이 방법의 주요 장점은 스토리지 크기를 자동으로 조정하는 것입니다.ptr변경되어 있습니다.리팩터링 시 약간의 시간(또는 오류)을 절약할 수 있습니다.

단점은 다음과 같은 경우 이 방법이 작동하지 않는다는 것입니다.ptrvoid*좋은 것으로 인식될 수도 있습니다.또, C++에서는 동작하지 않기 때문에, C++ 프로그램이 사용하는 헤더의 인라인 함수에 사용하지 말아 주세요.

개인적으로는 두 번째 옵션을 선호합니다.

  1. 다른 것과 같이, 이것은 C가 아니라 C++에 필요합니다.

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

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

  4. 단, stdlib.h를 포함하지 않은 경우 오류가 숨겨질 수 있습니다.이로 인해 크래시가 발생할 수 있습니다(더 나쁘게도 코드의 완전히 다른 부분에서 나중에 크래시가 발생할 때까지 크래시가 발생하지 않습니다).

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

보이드 포인터는 범용 포인터이며, C는 보이드 포인터 타입에서 다른 타입으로의 암묵적인 변환을 지원하므로 명시적으로 타이핑할 필요가 없습니다.

단, 암묵적인 변환을 지원하지 않는 C++ 플랫폼에서 완전히 호환되는 동일한 코드를 사용하려면 타이프캐스팅을 수행해야 합니다.이렇게 하면 모든 것이 사용성에 따라 달라집니다.

보이드 포인터의 개념은 malloc이 보이드를 반환하는 모든 데이터 유형에 캐스팅할 수 있다는 것입니다.또한 자동 타이프캐스팅도 알고 있어야 합니다.그래서 포인터를 던질 필요는 없지만 반드시 해야 합니다.코드 클린 유지 및 디버깅에 도움이 됩니다.

제게 있어서, 여기서의 결론이자 결론은 캐스팅은mallocC는 전혀 필요하지 않지만, 만약 당신이 어떤 캐스팅을 하더라도, 그것은 영향을 미치지 않습니다.malloc~하듯이malloc에서는 요청된 축복된 메모리 공간이 계속 할당됩니다.또 다른 테이크 홈은 사람들이 캐스팅을 하는 이유 또는 이유 중 하나이며, 이것은 그들이 같은 프로그램을 C 또는 C++로 컴파일 할 수 있도록 하기 위함이다.

다른 이유들이 있을 수 있지만, 다른 이유들은, 거의 확실히, 당신을 조만간 심각한 곤경에 빠뜨릴 것이다.

언급URL : https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc

반응형