C의 단일 구조체 멤버 sizeof


109

다른 구조체에 종속 된 구조체를 선언하려고합니다. 나는 sizeof안전 / 보행 적 으로 사용하고 싶습니다 .

typedef struct _parent
{
  float calc ;
  char text[255] ;
  int used ;
} parent_t ;

이제 .NET child_t과 같은 크기 의 구조체를 선언하고 싶습니다 parent_t.text.

어떻게 할 수 있습니까? (아래 의사 코드.)

typedef struct _child
{
  char flag ;
  char text[sizeof(parent_t.text)] ;
  int used ;
} child_t ;

parent_t및을 사용 하여 몇 가지 다른 방법을 시도 struct _parent했지만 컴파일러는 허용하지 않습니다.

트릭으로 이것은 작동하는 것 같습니다.

parent_t* dummy ;
typedef struct _child
{
  char flag ;
  char text[sizeof(dummy->text)] ;
  int used ;
} child_t ;

를 child_t사용하지 않고 선언 할 수 dummy있습니까?

답변:


202

a를 사용하여 버퍼 크기를 정의하는 #define것이 관용적 방법이지만 다른 방법은 다음과 같은 매크로를 사용하는 것입니다.

#define member_size(type, member) sizeof(((type *)0)->member)

다음과 같이 사용하십시오.

typedef struct
{
    float calc;
    char text[255];
    int used;
} Parent;

typedef struct
{
    char flag;
    char text[member_size(Parent, text)];
    int used;
} Child;

sizeof((type *)0)->member)상수 표현으로도 허용 된다는 사실이 사실 조금 놀랐습니다 . 멋진 것.


2
와, sizeof ((type *) 0)-> member)가 작동하는지 몰랐습니다. 현재 내 개발 컴퓨터에 없지만 모든 컴파일러에서 작동합니까? 조이 감사합니다.
— Gangadhar

4
@Gangadhar : 예, 이것은 모든 컴파일러에서 작동합니다. 의 피연산자 sizeof는 평가되지 않으므로 null 포인터를 역 참조하는 데 문제가 없습니다 (실제로 역 참조되지 않기 때문에).
— James McNellis

4
훌륭한? 일반 C89, <stddef.h>의 "offsetof"구현 또는 동일한 구현 참조 eetimes.com/design/other/4024941/…
— user411313

1
@XavierGeoffrey : 여기서 sizeof는 ((type *) 0)-> member의 유형을 유추하고 해당 유형의 크기를 반환합니다. ((type *) 0)은 구조체 유형의 널 포인터 일뿐입니다. ptr-> member는 (컴파일시) 멤버의 유형 인 표현식입니다. sizeof 내의 코드는 실행되지 않습니다 (실행하면 프로그램이 세그 폴트됩니다!). sizeof 내의 값 유형 만 표시됩니다.
— Joey Adams

1
offset_of에 대한 위키 백과 페이지 나는 그것이 모든 컴파일러 작업에 베팅하지 않을 C 표준에 따라 정의되지 않은 동작과 같은 사항이, 그래서.
— Graeme

30

나는 지금 내 개발 시스템에 있지 않지만 다음 중 하나를 수행 할 수 있다고 생각합니다.

sizeof(((parent_t *)0)->text)

sizeof(((parent_t){0}).text)


편집 : Joey 가이 기술을 사용하여 제안한 member_size 매크로가 마음에 들었습니다.


12
두 번째 형식은 매우 훌륭하지만 (그리고 null 포인터를 포함하지 않는다는 점에서 개념적으로 깨끗합니다) C99 이전 컴파일러에서는 불가능하다는 점을 언급해야합니다.
— R .. GitHub STOP HELPING ICE

11

FIELD_SIZEOF(t, f)Linux 커널에서 자유롭게 사용할 수 있습니다 . 다음과 같이 정의됩니다.

#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))

이 유형의 매크로는 다른 답변에서 언급됩니다. 그러나 이미 정의 된 매크로를 사용하는 것이 더 이식 가능합니다.


4
현대 리눅스에서 사용되는 매크로는, 리눅스 / kernel.h는 발견 커널 FIELD_SIZEOF입니다
— 콜린 이안 킹

@ColinIanKing 그래서 이것은 C에서 일반적으로 구조체 멤버 크기를 얻는 관용적 방법입니까? 현대 C의 표준에 아직 그러한 매크로가 포함되어 있지 않습니까?
— St. Antario

제가 알기로 표준 C.에 상응하는 매크로는 없다
— 콜린 이안 킹

