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.