구조체 포인터를 케스팅하는데 이해가 안가는 부분이 있어 질문드립니다.
글쓴이: dingkyu / 작성시간: 목, 2011/02/24 - 6:00오후
안녕하세요.
포인터를 케스팅하는 데 있어 궁금한 점이 생겨서 질문드리려 합니다.
다음과 같은 구조체가 있다고 하죠.
#include <stdio.h> #include <stdlib.h> typedef struct { int a; int b; char c; }struct_A; typedef struct { struct_A value1; struct_A value2; }struct_B; int main(void) { struct_A originvalue; originvalue.a = 10; originvalue.b = 20; originvalue.c = 'A'; struct_B* pStruct_B = (struct_B*)&originvalue; printf("pStruct_B->value1.a = %d\n", pStruct_B->value1.a); printf("pStruct_B->value1.b = %d\n", pStruct_B->value1.b); printf("pStruct_B->value1.c = %c\n\n", pStruct_B->value1.c); printf("pStruct_B->value2.a = %d\n", pStruct_B->value2.a); printf("pStruct_B->value2.b = %d\n", pStruct_B->value2.b); printf("pStruct_B->value2.c = %c\n", pStruct_B->value2.c); return 0; }
위 문의 결과는 너무나 당연하다는 듯이
pStruct_B->value1.a = 10
pStruct_B->value1.b = 20
pStruct_B->value1.c = A
pStruct_B->value2.a = 어쩌구저쩌구
pStruct_B->value2.b = 어쩌구저쩌구
pStruct_B->value2.c = ?
위와 같이 나옵니다.
더 궁금한건 이게 클래스로 확장을 해도 적용되더라는 거죠.
이런식의 케스팅이 당연한 건가요 ?
Forums:
넵.. 구조체가 멤버 변수를 찾아가는 방법을
넵.. 구조체가 멤버 변수를 찾아가는 방법을 생각해보시면 금방 이해가 되실 것 입니다.
가령 originalvalue.a = 10 이라는것은 originalvalue의 주소값 + 0 에 10을 넣겠다는 것 이고,
originalvalue.b = 20 이라는 것은 originalvalue의 주소값 + sizeof(int) 에 20을 넣겠다는 것 입니다.
윗분 답변에 덧 붙여서...
윗분 답변에 덧 붙여서 말씀 드리면
예를 들어
메모리 0x1000_0000 에 originvalue 12Byte 공간이 할당 되었습니다.
그럼 0x1000_0000 ~ 0x1000_0008 까지 사용 할 수가 있습니다.
0x1000_0000 ~ 0x1000_0004 는 struct_A.a 가 사용 할 수 있는 4byte
0x1000_0004 ~ 0x1000_0008 는 struct_A.b 가 사용 할 수 있는 4byte
0x1000_0008 ~ 0x1000_000C 는 struct_A.c 가 사용 할 수 있는 4byte ( char 가 1 byte 인데 그냥 편하게 4byte 로 생각 합시다 ㅎㅎ )
이렇게 사용 될 수 있겠죠.
originvalue.a = 10;
originvalue.b = 20;
originvalue.c = 'A';
는 메모리로 표현 하면 다음과 같이 볼 수 있을 것입니다.
*(0x1000_0000) = 10;
*(0x1000_0004) = 20;
*(0x1000_0008) = 'c';
윗 분 말씀 처럼 sizeof(자료형) 공간 크기 만큼 증가되어 멤버변수에 값을 대입 합니다.
이제 궁금하던 struct_B* pStruct_B = (struct_B*)&originvalue;
주소 0x1000_0000 를 struct_B 로 강제 캐스팅 하였고 읽는 방법은 다음과 같을 것입니다.
pStruct_B->value1.a : *(0x1000_0000)
pStruct_B->value1.b : *(0x1000_0004)
pStruct_B->value1.c : *(0x1000_0008)
pStruct_B->value2.a : *(0x1000_000C)
pStruct_B->value2.b : *(0x1000_0010)
pStruct_B->value2.c : *(0x1000_0014)
질문 글에서 적어 주신
pStruct_B->value2.a = 어쩌구저쩌구
pStruct_B->value2.b = 어쩌구저쩌구
pStruct_B->value2.c = ?
나온 이유가 0x1000_000C ~ 0x1000_0014 의 값을 읽었기 때문에
초기화 되지 않은 알 수 없는 값 ( 흔히 쓰레기 값 ) 이 출력 된 것입니다.
저런식의 케스팅을 해서는 안 되며 하면 버그 인 겁니다~ ㅎㅎ ^^;
위의 코드야 0x1000_000C ~ 0x1000_0014 의 값을 읽어서 아무런 문제가 없지만
써 버렸다고 생각하면 큰 문제가 될 것 입니다~
답변 감사합니다.
사실은 지금 개발중인 네트워크 프로그래밍에서 클래스에서 저런 캐스팅을 활용해 프로그래밍을 해서 이해가 안됬었습니다.
클래스에 생성자 정의해놓고, 가장 위에 public 으로 구조체를 맴버로 선언한 클래스인데, 해당 구조체의 포인터를 클래스로 강제 캐스팅을 했는데 온전히 클래스의 구조체 맴버에 캐스팅에 의해 값이 정확히 들어가 있는 코드가 있었습니다. 보면서도 이해도 안되고, 솔직히 조금 황당했었거든요. 그래서 시험삼아 위와 같이 코드를 짜보니 에러도 안나고 정확히 잘 찾아가길레 확인삼아 여쭤본것이었습니다.
일종의 코딩 테크닉이 될 수는 있겠지만 역시 이런식으로 짜면 버그가 날 가능성이 크겠죠 ?
고민이 많아 고민인 애늙은이 입니다.
댓글 달기