【问题标题】:Accessing a struct defined in another c file?访问在另一个 c 文件中定义的结构?
【发布时间】:2021-01-21 17:54:16
【问题描述】:

我正在尝试从另一个 c 文件访问一个 c 文件中定义的结构。问题是 我不能使用 extern 关键字 我也不能在头文件中定义结构。如何访问abstract.cuse_abstract.c 中定义的结构?这是一个最低限度的可生产示例:

抽象.c

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

typedef struct s_strukt {
    int x;
} strukt;

strukt* create_struct() {
    strukt* s = malloc(sizeof(strukt));

    return s;
}

抽象.h

#ifndef H_ABSTRACT
#define H_ABSTRACT
struct s_strukt;

#endif

use_abstract.c

#include <stdio.h>
#include "abstract.h"

int main() {

    strukt *s = create_struct();
    s->x = 0;

    return 0;
}

执行以下会导致错误gcc use_abstract.c abstract.c:

use_abstract.c:6:5: error: use of undeclared identifier 'strukt'; did you mean 'struct'?
    strukt *s = create_struct();
    ^~~~~~
    struct
use_abstract.c:6:5: error: declaration of anonymous struct must be a definition
use_abstract.c:6:5: warning: declaration does not declare anything [-Wmissing-declarations]
use_abstract.c:7:5: error: use of undeclared identifier 's'
    s->x = 0;
    ^
1 warning and 3 errors generated.

【问题讨论】:

  • 为什么不能使用extern关键字?
  • 这只是一个标准。我正在尝试解决我的编程书中的一个问题,以自学 C 编程。但是我不相信上述方法会起作用,这就是我要问的原因。
  • extern 关键字在这里不相关。它不适用于类型。此外,它是在文件范围内声明的函数和对象的默认值。显式声明文件范围 variable extern 确实是有目的的,但在呈现的代码中没有这样的变量。
  • @pointersarehard "尝试解决我的编程书中的问题" 任何(严肃的)编程书练习都不太可能要求您使用未知且无法访问的结构。这闻起来像 XY problem,如果你说出你要解决的实际问题会更好,因为这可能不是正确的解决方案。
  • @mkrieger1 我能以任何方式改进这个问题吗?我无法提出更多问题,因为这篇文章有 0 票。

标签: c abstract-class abstract-data-type


【解决方案1】:

有几种方法可以解决此特定问题,具体取决于您要执行的操作。

首先,您的代码似乎将结构名称 struct s_strukt 与 typedef 名称 strukt 混为一谈。一般来说,typedef 将存在于abstract.h 中,它可用于客户端代码和abstract.c 中的实现(我认为,通常,类型名称与-- 并且发音相同 -- 因为现有的 C 关键字会导致混乱和沮丧)。

如果您的目标是明确区分接口和实现,您可以使用所谓的“opaque structures”。这就是当您有一个引用结构的类型时得到的结果,该结构的定义对调用代码不可见(例如,fopen/fclose/read/write 使用的FILE 类型等)。

abstract.h 中,你会:

#ifndef H_ABSTRACT
#define H_ABSTRACT

typedef struct s_strukt strukt;

strukt *create_strukt(void);
#endif

abstract.c 中,您将拥有:

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

#include "abstract.h"

struct s_strukt {
    int x;
};

strukt *create_strukt() {
    strukt *s = malloc(sizeof(strukt));
    return s;
}

鉴于上述情况,您可以这样写use_abstract.c,它会编译而不会出错:

#include <stdio.h>
#include "abstract.h"

int main() {
    strukt *s = create_strukt();

    return 0;
}

但是有一个问题!因为strukt是不透明类型,如果你尝试在use_abstract.c中这样做:

s->x = 0;

它会失败:

use_abstract.c: In function ‘main’:
use_abstract.c:8:6: error: invalid use of incomplete typedef ‘strukt’ {aka ‘struct s_strukt’}
    8 |     s->x = 0;
      |      ^~

一个典型的解决方案是在abstract.c 中实现例程以获取/设置不透明结构中的值。例如,让abstract.h 看起来像这样:

#ifndef H_ABSTRACT
#define H_ABSTRACT

typedef struct s_strukt strukt;

strukt *create_strukt(void);
void strukt_set_x(strukt *s, int value);
int strukt_get_x(strukt *s);

#endif

abstract.c 看起来像这样:

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

#include "abstract.h"

struct s_strukt {
    int x;
};

strukt *create_strukt() {
    strukt *s = malloc(sizeof(strukt));
    return s;
}

void strukt_set_x(strukt *s, int x) {
    s->x = x;
}

int strukt_get_x(strukt *s) {
    return s->x;
}

然后像这样写use_abstract.c

#include <stdio.h>
#include "abstract.h"

int main() {
    int val;

    strukt *s = create_strukt();
    strukt_set_x(s, 0);
    val = strukt_get_x(s);
    printf("val is: %d\n", val);

    return 0;
}


但是,如果您不想使用不透明的结构怎么办?然后你会这样写abstract.h

#ifndef H_ABSTRACT
#define H_ABSTRACT

typedef struct s_strukt {
    int x;
} strukt;

strukt *create_strukt(void);

#endif

因为结构定义现在在abstract.h 中,它同时暴露给abstract.c 中的实现和use_abstract.c 中的客户端代码,我们不再需要getter/setter 函数,因为use_abstract.c 中的代码可以直接访问结构成员。有了上面,abstract.c 看起来像:

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

#include "abstract.h"

strukt *create_strukt() {
    strukt *s = malloc(sizeof(strukt));
    return s;
}

use_abstract.c 看起来像:

#include <stdio.h>
#include "abstract.h"

int main() {
    strukt *s = create_strukt();
    s->x = 0;
    printf("x is: %d\n", s->x);

    return 0;
}

【讨论】:

  • 惊人的答案,正是我想要的。你写的正是我的想法,但犹豫不决,因为我好像错过了什么。我的编程书问题的限制太窄了(没有getter,没有setter,没有extern,没有头定义只有头声明,等等。)谢谢你的帮助,你是救命稻草!
猜你喜欢
  • 2015-06-03
  • 1970-01-01
  • 2015-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-06
相关资源
最近更新 更多