C中单个结构成员的大小


109

我试图声明一个依赖于另一个结构的结构。我想使用sizeof它是安全/学究的。

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

现在,我想声明一个结构child_t,其大小与相同parent_t.text

我怎样才能做到这一点?(下面的伪代码。)

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

我尝试了几种不同的方式与parent_tstruct _parent,但是我的编译器不接受。

作为技巧,这似乎可行:

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

child_t不使用可以声明dummy吗?

Answers:


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不评估的操作数,因此取消引用空指针没有问题(因为实际上并未取消引用)。
James McNellis

4
精彩?其纯C89,见实施“offsetof”在<STDDEF.H>或相同的实现eetimes.com/design/other/4024941/...
user411313

1
@XavierGeoffrey:在这里,sizeof推断((type *)0)-> member的类型,并返回该类型的大小。((type *)0)只是结构类型的空指针。ptr-> member是(在编译时)类型为成员类型的表达式。sizeof中的代码永远不会运行(如果运行,该程序将出现段错误!)。仅查看sizeof内的值类型。
乔伊·亚当斯

1
Wikipedia页面上,offset_of将该行为记录为根据C标准的未定义行为,因此,我不会打赌它可以与所有编译器一起使用。
Graeme

30

我现在不在开发机器上,但是我认为您可以执行以下一项操作:

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

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


编辑:我喜欢member_size宏乔伊建议使用此技术,我想我会使用它。


12
第二种形式非常好(从概念上讲,它不包含空指针,因此很干净),但您应该指出,在C99之前的编译器中这是不可能的。
R .. GitHub停止帮助ICE,2010年

11

您可以FIELD_SIZEOF(t, f)在Linux内核中自由使用。它的定义如下:

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

其他答案中提到了这种类型的宏。但是使用已经定义的宏更可移植。


4
FIELD_SIZEOF在现代Linux中使用的宏内核,在linux / kernel.h当发现
科林·伊恩·王

@ColinIanKing因此,这通常是C语言中惯用的获取结构成员大小的方法?这样的宏是否不包含在现代C的Standard中?
圣安塔里奥

据我所知,在标准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或其他具有描述性的名称。然后,您还可以在整个代码的条件中使用它,以防止缓冲区长度错误,并且它将进行简单的整数比较。
戴夫·曼科夫

1
我认为sizeof解决方案的优点是,如果它是在库中或其他地方定义的,则不需要访问父结构。

@evilclown:但您可以这样做:“ char text [member_size(Parent,text)];” 您需要引用“父母”。
dave mankoff 2010年

3
我不认为你了解我。假设父结构是drand48_data(在stdlib.h中定义),并且您需要sizeof __x。您不能#define X_LEN 3更改stdlib.h,member_size当您无法访问父结构的源时,使用stdlib.h 似乎是一个合理的情况。

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;
}

但是,在标题中查看时,这似乎是BSD内容,而不是ANSI或POSIX标准。我在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])
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.