구조체 정렬에 관한

mr.lee의 이미지

clet 에서 사용하기 위한 C 객체지향 프레임웍을 구현하고 있습니다.
glib 및 ooc 등을 살펴보았고..
결론적으로 위피에서는 제약들이 꽤 있어서 참고로 하되 여러가지 상황을 고려하며 자체적으로 만들고 있습니다.

여기서 확인할려고 하는것은,

구조체 두개가 있다고 할때 두번째 구조체의 멤버는 첫번째 구조체 그것을 포함하고 추가로 다른것이 있다고 할때,
구조체를 멤버로 하지 않고 각각의 멤버를 포함시켰을때도 절대로 각 멤버들의 옵셋은 변하지 않는가? 하는것입니다.

즉,

일반적으론 이렇게 객체 상속을 구현하죠.

struct C1
{
int a;
char b;
};

struct C2
{
struct C1;
int c;
short d;
};

구조체를 통째로 포함시켰을때는 당연히 C2 객체 포인터를 C1으로 캐스팅했을때 각 멤버에 대한 옵셋이 정확히 들어맞겠죠.

헌데 만약, 다음과 같이 C2를 정의했을때

struct C2
{
int a;
char b;
int c;
short d;
};

이때 C1으로 캐스팅한 C2 객체 포인터가 있다고 할때 이때의 C1 멤버들에 대한 옵셋은 절대적으로 동일하게 보장되는가 하는것입니다.

일반적으론 구조체 멤버란것은 메모리상에 연속적으로 배치된 - 물론 패딩을 포함해서 - 변수이므로 두번째 경우도 절대적으로 동일하다고 생각합니다. 테스트에서도 그러하구요.

헌데, 혹시 최적화 옵션이나 ARM CPU의 특성 혹은 확장된 구조체의 추가된 멤버에 영향을 받아서라던지.. 어떠한 경우라도 옵셋이 C1과 다른 경우도 있을 수 있는지요? 그래서 구조체 자체를 필히 멤버로 해야 한다는 그런 당위성이 혹 있는가 궁금합니다.

seank76의 이미지

clet이 뭐죠?

그리고 왜 꼭 이 방법을 쓰셔야하는지...
프로그램상에서 종속관계가 아닌 두개의 스트럭쳐를 서로 상호 캐스팅이 가능하게 쓰신다는거 자체가 좀 위험한 발상이시네요.

말씀하셨듯이 최적화 옵션이나 플랫폼, 콤파일러 등등의 변수에 의해 충분히 원하지 않는 결과가 나올수 있을거라고 봅니다.

우선 메모리에서 각 멤버들의 순서가 보장 안되지 않나요?

swiri15의 이미지

경험적으로는 보장된다고 보는데요...

보장은 못합니다.

위험하긴 하죠. 1%라도..

ㅡ,.ㅡ;;의 이미지

위험을떠나서라도 좋지 않은 방법인것 같군요..

프로젝트가 작다면 궂이 저렇게 하지 않아도 될것이며 크다면 저렇게 해서는 안될것으로 생각됩니다만..

----------------------------------------------------------------------------
C Library Development Project


----------------------------------------------------------------------------

navidad의 이미지


원하시는게 OOP적인 특징중 상속이라면, 처음부터 C가아닌 C++로 해보시죠?

=================================
나비아빠

=================================
나비아빠

superkkt의 이미지

구조체 선언시 나열한 멤버들의 순서대로 구조체 멤버가 메모리에 배치된다는것이 표준에 의해 보장되지 않나요? 만약 이게 안된다면 특정 포맷에 대한 헤더를 구조체로 선언하고, 메모리로 읽어들인 데이터를 해당 구조체로 캐스팅해서 접근하는 방법 자체가 portable한 방법이 아닌게 되버리는것 같은데요. 음.. 이게 portable한 방법이 아닌건가요? 햇갈리는군요.

======================
BLOG : http://superkkt.com

======================
BLOG : http://superkkt.com

전웅의 이미지

포인트는 "순서"가 아니라 "오프셋"입니다.

--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

thyoo의 이미지

관계 있을듯한 글입니다.

http://kldp.org/node/76375
___________________________________
Less is More (Robert Browning)

___________________________________
Less is More (Robert Browning)

mr.lee의 이미지

일단.. C 로 밖에 개발할 수 없는 플랫폼이구요. 상속 구현시 부모 클래스의 멤버 변수 구조체를 자식 클래스에서 구조체 형태로 포함할 것인지 아니면 각 멤버변수들를 그대로 순서대로 먼저 나열할 것인지에 관한것입니다. 어차피 수작업으로 적는건 아니고 #define 을 이용해서 자동화해 놓았기 때문에 각 클래스의 멤버들만 정의하면 나머진 상속 구조대로 상위부터 순서대로 나열되게 해놓았습니다.

부모 멤버 변수를 구조체형태로 포함시키지 않고 변수들을 직접 순서대로 나열했을때 이점은 메소드에서 상속받은 멤버 변수를 사용할때에도 객체를 부모 구조체로 캐스팅하거나 super->... 와 같은 식이 아니라 c++.처럼 자기 멤버 변수 엑세스 할때와 똑같이 self-> 로 똑같이 접근할 수 있기 때문입니다. self 객체 캐스팅이나 어떤 부모 클래스에서 상속받은 멤버 변수인지 등에 대한 신경을 안 쓰도 되죠.

헌데 이렇게 하였을때 각 멤버들의 오프셋이 구조체 형태로 포함했을때와 달라지는 경우가 있을 수 있는가? 하는것이 질문의 요지입니다. 예제를 조금 더 쉽게 쓰보면 아래 A와 B가 항상 같은 결과인가? 하는것입니다.

