如何使用封装在源文件之间传递 typedef 定义?
How to pass typedef'd definitions between source files using encapsulation?
在link提供- https://embeddedgurus.com/barr-code/2010/11/what-belongs-in-a-c-h-header-file/
Michael Barr 声明如下:
不要公开传递给一个或多个模块的接口函数或从一个或多个模块的接口函数返回的任何特定于模块的数据结构的内部格式。也就是说不应该有“struct { … } foo;”任何头文件中的代码。如果你确实有一个类型需要传入和传出你的模块,这样客户端模块就可以创建它的实例,你可以在头文件中简单地“typedef struct foo moduleb_type”。客户端模块不应该知道,而且这种方式也无法知道结构的内部格式。
我的理解是,如果有一个模块说 "led" 想被客户端模块使用,例如 "main",主模块应该不知道内部工作原理模块 "led"。
这是我按照建议所做的,但似乎无法实施:
led.c:
#include "led.h"
typedef enum
{
RED = 0,
GREEN
} e_LedColor_t;
typedef enum
{
FAST = 0,
SLOW,
DIRECT,
OFF,
HEARTBEAT,
DOUBLE_BLINK,
IDENTIFICATION
} e_LedMode_t;
struct Led
{
e_LedColor_t color;
e_LedMode_t mode;
};
led.h:
#ifndef LED_H
#define LED_H
typedef struct Led led_t;
#endif
main.c
#include "led.h"
int main() {
led_t led;
return 1;
}
我在 led_t 行收到错误 led; 主要说法是:
错误:字段类型不完整 'ledt_t'(又名 'struct led')
仅仅因为主模块无法识别 Led 结构的定义,它抛出了一个错误。但是如果我做了一个定义,那么整个封装的想法就会丢失。一定有什么我误解了,但我不知道它是什么。谁能帮帮我?
它可能比 Micheal 给出的解释更多,但我认为他的意图是为有经验的从业者列出 "rules",而不是教授 不透明类型 - 他假设他的听众之间的理解程度 - 也许你必须买他的一本书才能获得完整的瘦身;-)
稍后在评论中,Micheal 回复了有关 "rule" 的问题并定义:
typedef struct window* window_handle ;
^
注意类型是指针 typedef
,不是实例类型。
文章中的类型foo
无法实例化,只能创建一个指针,所以接口将采用foo*
类型的参数,而不是foo
。例如,stdio 的 FILE
类型是如何定义和使用的——您不能创建 FILE
实例,只能创建 FILE*
您可以定义:
typedef struct Led* led_t;
或者保留你的 typedef
并实例化一个 led_t*
:
led_t* led;
两种情况下的类型都是不透明。
第一个隐藏了 "handle" let_t
是指针的事实,这可能很有用,因为在某些情况下它可能不是指针 - 它可能是资源的整数索引例如有限长度的数组。
重点是您只能实例化指向不完整类型的指针,而不是具体实例。
在link提供- https://embeddedgurus.com/barr-code/2010/11/what-belongs-in-a-c-h-header-file/
Michael Barr 声明如下:
不要公开传递给一个或多个模块的接口函数或从一个或多个模块的接口函数返回的任何特定于模块的数据结构的内部格式。也就是说不应该有“struct { … } foo;”任何头文件中的代码。如果你确实有一个类型需要传入和传出你的模块,这样客户端模块就可以创建它的实例,你可以在头文件中简单地“typedef struct foo moduleb_type”。客户端模块不应该知道,而且这种方式也无法知道结构的内部格式。
我的理解是,如果有一个模块说 "led" 想被客户端模块使用,例如 "main",主模块应该不知道内部工作原理模块 "led"。 这是我按照建议所做的,但似乎无法实施:
led.c:
#include "led.h"
typedef enum
{
RED = 0,
GREEN
} e_LedColor_t;
typedef enum
{
FAST = 0,
SLOW,
DIRECT,
OFF,
HEARTBEAT,
DOUBLE_BLINK,
IDENTIFICATION
} e_LedMode_t;
struct Led
{
e_LedColor_t color;
e_LedMode_t mode;
};
led.h:
#ifndef LED_H
#define LED_H
typedef struct Led led_t;
#endif
main.c
#include "led.h"
int main() {
led_t led;
return 1;
}
我在 led_t 行收到错误 led; 主要说法是:
错误:字段类型不完整 'ledt_t'(又名 'struct led')
仅仅因为主模块无法识别 Led 结构的定义,它抛出了一个错误。但是如果我做了一个定义,那么整个封装的想法就会丢失。一定有什么我误解了,但我不知道它是什么。谁能帮帮我?
它可能比 Micheal 给出的解释更多,但我认为他的意图是为有经验的从业者列出 "rules",而不是教授 不透明类型 - 他假设他的听众之间的理解程度 - 也许你必须买他的一本书才能获得完整的瘦身;-)
稍后在评论中,Micheal 回复了有关 "rule" 的问题并定义:
typedef struct window* window_handle ;
^
注意类型是指针 typedef
,不是实例类型。
文章中的类型foo
无法实例化,只能创建一个指针,所以接口将采用foo*
类型的参数,而不是foo
。例如,stdio 的 FILE
类型是如何定义和使用的——您不能创建 FILE
实例,只能创建 FILE*
您可以定义:
typedef struct Led* led_t;
或者保留你的 typedef
并实例化一个 led_t*
:
led_t* led;
两种情况下的类型都是不透明。
第一个隐藏了 "handle" let_t
是指针的事实,这可能很有用,因为在某些情况下它可能不是指针 - 它可能是资源的整数索引例如有限长度的数组。
重点是您只能实例化指向不完整类型的指针,而不是具体实例。