不允许使用指向不完整类类型“struct punto”的指针。

3
我正在尝试创建一个生成点列表的代码。我有一个名为“punti.c”的文件,其中包含其头文件,以及一个名为“item.c”的文件,其中包含其头文件。问题是我无法从项目中访问结构体点(x,y)的变量。
//item.c
#include <stdio.h>
#include "item.h"
#include "punti.h"

int eq(item it1, item it2)
{
    return it1->x == it2->x; //the problem is here
}

//item.h
#include "punti.h"
typedef Punto item;

int eq(item x, item y);

//punti.c
#include "utilities.h"
#include "punti.h"
#include <math.h>

struct punto
{
    double x;
    double y;
};

//punti.h
typedef struct punto *Punto;

我以多种方式测试了类型“Punto”,所以我确信它是有效的。 我试图更改项的typedef,将其变为指向Punto的指针,但没有成功。 (代码的一部分是用意大利语编写的,抱歉:))

1
如果您想隐藏结构定义,并将其制作成不透明的数据类型,则需要创建一个API来访问该结构。为了帮助理解,考虑结构、其成员和函数的行为,而不仅仅是一组变量的分组。 - Some programmer dude
1
在不透明类型的基础上进行扩展(如果需要):punti.h: double getX(struct punto* p);punto.c: double getX(struct punto* p) { return p->x; } - Aconcagua
2
附注:请不要使用typedef指针 - 这只是信息隐藏,没有任何进一步的好处(在某些情况下除外,例如WinAPI中的HANDLE类型,其中指针性质确实不重要)。相反,最好typedef结构体:typedef struct punto Punto;,并在需要指针的地方使用Punto* - Aconcagua
请仔细考虑是否使用浮点数,因为它们会带来很多问题,导致无法进行精确计算(主要是围绕四舍五入和比较问题,例如参见这里这里这里)。 - Aconcagua
有一些情况下它们是有意义的(例如在天文应用中),但大多数情况下,您最好使用定点算术,即如果需要计算子单位(如分或十分之一)而不是欧元或美元、微秒而不是毫秒等,则可以切换到更大的类型(uint64_t而不是uint32_t或使用一些大整数库)。 - Aconcagua
显示剩余7条评论
2个回答

1

头文件punti.h声明名称Punto作为指向不完整类型struct punto的指针类型struct punto *的别名。

//punti.h
typedef struct punto *Punto;

这个头文件被包含在头文件item.h中,其中声明了typedef名称item作为typedef名称Punto的别名,该别名用于函数eq的参数声明列表中:

//item.h
#include "punti.h"
typedef Punto item;

int eq(item x, item y);

typedef名称Punto和item仍然表示指向不完整结构类型的指针类型。它们可以在函数声明中使用,因为指针本身始终是完整类型。

但是,在模块item.c中,在函数eq的定义中使用了访问不完整结构类型struct punto的数据成员的表达式。

//item.c
#include <stdio.h>
#include "item.h"
#include "punti.h"

int eq(item it1, item it2)
{
    return it1->x == it2->x; //the problem is here
}

此时编译器并不知道结构体struct punto是否包含数据成员x,因此它会发出错误提示。您需要在尝试访问结构体数据成员的模块中包含完整的结构体声明。否则,编译器将报告错误。


0

struct punto的定义需要被item.c知道(例如通过punti.h进行包含)。

// punti.h
struct punto
{
    double x;
    double y;
};

typedef struct punto *Punto;

你可以将typedef看作是一个别名。 "typedef声明提供了一种将标识符声明为类型别名的方法,用于替换可能复杂的类型名称"(cppreference)。编译器基本上只是用它定义的内容来替换typedef。然后你的函数就等价于:

int eq(struct punto* it1, struct punto* it2)
{
    return it1->x == it2->x;
}

因此,它需要知道struct punto的定义。
如果您不想让struct punto的定义被知晓,那么您需要提供一种替代方式来访问它的成员。例如:

Stack overflow - what defines an opaque type in c

//punti.h
typedef struct punto *Punto;
double get_x(Punto p);

//punti.c
...
struct punto
{
    double x;
    double y;
};

double get_x(Punto p)
{
    return p->x;
}

//item.c
...
int eq(item it1, item it2)
{
    // This is ok, as there is no `->` or `*it1`.
    return get_x(it1) == get_x(it2);
}

谢谢@Someprogrammerdude提供的想法。

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