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;
}
컴파일되지만 인쇄문에는 가비지 변수가 표시됩니다(프로그램을 호출할 때마다 다릅니다).좋은 생각 있어요?
포인터를 생각할 때 그림을 그리는 것이 도움이 됩니다.포인터는, 메모리의 주소를 가리키는 화살표이며, 값의 타입을 나타내는 라벨이 붙어 있습니다.주소는 찾을 위치를 나타내고 유형은 가져갈 항목을 나타냅니다.포인터를 캐스팅하면 화살표의 라벨이 변경되지만 화살표가 가리키는 위치는 변경되지 않습니다.
d
에main
에 대한 포인터입니다.c
종류로 되어 있다char
.achar
1바이트의 메모리이기 때문에d
참조되지 않은 경우 해당 1바이트의 메모리 값을 얻을 수 있습니다.다음 그림에서 각 셀은 1바이트를 나타냅니다.
-+----+----+----+----+----+----+-
| | c | | | | |
-+----+----+----+----+----+----+-
^~~~
| char
d
캐스팅할 때d
로.int*
, 당신 말은d
정말로 가리키다int
가치. 오늘날 대부분의 시스템에서int
는 4바이트를 차지합니다.
-+----+----+----+----+----+----+-
| | c | ?₁ | ?₂ | ?₃ | |
-+----+----+----+----+----+----+-
^~~~~~~~~~~~~~~~~~~
| int
(int*)d
참조 해제 시(int*)d
이 4바이트의 메모리에서 값이 결정됩니다.이 셀에 표시된 값에 따라 값이 달라집니다.?
, 및 그 방법에 대해서int
는 메모리에 표시됩니다.
PC는 little-endian입니다.즉, PC의 가치는int
는 다음과 같이 계산됩니다(4바이트에 걸치는 것을 전제로 합니다). * ((int*)d) == c + ?₁ * 2⁸ + ?₂ * 2¹⁶ + ?₃ * 2²⁴
값이 가비지일 때 16진수로 인쇄하면 표시됩니다.printf("%x\n", *n)
)의 마지막 2자리는 항상35
(그게 캐릭터의 가치입니다)'5'
).
일부 다른 시스템은 빅 엔디안이며 바이트를 다른 방향으로 배열합니다.* ((int*)d) == c * 2²⁴ + ?₁ * 2¹⁶ + ?₂ * 2⁸ + ?₃
이러한 시스템에서는 값이 항상 다음과 같이 시작된다는 것을 알 수 있습니다.35
16진수로 인쇄된 경우.일부 시스템의 크기는int
4바이트와는 다릅니다.몇 안 되는 시스템 어레인지int
서로 다른 방식으로 마주칠 가능성은 매우 낮습니다.
사용하고 있는 컴파일러와 operating system에 따라서는, 프로그램을 실행할 때마다 값이 다르거나, 항상 같으나, 소스코드에 사소한 변경을 가했을 때에 값이 바뀌는 일이 있습니다.
시스템에 따라서는int
값은 4(또는 2 또는 8)의 배수인 주소에 저장해야 합니다.이를 정렬 요구사항이라고 합니다.주소의 유무에 따라c
올바르게 정렬되어 있지 않으면 프로그램이 크래쉬 할 수 있습니다.
사용 중인 프로그램과 달리 다음과 같은 작업을 수행할 수 있습니다.int
값을 매겨 포인터를 얻을 수 있습니다.
int x = 42;
int *p = &x;
-+----+----+----+----+----+----+-
| | x | |
-+----+----+----+----+----+----+-
^~~~~~~~~~~~~~~~~~~
| int
p
포인터p
을 가리키다int
값. 화살표의 라벨은 메모리 셀에 무엇이 들어있는지 정확하게 설명하므로 참조를 취소해도 놀랄 일이 없습니다.
일반적으로 C에서는 포인터를 캐스팅할 수 없습니다.몇 가지 이유가 있습니다.
얼라인먼트정렬 고려 사항으로 인해 대상 포인터 유형이 소스 포인터 유형의 값을 나타내지 못할 수 있습니다.예를 들어,
int *
기본적으로 4바이트로 정렬되어 있습니다.char *
로.int *
낮은 비트를 잃게 됩니다.에일리어싱.일반적으로 개체에 대한 올바른 유형의 l값을 사용하지 않는 한 개체에 액세스할 수 없습니다.몇 가지 예외가 있지만 잘 이해하지 못하면 하고 싶지 않을 것이다.에일리어스는 실제로 포인터의 참조를 해제하는 경우에만 문제가 됩니다.
*
또는->
연산자 또는 역참조를 하는 함수에 전달합니다.)
캐스팅 포인터가 정상인 주요 사례는 다음과 같습니다.
대상 포인터 유형이 문자 유형을 가리키는 경우.문자 타입에 대한 포인터는 임의의 타입에 대한 포인터를 나타낼 수 있으며 필요에 따라 원래 타입으로 정상적으로 왕복할 수 있습니다.무효 포인터(
void *
)는 문자 타입에 대한 포인터와 똑같습니다.단, 문자 타입에 대한 참조 해제나 산술 연산을 할 수 없습니다.또, 캐스트를 필요로 하지 않고, 다른 포인터 타입과 자동적으로 변환되기 때문에, 이 목적을 위해서 무효의 포인터가 문자 타입에 대한 포인터보다 우선됩니다.대상 포인터 유형이 원래 포인트된 구조 유형의 초기 멤버와 정확히 일치하는 멤버의 구조 유형 포인터인 경우.이것은 C의 다양한 객체 지향 프로그래밍 기법에 유용합니다.
그 밖의 불분명한 경우들은 언어 요건 면에서는 괜찮지만 문제가 있어 피하는 것이 가장 좋습니다.
char c = '5'
A char
(1바이트)는 주소의 스택에 할당됩니다.0x12345678
.
char *d = &c;
다음 주소를 얻습니다.c
저장하다d
,그렇게d = 0x12345678
.
int *e = (int*)d;
컴파일러에게 다음과 같이 가정하도록 강요합니다.0x12345678
을 가리키다int
단, int는 1바이트만이 아닙니다(sizeof(char) != sizeof(int)
아키텍처 또는 기타 값에 따라 4바이트 또는 8바이트가 될 수 있습니다.
따라서 포인터의 값을 인쇄할 때 첫 번째 바이트를 취함으로써 정수가 고려됩니다(즉,c
기타 연속된 바이트는 스택 상에 존재하며 의도한 대로 사용할 수 없습니다.
에 대한 포인터가 있습니다.char
시스템에서 알 수 있듯이 메모리 주소에는char
을 중시하다sizeof(char)
우주 공간. 우주 공간.int*
, 의 데이터를 사용하여 작업합니다.sizeof(int)
그래서 문자 뒤에 정수로 출력합니다.
좀 더 일반적인 답변이 필요할 것 같습니다.
C에 포인터를 넣는 규칙은 없습니다!언어를 사용하면 설명 없이 다른 포인터에 포인터를 던질 수 있습니다.
하지만 중요한 건:데이터 변환 같은 것은 없습니다.캐스트 후에 시스템이 데이터를 잘못 해석하지 않는 것은 전적으로 사용자의 책임입니다.일반적으로 이 경우 런타임 오류가 발생합니다.
따라서 주조된 포인터에서 데이터를 사용하는 경우 데이터가 호환되도록 주의해야 합니다.
C는 퍼포먼스에 최적화되어 있기 때문에 포인터/참조 실행 시 반사성이 부족합니다.하지만 여기에는 대가가 따른다. 프로그래머로서 당신이 하고 있는 일을 더 잘 관리해야 한다.'법적'인지 아닌지는 스스로 알아야 한다.
언급URL : https://stackoverflow.com/questions/17260527/what-are-the-rules-for-casting-pointers-in-c
'itsource' 카테고리의 다른 글
Vuejs 자 컴포넌트 입력과 함께 폼 제출 (0) | 2022.08.16 |
---|---|
Vuex 구성 요소에 모듈 상태 액세스 저장 (0) | 2022.08.16 |
C++를 배우기 전에 C를 배워야 하나요? (0) | 2022.08.16 |
Linux에서 (C 및 C++) 바이너리 기호를 표시하려면 어떻게 해야 합니까? (0) | 2022.08.16 |
C에 있는 구조물의 전진 선언? (0) | 2022.08.16 |