【问题标题】:Can you modify a nested struct's value using a pointer to the containing struct?您可以使用指向包含结构的指针来修改嵌套结构的值吗?
【发布时间】:2015-04-05 04:17:12
【问题描述】:

我有一个关于 C 中结构行为的问题。

以给定的结构为例:

typedef struct {
    char num1;
    char num2;
} structa;

typedef struct {
    structa innerstruct;
    char num3;
    char num4;
} structb;

我假设由于 structb 包含一个 structa 字段,而不是指向一个字段的指针,因此 structb 将这样布局在内存中:

struct {
    char num1; //innerstruct num1
    char num2; //innerstruct num2
    char num3; //num3
    char num4; //num4
};

如果是这样,你能像这样访问每个字段吗?

*(((char *)&structbvar) + 0) = 1; //innerstruct num1
*(((char *)&structbvar) + 1) = 2; //innerstruct num2
*(((char *)&structbvar) + 2) = 3; //num3
*(((char *)&structbvar) + 3) = 4; //num4

或者像这样访问它们?

((structa)structbvar).num1 = 1; //innerstruct num1
((structa)structbvar).num2 = 2; //innerstruct num2

不管这是否是不好的做法。

它是否可靠/便携?


编辑,正如 Matt McNabb 所指出的,你不能直接转换结构,所以它应该是:

((structa *)&structbvar)->num1 = 1; //innerstruct num1
((structa *)&structbvar)->num2 = 2; //innerstruct num2

【问题讨论】:

  • 你可以尝试一下,通常你会侥幸成功,但并没有定义它必须有效。不要这样做;它使您的代码变得模糊不清。
  • 我在我的系统上已经厌倦了它,它似乎可以工作。问题是,我不确定它是否便携,如果不是,为什么不呢。不过,我并不担心这是否是一种不好的做法,我已经知道它肯定是,而且我不会编写这样的代码,但很高兴知道 C 是如何滴答作响的。
  • 你必须确保你的结构是对齐的
  • 是的,我现在实际上正在阅读相关内容,因为 Matt McNabb 指出了变量之间的填充。我不知道它,但它很有意义!
  • 您可以使用 offsetof 而不是 1、2、3、4,如果您小心的话,可以使用便携的东西。

标签: c pointers struct portability c11


【解决方案1】:

*(char *) 版本定义明确,尽管您需要在innerstruct 结束之后和num3 之前检查填充。

(structa)structbvar 格式错误。我认为*(structa *)&structbvar 可以,因为关于具有公共初始序列的结构的规则(尽管我会仔细检查并更新我的答案)。但是,这有点没有意义,因为您可以只写 structbvar.innerstruct

【讨论】:

  • 啊,您对 (structa)structbvar 的看法是正确的,我完全忘记了您不能直接将一个结构转换为另一个结构,谢谢!我将在有问题的行下方插入一个编辑说明。也感谢有关填充的说明。我没有想到这一点。是的,我知道这有点毫无意义,但这更多的是关于 c 如何滴答作响的问题。
【解决方案2】:

如果您使用指针强制访问结构字段,则代码的可靠性取决于内存的对齐方式。所以不推荐,除非你强制内存按预期对齐。

另一种访问字段而不调用嵌套结构名称的方法是使用带有联合的匿名结构。它是 C99 标准,当然可移植且可靠,但您的编译器不支持 C99。

你可以像这样用 Anonymous Strct 定义一个联合:

typedef union {
    uint32_t wWord;
    struct {
        uint16_t hwLow;
        uint16_t hwHigh;
    };
} test_t;

然后像这样访问每个字段:

test_t tTest;
tTest.wWord = 0x00FF0000;

还有:

tTest.hwHigh = 0x00FF;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多