<code>
typedef struct _Super
{
  int super1;
  char super2;
}
Super;
 
typedef struct _Class
{
  Super super;
 
  short class1;
  char class2;
}
Class;

<code>
typedef struct _Super
{
  int super1;
  char super2;
} Super;
 
typedef struct _Class
{
  int super1;
  char super2;
 
  short class1;
  char class2;
}
Class;

전웅의 이미지

위에서 이미 답변이 나왔습니다. 다를 수 있습니다.

--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

ez8의 이미지

조금 다른 이야기이지만 관련이 있을까 해서 적어봅니다

IPv6 에 관련해서 새로 추가된 sockaddr_storage 가 비슷하게도

sockaddr, sockaddr_in, sockaddr_in6 로 서로 캐스팅해서 쓸 수 있습니다.
(http://www.faqs.org/rfcs/rfc2553.html 의 #3.10)

각각 구조체가

struct sockaddr_in {
        uint8_t sin_len;
        sa_family_t     sin_family;
        in_port_t       sin_port;
        struct  in_addr sin_addr;
        char    sin_zero[8];
};
 
struct sockaddr_in6 {
        uint8_t         sin6_len;       /* length of this struct */
        sa_family_t     sin6_family;    /* AF_INET6 */
        in_port_t       sin6_port;      /* Transport layer port # */
        uint32_t        sin6_flowinfo;  /* IP6 flow information */
        struct in6_addr sin6_addr;      /* IP6 address */
        uint32_t        sin6_scope_id;  /* scope zone index */
};
 
struct sockaddr {
        unsigned char   sa_len;         /* total length */
        sa_family_t     sa_family;      /* address family */
        char            sa_data[14];    /* actually longer; address value */
};
 
#define _SS_MAXSIZE     128U
#define _SS_ALIGNSIZE   (sizeof(__int64_t))
#define _SS_PAD1SIZE    (_SS_ALIGNSIZE - sizeof(unsigned char) - \
                            sizeof(sa_family_t))
#define _SS_PAD2SIZE    (_SS_MAXSIZE - sizeof(unsigned char) - \
                            sizeof(sa_family_t) - _SS_PAD1SIZE - _SS_ALIGNSIZE)
 
struct sockaddr_storage {
        unsigned char   ss_len;         /* address length */
        sa_family_t     ss_family;      /* address family */
        char            __ss_pad1[_SS_PAD1SIZE];
        __int64_t       __ss_align;     /* force desired struct alignment */
        char            __ss_pad2[_SS_PAD2SIZE];
};

입니다.

전웅의 이미지

> IPv6 에 관련해서 새로 추가된 sockaddr_storage 가 비슷하게도
> sockaddr, sockaddr_in, sockaddr_in6 로 서로 캐스팅해서 쓸 수 있습니다.
>

http://kldp.org/node/72838

중간 bind 함수가 언급되는 곳부터 보시면 됩니다. 애초부터 잘못된 설계가
얼마나 긴 시간 영향을 줄 수 있는지 보여주는 대표적 예에 해당합니다.

p.s. 퇴근하고 싶네요 T.T

--
Jun, Woong (woong at icu.ac.kr)
Web: http://www.woong.org (서버 공사중)

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

kalstein의 이미지

아무리 자동화가 되어있다고 한들... 언어자체에서 지원하지 않는 것을 하다보면...

시스템이 약해지지않을까요...^^; 나중에 에러나면 처리하기 무지어렵다던지...;;

OOP가 없는 세상은 이래서 별로 맘에 안듭니다 ^_^;;;


------------------------------------------
Let`s Smart Move!!
http://kalstein.tistory.com/

mr.lee의 이미지

답변들 감사드립니다. 음..일단 표준엔 위배되므로 구현체따라 구조체 멤버의 옵셋이 바뀔수도 있으므로 이식성은 없다. 이렇게 생각하면 되겠군요.
만약 gcc 에선 항상 옵셋이 동일하게 처리한다고 가정하면 gcc를 사용하는 경우엔 옵셋이 안바뀐다고 봐도 될련지요?

위 질문과 별개로..말씀하신대로 공용체를 쓰는 방식으로 다음과 같은 했을때는 절대적으로 바뀌지 않는다고 봐도 될련지요.

#define SELF __self->__self
#define call(obj, func, ...) obj->__self->func(obj, ## __VA_ARGS__)
#define $(obj) obj->__self
 
// Parent Class
 
typedef struct _S_Super S_Super;
typedef union _Super Super;
 
union _Super
{
  struct _S_Super
  {
    char super1;
    long super2;
  }
  __self;
};
 
// Child Class
 
typedef struct _S_This S_This;
typedef union _This This;
 
 
union _This
{
  Super __super;
 
  struct _S_This
  {
    char super1;
    long super2;
 
    int this1;
    short this2;
    void (* prnMember)(This* __self);
  }
  __self;
};
 
 
// member method
void This_prnMember(This* __self)
{
  printf("super1=%d, super2=%d, this1=%d, this2=%d\n",
          SELF->super1,
          SELF->super2,
          SELF->this1,
          SELF->this2);
}
 
// constructor
This* This_new()
{
  This* __self = (This*) malloc(sizeof(This));
 
  SELF->super1 = 1;
  SELF->super2 = 2;
  SELF->this1 = 3;
  SELF->this2 = 4;
  SELF->prnMember = This_prnMember;
 
  return __self;
}
 
// destructor
void This_delete(This* __self)
{
  // do anything
  free(__self);
}
 
 
int main()
{
  This* obj = This_new();
  $(obj)->super1 = 20;
  $(obj)->this1 = 10;
  call(obj, prnMember);
 
  This_delete(obj);
  return 0;
}


댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.