C 中单个结构成员的大小

问题描述 投票:0回答:10

我试图声明一个依赖于另一个结构的结构。 我想用

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_t
struct _parent
尝试了几种不同的方法,但我的编译器不会接受。

作为一个技巧,这似乎有效:

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

是否可以在不使用

child_t
的情况下声明
dummy

c struct sizeof
10个回答
254
投票

虽然用

#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)
甚至被允许作为常量表达式。很酷的东西。


45
投票

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

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

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


编辑:我喜欢 Joey 建议使用这种技术的 member_size 宏,我想我会使用它。


16
投票

您可以在 Linux 内核中自由使用

FIELD_SIZEOF(t, f)
。 它的定义如下:

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

其他答案中提到了这种类型的宏。但使用已经定义的宏更便携。


11
投票

使用预处理器指令,即#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 ;

6
投票

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机器上试过了,不行;用途有限。


5
投票

您可以使用预处理器指令来确定大小:

#define TEXT_MAX_SIZE 255

并在父母和孩子中使用它。


5
投票

c++解决方案:

sizeof(Type::member) 似乎也有效:

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

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

4
投票

另一种可能性是定义一个类型。我认为,您希望确保两个字段的大小相同这一事实表明您对它们具有相同的语义。

typedef char description[255];

然后有一个字段

description text;

适合您的两种类型。


0
投票

@乔伊-亚当斯,谢谢! 我正在搜索同样的东西,但是对于非字符数组,即使这样它也能完美地工作:

#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])

0
投票

您可以使用

typeof
运算符生成一个与类型无关的宏来执行此操作,它已经成为 GCC 内置函数一段时间了 https://gcc.gnu.org/onlinedocs/gcc/Typeof.html,并且是 GCC 的一部分C23标准:

#define member_size(p_struct, member) sizeof(((typeof(p_struct))0)->member)

适用于传递给它的任何类型


当您想知道作为函数参数传递的元素的大小时,这特别有用,例如:

#include <stdio.h>
#include <stdint.h>

#define member_size(p_struct, member) sizeof(((typeof(p_struct))0)->member)

struct foo {
    uint32_t big_int;
};

struct bar {
    uint16_t small_int;
};

void some_random_function(struct foo* data) {
    printf("big_int is %u bytes\n", member_size(data, big_int));
}

void some_other_function(struct bar* data) {
    printf("small_int is %u bytes\n", member_size(data, small_int));
}


int main() {
    some_random_function(&(struct foo){0});
    some_other_function(&(struct bar){0});
}

打印

big_int is 4 bytes
small_int is 2 bytes

Godbolt 中的示例

© www.soinside.com 2019 - 2024. All rights reserved.