【问题标题】:Dereferencing pointer to incomplete type using a struct使用结构取消引用指向不完整类型的指针
【发布时间】:2016-04-21 11:10:54
【问题描述】:

我在标题“point.h”中有以下代码:

#ifndef POINT_H_INCLUDED
#define POINT_H_INCLUDED

struct Point* createDefaultValues();

#endif // POINT_H_INCLUDED

point.c 文件代码如下:

#include <stdlib.h>
struct Point {
int x;
int y;
};


struct Point* createDefaultValues()
{
    struct Point* point;
    point = (struct Point*) malloc(sizeof(struct Point));
    point->x = 2;
    point->y = 1;
    return point;
};

而main.c由以下几行组成:

#include <stdio.h>
#include <stdlib.h>
#include "point.h"

int main()
{
    struct Point* cerc;
    cerc = createDefaultValues();
    printf("%d, %d", cerc->x, cerc->y);
    return 0;
}

我在 printf() 行获得了指向不完整类型错误的取消引用指针。我该怎么做才能修复它?

我知道我可以在 struct 中分配默认值,但我不想这样做,我只想使用在我的标题中找到的函数来分配它们。

【问题讨论】:

  • 为什么 point.c 文件以“};”结尾。不应该只有}吗?
  • 在 C 中,不带参数的函数应在声明 struct Point* createDefaultValues(void); 中使用类型 void。空括号意味着函数可以接受任何个参数。
  • @Lundin 这是函数定义,不是声明。
  • 啊,没关系,我误会了。我以为他问为什么结构声明以分号结尾。评论已删除。

标签: c pointers struct


【解决方案1】:

您可以将结构定义移动到头文件中:

 #ifndef POINT_H_INCLUDED
 #define POINT_H_INCLUDED

    struct Point {
      int x;
      int y;
    };


    struct Point* createDefaultValues();

    #endif // POINT_H_INCLUDED

并在point.c中包含头文件

【讨论】:

  • 这并不能解决我的问题。它给了我一个额外的编译错误:'sizeof' 对不完整类型'struct Point'的无效应用
  • 编辑提到你还需要在point.c中包含头文件
  • 非常感谢,成功了!我以后应该在头文件中声明所有结构吗?
  • @MarK 如果这些结构是供外部使用的,那么可以。如果它们是实现细节,那么不是。
  • @MarK 公开所有结构实现是传统的 C 方法。如果实现是已知的,您只能访问成员或创建实例。缺点是这引入了头文件中源文件的编译时依赖性。大约 20 年前,软件项目变得如此庞大,以至于仅仅因为无处不在的标题中的一个小细节发生了变化就重新编译所有内容是不切实际的。然后人们通过使用“Pimpl Idiom”来使用“编译防火墙”。 Herb Sutter 有一个关于它的 gotcha of the week(C++,但仍然如此)。
【解决方案2】:

另一种方法是编写两个访问器函数,因此您可以通过它们获取成员的值,而不是引用指针。这种方法可能会更好,因为它不会强迫您将结构定义置于公共视图中。

为此,您可以添加 point.h:

int getX(struct Point* point);
int getY(struct Point* point);

定义进入point.c:

int getX(struct Point* point)
{
    return point->x;
}

int getY(struct Point* point)
{
    return point->y;
}

并在 main.c 中将其替换为:

printf("%d, %d", getX(cerc), getY(cerc));

通过扩展它,您可以编写 setter 函数,例如验证等。

【讨论】:

  • 这是正确答案。不将私有成员暴露给调用者是一个很好的设计。这就是你使用不完整类型开始的原因。
猜你喜欢
  • 2021-07-25
  • 1970-01-01
  • 2017-02-24
  • 2014-07-06
  • 1970-01-01
  • 1970-01-01
  • 2013-12-22
  • 2016-07-12
  • 1970-01-01
相关资源
最近更新 更多