在C语言中遍历结构体

3
我正在编写一个类似于这段代码的单元测试,我试图在设置值时测试我的值,以便了解发生了什么。当我运行以下代码时,我不明白为什么指针值没有被设置为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;
}

1
*ptr++; 会导致未定义的行为,因为它没有指向数组。它还会增加 ptr,之后指向未初始化的内存。因此,printf 输出的是垃圾数据。 - mch
1
首先,你的printf语句是不正确的,因为你使用了%d,它期望一个int,但你传递了一个bool。尝试这样做:printf("ptr value = %d\n", (int)*ptr); - Adrian
1
*ptr++; 这段代码会产生警告:"warning: value computed is not used [-Wunused-value]"。 - Sourav Ghosh
1
  1. 打开警告。
  2. 阅读警告。
- klutt
你到底为什么想要这样做? - klutt
显示剩余9条评论
2个回答

3
*ptr++中,++*优先级更高,因此这会将指针后缀递增,并读取和丢弃原始指向的值。现在指针已经被递增,您正在printf中读取未初始化的内存。如果您的意图是递增被指向的值,请尝试:
(*ptr)++;

或者

ptr[0]++;

编辑

嗯,既然你的循环边界是基于结构体大小中可以容纳的布尔变量的数量,那么你的意图可能是要增加指针。在这种情况下,您不需要同时对其进行解引用,并且不应该期望在printf 中得到任何有意义的内容。另外,正如所指出的那样,由于结构体不是数组,因此您将进入未定义的行为领域,因为编译器可能会决定添加填充:

来自 C99 §6.7.2.1:

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

13 在结构对象内,非位字段成员和位字段所驻留的单位的地址按照它们声明的顺序递增。指向结构对象的指针,在适当转换后,指向其初始成员(或如果该成员是位字段,则指向其中所驻留的单元),反之亦然。结构对象内可能存在匿名填充,但不能存在于其开头。


我正在从事嵌入式系统的工作,并对已编写的单元测试代码进行测试。我以前没有使用过嵌入式代码,因此这对于测试和编写来说相当复杂。typedef结构已经由bool值组成。我正在测试的函数涉及28个if语句,每个语句都有一个结构值进行评估,如果为真,则将一个字变量设置为十六进制值,并根据其是否为真或假执行位运算。我的目标是执行一个行走1和0的操作。 - dsb4591
如果您确定您的编译器不会添加任何填充,则可以这样做。否则,请查看您的编译器是否有一些 #pragmas 允许您指定结构体的打包方式。 - Jabberwocky
@MichaelWalz 我一定会研究你的建议。谢谢! - dsb4591

2
你有两个主要问题。
首先,你存在一个逻辑错误,因为在打印指针所指向的值之前,你先使指针向前移动了;你打印的不是刚设置的值,而是下一个未初始化的成员的值。你需要颠倒前进和打印语句的顺序,像这样:
```c // 颠倒前进和打印语句的顺序 ptr++; printf("%d", *ptr); ```
其次,你需要检查指针是否为空,以防止出现未定义的行为。
printf("ptr value = %d\n", *ptr);
ptr++; // note no * operator

或者将操作合并在一个表达式中:

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

这假设您可以使用%d来打印bool值 - 我不确定这一点(可能需要将参数明确转换为(int))。
但是,您有一个更大的问题 - 不能保证您可以像这样使用指针迭代struct类型的成员。即使所有成员都是相同的类型,也不能保证成员之间不会有填充(这取决于bool类型的大小和平台的对齐要求)。
您的代码可能按预期工作,或者可能导致结构体实例中的数据损坏,或任何其他问题。更安全的方法是使用指向这些成员的单独指针数组,因为可以保证您可以使用指针迭代数组。
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) );

但那样可能会被打。

boolint 的等级低。将 bool 传递给 ... 函数将会将其提升为 int 值。不需要使用 (int) - chux - Reinstate Monica
谢谢@JohnBode,我在阅读所有评论(包括你的)后意识到自己犯了几个错误。这非常有帮助,我会尽量在未来更加小心。 - dsb4591
bool *members[] = { &item.bOne, &item.bTwo,... 这是一个有用的想法。 - chux - Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接