首页 > 解决方案 > 包含守卫不允许我声明类型

问题描述


我遇到了这么一个有趣的问题,因为包含保护触发器,头文件中声明的类型没有声明。

我有一个描述 mutex_t 类型的 mutex file.h,它取决于在线程 file.h 中声明的 thread_t 类型,但是,thread_t 取决于 mutex_t,而 main.c 文件使用这两种类型。

问题:在编译main.c的时候,thread文件是included.h,里面包含mutex.h,但是由于thread.h已经连接,所以推出了include guard,不允许在mutex中声明thread_t类型。H

线程.h

#ifndef _THREAD_H_
#define _THREAD_H_

#include "mutex.h"

typedef struct thread
{
    int thread_data;
} thread_t;

extern mutex_t* get_mutex();

#endif

互斥体.h

#ifndef _MUTEX_H_
#define _MUTEX_H_

#include "thread.h"
#include "stdint.h"

typedef struct mutex {
    uint8_t      lock_status; //+0
    thread_t*    waiting_thread_queue[1024];
} mutex_t;

extern thread_t* get_thread();

#endif

主程序

#include "stdlib.h"
#include "stddef.h"
#include "thread.h"

int main(void) {
    get_thread();
    get_mutex();
    return 0;
}

这是我得到的错误:

emilia@emilia-pc:~/test$ gcc main.c
In file included from thread.h:4,
                 from main.c:3:
mutex.h:9:5: error: unknown type name ‘thread_t’
    9 |     thread_t*    waiting_thread_queue[1024];
      |     ^~~~~~~~
mutex.h:12:8: error: unknown type name ‘thread_t’
   12 | extern thread_t* get_thread();
      |        ^~~~~~~~

标签: c

解决方案


您在两个标头之间存在循环依赖关系。线程头需要互斥体,反之亦然

你这样做的方式没有意义。线程头声明了一个名为的函数get_mutex反之亦然,互斥头声明了一个名为的函数get_thread

可能,这表明标题是如此密切相关,它们应该是一个标题。

无论如何,我们可以打破循环依赖的方法是在其中一个标头中使用前向声明。

// child.h
struct parent; // incomplete "forward" declaration
struct child {
  struct parent *parent;
};

// parent.h
#include "child.h"
#define MAX_CHILDREN 42
struct parent {
  struct child *children[MAX_CHILDREN];
};

“转发”声明struct parent不需要parent.h标题。标parent.h头选择了该声明,但它不会干扰自己的声明,因为这是允许的:

struct parent;

struct parent { ... };

请注意,这会_THREAD_H_侵入保留的实现命名空间。保留以下划线开头的名称,后跟大写字母或另一个下划线。违反此规则实际上是未定义的行为,可能会产生任何后果。该实现可以使用诊断消息停止翻译您的程序。或者它可以预定义一个名为 的宏_THREAD_H_,以便您自己的标头无法生成其预期的内容。


推荐阅读