C 合并/内联结构

C 合并/内联结构,c,C,STRA的大小为4字节,STRB的大小为8字节 typedef struct { int a : 1; } STRA; typedef struct { STRA stra; int b : 1; } STRB; STRA的大小为4字节,STRB的大小为4字节 我可以在STRB中使用STRA的同时将其设置为4字节吗?这似乎对gcc有效。我的眼睛不习惯摆弄。您应该决定代码是否回答了您的问题: typedef struct { int a : 1; } STRA; typedef struct {

STRA的大小为4字节,STRB的大小为8字节

typedef struct { int a : 1; } STRA;
typedef struct { STRA stra; int b : 1; } STRB;
STRA的大小为4字节,STRB的大小为4字节

我可以在STRB中使用STRA的同时将其设置为4字节吗?

这似乎对gcc有效。我的眼睛不习惯摆弄。您应该决定代码是否回答了您的问题:

typedef struct { int a : 1; } STRA;
typedef struct { int a : 1; int b : 1; } STRB;
输出为: 1 4 1
0x0101不,这是不可能的。当STRB包含STRA类型的成员时,该成员必须可用作其自己的对象。因此,即使STRA包含的填充空间足够大,可以容纳更多的STRB成员,也不能以这种方式使用。其他成员必须使用不与STRA成员重叠的空间

查看原因,考虑如下代码:

#include <stdio.h>

#pragma pack(push, 1)

typedef struct a {
    int v : 1;
}a;

#pragma pack(pop)

typedef struct b {
    a   a_value;
    int b_value : 1;
}b;


int main()
{
    b variable;
 
    printf("%lu %lu %lu\n", sizeof(a), sizeof(b), sizeof(variable.a_value));

    variable.a_value.v = ~0;
    variable.b_value   = ~0;

    printf("0x%04x\n", *(unsigned*)&variable);

    return 0;
}
update中的赋值通常是通过将new的所有4个字节(包括填充)复制到*p中来完成的。如果其中一部分空间用于sb.b,它将被覆盖,并且foo不会像预期的那样输出1

我想你可以有一个实现,其中结构的赋值一个接一个地复制字段,而不使用填充;但这将大大降低效率,并且对于填充物实际上不包含任何感兴趣的内容的正常情况来说是浪费时间


这也说明了为什么不可能走另一条路,将sb.stra存储在STRB的填充物中;对象sb.stra需要有自己的地址才能运行此代码,并且它的大小必须是完整的4个字节,以便像update这样的函数可以安全地写入所有4个字节。

不,对不起,C结构不是这样工作的-组合它们绝不允许将一个结构内联到另一个结构中。定义所需字段的宏可能是更好的选择。是的,您可以。使用union或编译器支持的某种pragma。@YWW union不正确,这将使它们重叠。@Barmar和?也许这就是我的意图,看起来不像。他希望它与最后一个typedef相等。这不是正确的输出;如果字段确实像问题中的第二个STRB那样彼此相邻,则输出应为0x0003设置两个lsb。看起来GCC决定sizeofa=1,尽管有int说明符,因此将a_值和b_值打包成相邻字节,但不是相邻位,如int a:1;int b:1;可以。@nneonneo OP没有要求在一个位边界打包两个结构。这个问题对我来说很清楚。请再读一遍。并且输出是正确的。代码被编译并运行。OP写入typedef struct{inta:1;intb:1;}STRB;作为第二个例子。这包含两个相邻的位字段,即两个字段压缩到同一字节的相邻位中。@n若要将第二个结构压缩到三个字节,请添加pragma,现在第一个结构将为一个字节。所以struct STRB将是四个字节,他仍然可以在其中使用struct STRA。根据OP的要求,请再次阅读问题。
void update(STRA *p) {
    static STRA new = { 1 };
    *p = new;
}

STRB sb;

void foo(void) {
    sb.b = 1;
    update(&sb.stra);
    printf("%d\n", sb.b);
}