【问题标题】:C header file The chicken or The egg problemC 头文件 有鸡还是有蛋的问题
【发布时间】:2021-04-13 21:41:27
【问题描述】:

我正在开发一个 c 程序(一个合成器),我突然遇到了一个问题。

问题出在这里:

我有两个头文件 server.h 和 seat.h,每个包含一个结构。

server.h

typedef struct
{
    const char *socket;
    struct wl_display *wl_display;
    struct wl_event_loop *wl_event_loop;
    struct wlr_backend *backend;
    struct wlr_renderer *renderer;
    struct wlr_compositor *compositor;
    struct wlr_output_layout *output_layout;

    Seat *seat; // the seat struct from seat.h

    struct wl_list outputs;

    struct wl_listener output_listener;
} Server;

bool init_server(Server *server);
void run_server(Server *server);
void destroy_server(Server *server);

seat.h

typedef struct
{
    Server *server;  // the server struct from server.h
    struct wlr_seat *wlr_seat;

    struct wl_listener input_listener;
    struct wl_listener destroy_seat;
} Seat;

Seat *create_seat(Server *server);
void handle_new_input(struct wl_listener *listener, void *data);
void destroy_seat(struct wl_listener *listener, void *data);

主要问题是它创建了一个头文件循环,所以当我编译它时会导致错误。

我已在C header file loops 阅读了有关该问题的信息。我试过这个,它在 struct 的情况下有效,但是当我调用 create_seat() 函数时,它告诉我类型不匹配。在我的情况下,我也在使用typedef,所以这有点令人困惑。

由于实际代码在任何机器上都不好运行(因为它需要依赖等),请使用此代码作为参考,这解释了我的实际问题。

我使用介子构建系统。如果我使用 ninja 编译程序,它会以无限循环结束。

代码如下:

ma​​in.c

#include <stdio.h>
#include "server.h"
#include "seat.h"

int main()
{
    Server server;
    server.id=10;

    Seat seat;
    seat.id=20;

    server.seat=seat;
    seat.server=server;

    printSeatId(server);
    printServerId(seat);
    return 0;
}

server.h

#include "seat.h"
typedef struct
{
    Seat seat;
    int id;
} Server;

void printSeatId(Server s);

seat.h

#include "server.h"
typedef struct
{
    Server server;
    int id;
} Seat;

void printServerId(Seat s);

server.c

#include <stdio.h>
#include "server.h"
void printSeatId(Server s)
{
    printf("%d",s.seat.id);
}

seat.c

#include <stdio.h>
#include "seat.h"
void printServerId(Seat s)
{
    printf("%d",s.server.id);
}

meson.build - 在 src 文件夹中

sources = files(
  'main.c',
  'server.c',
  'seat.c'
)

executable(
  'sample',
  sources,
  include_directories: [inc],
  install: false,
)

项目文件夹中的meson.build

project(
  'sample',
  'c',
  version: '1.0.0',
  meson_version: '>=0.56.0',
  default_options: ['c_std=c11','warning_level=2'],
)

add_project_arguments(
  [
    '-DWLR_USE_UNSTABLE',
    '-Wno-unused',
    '-Wno-unused-parameter',
    '-Wno-missing-braces',
    '-Wundef',
    '-Wvla',
    '-Werror',
    '-DPACKAGE_VERSION="' + meson.project_version() + '"',
  ],
  language: 'c',
)

cc = meson.get_compiler('c')
inc = include_directories('include')
subdir('src')

目录结构如下:

<project_folder>
     |--->src
     |     |--->server.c
     |     |--->seat.c
     |     |--->meson.build
     |
     |--->include
     |     |--->server.h
     |     |--->seat.h
     |
     |--->meson.build

我已经给出了与原项目相同的目录结构。

【问题讨论】:

  • 这能回答你的问题吗? C++ circular header includes
  • 您可以通过在Server 结构之前添加Seat 结构的前向声明或在Seat 结构之前添加Server 结构的前向声明来解决此问题。跨度>
  • 你能解释一下吗
  • 编辑的代码没有任何逻辑,但这是我面临的问题
  • 警告:minimal reproducible example 不使用指向相应其他结构的指针。

