【问题标题】:iterating through a struct in c遍历c中的结构
【发布时间】:2017-11-20 16:31:58
【问题描述】:

我正在编写一个与此代码类似的单元测试,并且我正在尝试在设置值时测试我的值,以便我知道发生了什么。当我运行以下代码时,我不明白为什么 ptr 值没有设置为 1。相反,当我运行它时,它会输出 10、64、0、0。

任何解释或建议将不胜感激!

#include <stdio.h>
#include <stdbool.h>

typedef struct
{
    bool bOne;
    bool bTwo;
    bool bThree;
    bool bFour;
} items;

int main()
{
    items item;
    item.bOne = 0;
    bool *ptr = &(item.bOne);

    for(int i = 0; i < sizeof(items)/sizeof(bool); i++)
    {
        *ptr = 1;
        *ptr++;
        printf("ptr value = %d\n", *ptr);
    }
    return 0;
}

【问题讨论】:

  • *ptr++; 调用未定义的行为,因为它不指向数组。它还会增加ptr,它指向之后未初始化的内存。所以printf 的输出是垃圾。
  • 一方面,您的 printf 语句不正确,因为您使用了 %d,它需要 int,但您传递给它的是 bool。试试这个:printf("ptr value = %d\n", (int)*ptr);
  • *ptr++;....?? “警告:未使用计算的值 [-Wunused-value]”。
  • 你没有打印出刚刚初始化的成员。
  • 1) 打开警告。 2) 阅读警告。

标签: c pointers struct boolean


【解决方案1】:

在*ptr++中,++的优先级高于*,所以这个post递增指针,读取并丢弃原来指向的值。现在指针已经递增,您正在读取printf 中的未初始化内存。如果您的意图是增加所指向的值,请尝试:

(*ptr)++;

或者

ptr[0]++;

编辑

嗯,由于您的循环绑定基于适合结构大小的bools 的数量,因此您的意图可能是增加指针。在这种情况下,您不需要同时取消引用它,并且您不应该期望在printf 中获得任何有意义的东西。此外,正如所指出的,由于结构不是数组,您将徘徊在未定义的行为领域,因为编译器可能会决定添加填充:

来自 C99 §6.7.2.1:

12 结构或联合对象的每个非位域成员都以适合其类型的实现定义方式对齐。

13 在结构对象中,非位域成员和位域所在的单元的地址按声明顺序递增。一个指向结构对象的指针,经过适当的转换,指向它的初始成员(或者如果该成员是位域,则指向它所在的单元),反之亦然。结构对象中可能有未命名的填充,但不是在其开头。

【讨论】:

  • 嗯,我正在研究嵌入式系统,以及已经编写好的单元测试代码。我从未使用过嵌入式代码,因此测试和编写起来非常复杂。 typedef 结构已经由 bool 值组成。我正在测试的函数处理 28 个 if 语句,每个语句都评估了一个结构值,如果为 true,则将 word 变量设置为十六进制值,并根据它是 true 还是 false 对其执行按位操作.因此,我要做的是执行步行 1 和 0 的操作。
  • @dsb4591 如果您确定您的编译器没有添加任何填充,那么您可以这样做。否则,看看你的编译器是否有一些 #pragmas 允许你指定结构的打包。
  • @MichaelWalz 我一定会考虑你的建议。谢谢!
【解决方案2】:

你有两个主要问题。

首先,您有一个逻辑错误,因为您在打印出它指向的值之前提前了指针;而不是打印您刚刚设置的值,而是打印下一个未初始化成员的值。您需要颠倒提前和打印语句的顺序,如下所示:

printf("ptr value = %d\n", *ptr);
ptr++; // note no * operator

或者只是将操作组合在一个表达式中:

printf("ptr value = %d\n", *ptr++);

这假设您可以使用 %d 打印 bool 值 - 我不确定那个临时(可能必须明确地将参数转换为 (int))。

但是你有一个更大的问题——不能保证你可以用这样的指针遍历 struct 类型的成员。即使所有成员都是同一类型,也不能保证成员之间不会有填充(这取决于bool 类型的大小和您平台的对齐要求)。

您的代码可能按预期工作,或者它可能导致您的struct 实例中的数据损坏,或任何数量的其他问题。更安全的做法是使用指向这些成员的单独指针数组,因为它是保证您可以使用指针遍历数组:

bool *members[] = { &item.bOne, &item.bTwo, &item.bThree, &item.bFour, NULL };

bool *ptr = members[0];
while ( ptr )
{
  *ptr++ = 1;
}

如果你仍然想要输出,你会写

*ptr = 1;
printf( "ptr value = %d\n", *ptr++ );

您可以发挥创意,在打印语句中结合赋值和指针前进:

printf( "ptr value = %d\n", (*ptr++ = 1) );

但这可能会让你受到打击。

【讨论】:

  • bool 的排名低于int。传递给... 函数的bool 会将值提升为int。 (int) 不需要。
  • 谢谢@JohnBode 我意识到在阅读了所有的 cmets 之后我犯了一些错误,包括你的。这非常有帮助,我会在以后尝试并更加小心。
  • bool *members[] = { &amp;item.bOne, &amp;item.bTwo,... 是一个有用的想法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-28
  • 1970-01-01
  • 2011-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-02
相关资源
最近更新 更多