최근에 linux / kernel.h에서 제거되었습니다 .
— Andriy Makukha

10

전 처리기 지시문, 즉 #define을 사용하십시오.

#define TEXT_LEN 255

typedef struct _parent
{
  float calc ;
  char text[TEXT_LEN] ;
  int used ;
} parent_t ;

typedef struct _child
{
  char flag ;
  char text[TEXT_LEN] ;
  int used ;
} child_t ;

Nyan과 동의합니다. 다른 솔루션도 작동하지만 다른 결과는 없습니다. 좀 더 명시하고 싶다면 PARENT_TEXT_LEN 또는 똑같이 설명적인 이름으로 부르세요. 그런 다음 코드 전체에서 조건부로 사용하여 버퍼 길이 오류를 방지 할 수 있으며 간단한 정수 비교를 수행합니다.
— dave mankoff

1
sizeof 솔루션의 장점은 라이브러리 나 다른 곳에 정의되어있는 경우 부모 구조체에 액세스 할 필요가 없다는 것입니다.

@evilclown :하지만 당신은 "char text [member_size (Parent, text)];" "부모"를 참조해야합니다.
— dave mankoff

3
당신이 나를 이해하지 못했다고 생각합니다. 부모 구조체가 drand48_data(stdlib.h에 정의되어 있고) sizeof를 원한다고 가정합니다 __x. #define X_LEN 3stdlib.h를 변경할 수 없으며 member_size부모 구조체의 소스에 대한 액세스 권한이 없을 때 사용하는 것이 합리적 인 상황처럼 보입니다.

5

크기에 대한 전 처리기 지시문을 다음과 같이 사용할 수 있습니다.

#define TEXT_MAX_SIZE 255

부모와 자식 모두에서 사용합니다.


예,하지만 항상 옵션은 아닙니다. 예를 들어, Linux /usr/include/bits/dirent.h에서 d_name필드 (struct direct/ dirent) 의 크기는 DIRSIZ더 이상 정의되지 않고 하드 코딩됩니다. 그래서 sizeof()종속성을 유지하는 깨끗한 방법이 될 것 같다
— ジョージ

5

struct.h 이미 정의되어 있습니다.

#define fldsiz(name, field) \
    (sizeof(((struct name *)0)->field))

그래서 당신은 할 수 있습니다.

#include <stdlib.h> /* EXIT_SUCCESS */
#include <stdio.h>  /* printf */
#include <struct.h> /* fldsiz */

struct Penguin {
    char name[128];
    struct Penguin *child[16];
};
static const int name_size  = fldsiz(Penguin, name) / sizeof(char);
static const int child_size = fldsiz(Penguin, child) / sizeof(struct Penguin *);

int main(void) {
    printf("Penguin.name is %d chars and Penguin.child is %d Penguin *.\n",
           name_size, child_size);
    return EXIT_SUCCESS;
}

그러나 헤더를 살펴보면 이것은 ANSI 또는 POSIX 표준이 아닌 BSD 것으로 보입니다. Linux 시스템에서 시도했지만 작동하지 않았습니다. 제한된 유용성.


4

또 다른 가능성은 유형을 정의하는 것입니다. 두 필드에 대해 동일한 크기를 보장하고 싶다는 사실은 두 필드에 대해 동일한 의미를 가지고 있음을 나타내는 지표라고 생각합니다.

typedef char description[255];

그리고 필드가

description text;

두 유형 모두에서.


4

C ++ 솔루션 :

sizeof (Type :: member)도 작동하는 것 같습니다.

struct Parent
{
    float calc;
    char text[255];
    int used;
};

struct Child
{
    char flag;
    char text[sizeof(Parent::text)];
    int used;
};

3
문제는 C ++가 아니라 C에 관한 것입니다.
— Marc

0

@ joey-adams, 감사합니다! 나는 똑같은 것을 찾고 있었지만 char 배열이 아닌 경우에도 완벽하게 작동합니다.

#define member_dim(type, member) sizeof(((type*)0)->member) / \
                                 sizeof(((type*)0)->member[0])

struct parent {
        int array[20];
};

struct child {
        int array[member_dim(struct parent, array)];
};

int main ( void ) {
        return member_dim(struct child, array);
}

예상대로 20을 반환합니다.

그리고 @ brandon-horsley, 이것도 잘 작동합니다.

#define member_dim(type, member) sizeof(((type){0}).member) / \
                                 sizeof(((type){0}).member[0])
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.