标签: c gcc struct typedef meson-build


【解决方案1】:

解决冲突的方法是添加不完整结构类型的前向声明。前向声明中使用的struct类型需要一个标签,同一个标签用于同一类型的完整声明。为了对称,添加SeatServer 结构类型的前向声明是有意义的。 typedef 类型定义可以移动到一个或多个由 seat.hserver.h 头文件包含的新头文件。头文件需要定义保护宏,避免多次定义冲突。

例如:

seat_server_t.h

#ifndef SEAT_SERVER_T_H__INCLUDED
#define SEAT_SERVER_T_H__INCLUDED

typedef struct Seat_s Seat;
typedef struct Server_s Server;

#endif

seat.h

#ifndef SEAT_H__INCLUDED
#define SEAT_H__INCLUDED

#include "seat_server_t.h"

/* Other includes for struct wl_listener, etc. here... */

struct Seat_s
{
    Server *server;
    struct wlr_seat *wlr_seat;

    struct wl_listener input_listener;
    struct wl_listener destroy_seat;
};

Seat *create_seat(Server *server);
void handle_new_input(struct wl_listener *listener, void *data);
void destroy_seat(struct wl_listener *listener, void *data);
#endif

server.h

#ifndef SERVER_H__INCLUDED
#define SERVER_H__INCLUDED

#include "seat_server_t.h"

/* Other #include's for struct wl_display, etc. here... */

struct Server_s
{
    const char *socket;
    struct wl_display *wl_display;
    struct wl_event_loop *wl_event_loop;
    struct wlr_backend *backend;
    struct wlr_renderer *renderer;
    struct wlr_compositor *compositor;
    struct wlr_output_layout *output_layout;

    Seat *seat; // the seat struct from seat.h

    struct wl_list outputs;

    struct wl_listener output_listener;
};

bool init_server(Server *server);
void run_server(Server *server);
void destroy_server(Server *server);

#endif

新的头文件seat_server_t.h不需要直接包含在ma​​in.c等.c文件中。只有其他头文件 seat.hserver.h 才能将其视为内部文件。如果需要,也可以将其拆分为两个单独的头文件(每个 typedef 一个)。

【讨论】:

  • 让我检查一下
  • 但这一个给出了一个错误列表,尤其是:无效使用不完整的 typedef ‘Server’ {aka ‘struct Server_s’}
  • @trickymind 该错误是否发生在上面显示的代码中或其他地方?包含错误的代码中是否有#include "server.h"?需要额外的#includes 才能使其工作,例如#include &lt;stdbool.h&gt; 以及任何定义所有struct wl... 的东西。
  • 查看日志:pastebin.com/Q5Wwxk4M
  • @trickymind server.c 是否同时包含 server.h 和 seat.h?
【解决方案2】:

如果您只需要一个指向另一个 struct 的指针,您可以向前声明那个,如下所示:

typedef struct Server Server;

typedef struct
{
    Server *server;  // the server struct from server.h
    struct wlr_seat *wlr_seat;

    struct wl_listener input_listener;
    struct wl_listener destroy_seat;
} Seat;

【讨论】:

  • 我将附上整个源代码,因为我也在另一个头文件中使用了这些结构。
  • 这里是完整的源代码:firebasestorage.googleapis.com/v0/b/…
  • 注意:我附上整个源代码只是因为这些结构已在多个头文件中使用。
  • 哦,请不要链接到外部资源,我拒绝看那里。请编辑您的问题并提供显示问题的minimal reproducible example
  • 请给我一些时间我会编辑问题
猜你喜欢
  • 2011-01-05
  • 1970-01-01
  • 2010-11-25
  • 1970-01-01
  • 2020-05-18
  • 2017-05-29
  • 2011-07-08
  • 1970-01-01
  • 2011-02-17
相关资源
最近更新 更多