특히 malloc의 결과를 캐스팅하는 것이 위험한 것은 무엇입니까?
이제 사람들이 이것을 복제로 표시하기 전에 다음을 모두 읽었으며 그중 어느 것도 내가 찾고있는 답을 제공하지 않습니다.
- C FAQ : malloc의 반환 값을 캐스팅하는 데 어떤 문제가 있습니까?
- SO : malloc ()의 반환 값을 명시 적으로 캐스팅해야합니까?
- SO : C에서 불필요한 포인터 캐스트
- SO : malloc의 결과를 캐스팅합니까?
C FAQ와 위의 질문에 대한 많은 답변은 캐스팅 malloc
의 반환 값이 숨길 수 있다는 신비한 오류를 인용합니다 . 그러나 그들 중 어느 것도 실제로 그러한 오류의 구체적인 예를 제공하지 않습니다. 이제 경고 가 아니라 오류 라고 말한 것에주의하십시오 .
이제 다음 코드가 제공됩니다.
#include <string.h>
#include <stdio.h>
// #include <stdlib.h>
int main(int argc, char** argv) {
char * p = /*(char*)*/malloc(10);
strcpy(p, "hello");
printf("%s\n", p);
return 0;
}
캐스트를 사용하거나 사용하지 않고 gcc 4.2로 위 코드를 컴파일하면 동일한 경고가 표시되고 프로그램이 올바르게 실행되고 두 경우 모두 동일한 결과를 제공합니다.
anon@anon:~/$ gcc -Wextra nostdlib_malloc.c -o nostdlib_malloc
nostdlib_malloc.c: In function ‘main’:
nostdlib_malloc.c:7: warning: incompatible implicit declaration of built-in function ‘malloc’
anon@anon:~/$ ./nostdlib_malloc
hello
그렇다면 누구든지 캐스트 malloc
의 반환 값으로 인해 발생할 수있는 컴파일 또는 런타임 오류의 특정 코드 예제를 제공 할 수 있습니까? 아니면 이것이 단지 도시 전설입니까?
편집 나는이 문제에 대해 잘 쓰여진 두 가지 주장을 발견했습니다.
- 캐스팅에 찬성 : CERT 권고 : 메모리 할당 함수 호출의 결과를 할당 된 유형에 대한 포인터로 즉시 캐스팅
- Casting 반대 (2012-02-14 기준 404 오류 : 2010-01-27 의 Internet Archive Wayback Machine 사본을 사용하세요 . {2016-03-18 : "robots.txt로 인해 페이지를 크롤링하거나 표시 할 수 없습니다."})
컴파일러 오류가 발생 하지 않지만 컴파일러 경고가 발생 합니다. 인용 한 소스 (특히 첫 번째 소스 )에서 . 를 포함하지 않고 캐스트 를 사용할 때 예측할 수없는 런타임 오류가 발생할 수 있습니다 .stdlib.h
따라서 당신 측의 오류는 캐스트가 아니라 stdlib.h
. 컴파일러는 가정 할 수 malloc
함수가 반환 int
따라서 변환 void*
사실에 의해 반환 된 포인터 malloc
에 int
다음 포인터 타입에 의한 명시 적 캐스트에 있습니다. 일부 플랫폼에서는 int
포인터가 다른 바이트 수를 차지할 수 있으므로 유형 변환으로 인해 데이터가 손상 될 수 있습니다.
Fortunately, modern compilers give warnings that point to your actual error. See the gcc
output you supplied: It warns you that the implicit declaration (int malloc(int)
) is incompatible to the built-in malloc
. So gcc
seems to know malloc
even without stdlib.h
.
Leaving out the cast to prevent this error is mostly the same reasoning as writing
if (0 == my_var)
instead of
if (my_var == 0)
since the latter could lead to a serious bug if one would confuse =
and ==
, whereas the first one would lead to a compile error. I personally prefer the latter style since it better reflects my intention and I don't tend to do this mistake.
The same is true for casting the value returned by malloc
: I prefer being explicit in programming and I generally double-check to include the header files for all functions I use.
One of the good higher-level arguments against casting the result of malloc
is often left unmentioned, even though, in my opinion, it is more important than the well-known lower-level issues (like truncating the pointer when the declaration is missing).
A good programming practice is to write code, which is as type-independent as possible. This means, in particular, that type names should be mentioned in the code as little as possible or best not mentioned at all. This applies to casts (avoid unnecessary casts), types as arguments of sizeof
(avoid using type names in sizeof
) and, generally, all other references to type names.
Type names belong in declarations. As much as possible, type names should be restricted to declarations and only to declarations.
From this point of view, this bit of code is bad
int *p;
...
p = (int*) malloc(n * sizeof(int));
and this is much better
int *p;
...
p = malloc(n * sizeof *p);
not simply because it "doesn't cast the result of malloc
", but rather because it is type-independent (or type-agnositic, if you prefer), because it automatically adjusts itself to whatever type p
is declared with, without requiring any intervention from the user.
Non-prototyped functions are assumed to return int
.
So you're casting an int
to a pointer. If pointers are wider than int
s on your platform, this is highly risky behavior.
Plus, of course, that some people consider warnings to be errors, i.e. code should compile without them.
Personally, I think the fact that you don't need to cast void *
to another pointer type is a feature in C, and consider code that does to be broken.
If you do this when compiling in 64-bit mode, your returned pointer will be truncated to 32-bits.
EDIT: Sorry for being too brief. Here's an example code fragment for discussion purposes.
main() { char * c = (char *)malloc(2) ; printf("%p", c) ; }
Suppose that the returned heap pointer is something bigger than what is representable in an int, say 0xAB00000000.
If malloc is not prototyped to return a pointer, the int value returned will initially be in some register with all the significant bits set. Now the compiler say, "okay, how do I convert and int to a pointer". That's going to be either a sign extension or zero extension of the low order 32-bits that it has been told malloc "returns" by omitting the prototype. Since int is signed I think the conversion will be sign extension, which will in this case convert the value to zero. With a return value of 0xABF0000000 you'll get a non-zero pointer that will also cause some fun when you try to dereference it.
A Reusable Software Rule:
In the case of writing an inline function in which used malloc(), in order to make it reusable for C++ code too, please do an explicit type casting (e.g. (char*)); otherwise compiler will complain.
A void pointer in C can be assigned to any pointer without an explicit cast. The compiler will give warning but it can be reusable in C++ by type casting malloc()
to corresponding type. With out type casting also it can be use in C, because C is no strict type checking. But C++ is strictly type checking so it is needed to type cast malloc()
in C++.
'Programing' 카테고리의 다른 글
WebView 리소스 요청에 사용자 지정 헤더 추가-Android (0) | 2020.09.22 |
---|---|
"catch, when"을 사용하여 예외 잡기 (0) | 2020.09.22 |
MySQL에 PHP 배열을 저장 하시겠습니까? (0) | 2020.09.22 |
TFS에서 비난 기능을 사용하는 방법은 무엇입니까? (0) | 2020.09.22 |
Karma + AngularJS 테스트 내에서 모의 JSON 파일로드 (0) | 2020.09.22 |