구조체 포인터를 케스팅하는데 이해가 안가는 부분이 있어 질문드립니다.

dingkyu의 이미지

안녕하세요.
포인터를 케스팅하는 데 있어 궁금한 점이 생겨서 질문드리려 합니다.

다음과 같은 구조체가 있다고 하죠.

#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 = ?

위와 같이 나옵니다.
더 궁금한건 이게 클래스로 확장을 해도 적용되더라는 거죠.
이런식의 케스팅이 당연한 건가요 ?

visualplus의 이미지

넵.. 구조체가 멤버 변수를 찾아가는 방법을 생각해보시면 금방 이해가 되실 것 입니다.
가령 originalvalue.a = 10 이라는것은 originalvalue의 주소값 + 0 에 10을 넣겠다는 것 이고,
originalvalue.b = 20 이라는 것은 originalvalue의 주소값 + sizeof(int) 에 20을 넣겠다는 것 입니다.

furmuwon의 이미지

윗분 답변에 덧 붙여서 말씀 드리면

예를 들어

메모리 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 의 값을 읽어서 아무런 문제가 없지만

써 버렸다고 생각하면 큰 문제가 될 것 입니다~

dingkyu의 이미지

사실은 지금 개발중인 네트워크 프로그래밍에서 클래스에서 저런 캐스팅을 활용해 프로그래밍을 해서 이해가 안됬었습니다.
클래스에 생성자 정의해놓고, 가장 위에 public 으로 구조체를 맴버로 선언한 클래스인데, 해당 구조체의 포인터를 클래스로 강제 캐스팅을 했는데 온전히 클래스의 구조체 맴버에 캐스팅에 의해 값이 정확히 들어가 있는 코드가 있었습니다. 보면서도 이해도 안되고, 솔직히 조금 황당했었거든요. 그래서 시험삼아 위와 같이 코드를 짜보니 에러도 안나고 정확히 잘 찾아가길레 확인삼아 여쭤본것이었습니다.
일종의 코딩 테크닉이 될 수는 있겠지만 역시 이런식으로 짜면 버그가 날 가능성이 크겠죠 ?

고민이 많아 고민인 애늙은이 입니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.