C에서 포인터를 캐스팅하는 규칙은 무엇입니까?
K & R은 그것을 넘어 가지 않지만 그들은 그것을 사용합니다. 예제 프로그램을 작성하여 어떻게 작동하는지 보려고했지만 잘되지 않았습니다.
#include <stdio.h>
int bleh (int *);
int main(){
char c = '5';
char *d = &c;
bleh((int *)d);
return 0;
}
int bleh(int *n){
printf("%d bleh\n", *n);
return *n;
}
컴파일되지만 내 print 문은 가비지 변수를 뱉어냅니다 (프로그램을 호출 할 때마다 다릅니다). 어떤 아이디어?
포인터에 대해 생각할 때 다이어그램 을 그리는 것이 도움이됩니다 . 포인터는 값의 유형을 나타내는 레이블이있는 메모리의 주소를 가리키는 화살표입니다. 주소는 볼 곳을 나타내고 유형은 가져갈 것을 나타냅니다. 포인터를 캐스팅하면 화살표의 레이블이 변경되지만 화살표가 가리키는 위치는 변경되지 않습니다.
d
in main
은 c
유형 의 포인터 char
입니다. A char
는 1 바이트의 메모리이므로 d
역 참조되면 해당 1 바이트의 메모리에서 값을 얻습니다. 아래 다이어그램에서 각 셀은 1 바이트를 나타냅니다.
-+----+----+----+----+----+----+-
| | c | | | | |
-+----+----+----+----+----+----+-
^~~~
| char
d
당신이 캐스팅 할 때 d
에 int*
, 당신은 말을하는지 d
정말 포인트 int
값입니다. 오늘날 대부분의 시스템에서 1 int
은 4 바이트를 차지합니다.
-+----+----+----+----+----+----+-
| | c | ?₁ | ?₂ | ?₃ | |
-+----+----+----+----+----+----+-
^~~~~~~~~~~~~~~~~~~
| int
(int*)d
역 참조하면 (int*)d
이 4 바이트 메모리에서 결정된 값을 얻습니다. 얻을 수있는 값은이 표시된 셀의 내용 ?
과 int
메모리 에서이 표시 되는 방식 에 따라 다릅니다 .
PC는 little-endian 입니다. 즉,의 값 int
은 다음과 같이 계산됩니다 (4 바이트에 걸쳐 있다고 가정) * ((int*)d) == c + ?₁ * 2⁸ + ?₂ * 2¹⁶ + ?₃ * 2²⁴
. 따라서 값은 가비지이지만 16 진수 ( printf("%x\n", *n)
)로 인쇄 하면 마지막 두 자리는 항상 35
(문자의 값 '5'
)입니다.
일부 다른 시스템은 big-endian이며 다른 방향으로 바이트를 정렬합니다 * ((int*)d) == c * 2²⁴ + ?₁ * 2¹⁶ + ?₂ * 2⁸ + ?₃
.. 이러한 시스템에서는 16 진수로 인쇄 할 때 값이 항상 시작 되는 것을 알 수 35
있습니다. 일부 시스템은 크기가 int
4 바이트와 다릅니다. 드문 일부 시스템 int
은 다른 방식으로 배열 되지만 이러한 시스템 을 만날 가능성은 매우 낮습니다.
컴파일러와 운영 체제에 따라 프로그램을 실행할 때마다 값이 다르거 나 항상 동일하지만 소스 코드를 약간만 변경하면 값이 변경 될 수 있습니다.
일부 시스템에서는 int
값이 4 (또는 2 또는 8)의 배수 인 주소에 저장되어야합니다. 이를 정렬 요구 사항 이라고합니다 . 의 주소 c
가 올바르게 정렬 되었는지 여부에 따라 프로그램이 충돌 할 수 있습니다.
프로그램과 달리 int
값이 있고 포인터를 가져갈 때 발생하는 일은 다음 과 같습니다.
int x = 42;
int *p = &x;
-+----+----+----+----+----+----+-
| | x | |
-+----+----+----+----+----+----+-
^~~~~~~~~~~~~~~~~~~
| int
p
포인터 p
는 int
값 을 가리 킵니다 . 화살표의 레이블은 메모리 셀에있는 내용을 올바르게 설명하므로 역 참조 할 때 놀라운 일이 없습니다.
char c = '5'
A char
(1 byte) is allocated on stack at address 0x12345678
.
char *d = &c;
You obtain the address of c
and store it in d
, so d = 0x12345678
.
int *e = (int*)d;
You force the compiler to assume that 0x12345678
points to an int
, but an int is not just one byte (sizeof(char) != sizeof(int)
). It may be 4 or 8 bytes according to the architecture or even other values.
So when you print the value of the pointer, the integer is considered by taking the first byte (that was c
) and other consecutive bytes which are on stack and that are just garbage for your intent.
Casting pointers is usually invalid in C. There are several reasons:
Alignment. It's possible that, due to alignment considerations, the destination pointer type is not able to represent the value of the source pointer type. For example, if
int *
were inherently 4-byte aligned, castingchar *
toint *
would lose the lower bits.Aliasing. In general it's forbidden to access an object except via an lvalue of the correct type for the object. There are some exceptions, but unless you understand them very well you don't want to do it. Note that aliasing is only a problem if you actually dereference the pointer (apply the
*
or->
operators to it, or pass it to a function that will dereference it).
The main notable cases where casting pointers is okay are:
When the destination pointer type points to character type. Pointers to character types are guaranteed to be able to represent any pointer to any type, and successfully round-trip it back to the original type if desired. Pointer to void (
void *
) is exactly the same as a pointer to a character type except that you're not allowed to dereference it or do arithmetic on it, and it automatically converts to and from other pointer types without needing a cast, so pointers to void are usually preferable over pointers to character types for this purpose.When the destination pointer type is a pointer to structure type whose members exactly match the initial members of the originally-pointed-to structure type. This is useful for various object-oriented programming techniques in C.
Some other obscure cases are technically okay in terms of the language requirements, but problematic and best avoided.
I suspect you need a more general answer:
There are no rules on casting pointers in C! The language lets you cast any pointer to any other pointer without comment.
But the thing is: There is no data conversion or whatever done! Its solely your own responsibilty that the system does not misinterpret the data after the cast - which would generally be the case, leading to runtime error.
So when casting its totally up to you to take care that if data is used from a casted pointer the data is compatible!
C is optimized for performance, so it lacks runtime reflexivity of pointers/references. But that has a price - you as a programmer have to take better care of what you are doing. You have to know on your self if what you want to do is "legal"
You have a pointer to a char
. So as your system knows, on that memory address there is a char
value on sizeof(char)
space. When you cast it up to int*
, you will work with data of sizeof(int)
, so you will print your char and some memory-garbage after it as an integer.
The garbage value is actually due to the fact that you have called the function bleh() before its declaration.
In case of c++ you will get compilation error but in c, the compiler assumes that the return type of the function is int, whereas, your function is returning a pointer to integer.
See this for more info : http://www.geeksforgeeks.org/g-fact-95/
참고URL : https://stackoverflow.com/questions/17260527/what-are-the-rules-for-casting-pointers-in-c
'Programing' 카테고리의 다른 글
세로 스크롤을 기반으로 jquery로 클래스를 추가 / 제거 하시겠습니까? (0) | 2020.12.03 |
---|---|
Try-catch-finally-return 설명 (0) | 2020.12.03 |
Android에서 올바른 크기로 비트 맵 디코딩 (0) | 2020.12.02 |
Ruby on Rails 복수 (컨트롤러) 및 단수 (모델) 규칙-설명 (0) | 2020.12.02 |
APK를 디 컴파일하고 수정 한 다음 다시 컴파일합니다. (0) | 2020.12.02 |