标题可能不清楚,所以我举一个例子。
我正在尝试在C中建立一个“数据流”系统。
输入STREAM
:
typedef struct {
void (*tx) (uint8_t b);
uint8_t (*rx) (void);
} STREAM;
我有uart.h
文件uart.c
,应为UART提供STREAM
。
我决定最好将它作为指针公开,因此可以在不使用&符号的情况下传递给函数。
这是我想用它的一种功能(例子):
/** Send signed int */
void put_i16(const STREAM *p, const int16_t num);
这是我的UART文件:
uart.h
extern STREAM* uart;
uart.c
// Shared stream instance
static STREAM _uart_singleton;
STREAM* uart;
void uart_init(uint16_t ubrr) {
// uart init code here
// Create the stream
_uart_singleton.tx = &uart_tx; // function pointers
_uart_singleton.rx = &uart_rx;
uart = &_uart_singleton; // expose a pointer to it
}
我不确定这一点。它有效,但这是正确的方法吗?我应该只使用Malloc吗?
为什么我问这个,它是一个库代码,我希望它尽可能干净和“正确”
答案 0 :(得分:3)
全局指针是不必要的(as are all globals),而且不安全 - 它是非常量的;任何有权访问指针的代码都可以修改_uart_singleton
。
uart.h
const STREAM* getUart() ;
...
uart.c
// Shared stream instance
static STREAM _uart_singleton = {0} ;
const STREAM* getUart()
{
// Return singleton if initialised,
// otherwise NULL
return _uart_singleton.rx != 0 &&
_uart_singleton.tx != 0 ? _uart_singleton :
NULL ;
}
void uart_init(uint16_t ubrr)
{
// uart init code here
// Create the stream
_uart_singleton.tx = &uart_tx; // function pointers
_uart_singleton.rx = &uart_rx;
}
只要访问STREAM
成员的所有函数都使用uart.c定义,那么您还可以通过使用STREAM成为 opaque类型(Lundin在评论中的建议)标题中的不完整的结构声明因此:
uart.h
struct sStream ;
typedef struct sStream STREAM ;
const STREAM* getUart() ;
...
uart.c
// Shared stream instance
struct sStream
{
void (*tx) (uint8_t b);
uint8_t (*rx) (void);
} _uart_singleton = {0} ;
const STREAM* getUart()
{
// Return singleton if initialised,
// otherwise NULL
return _uart_singleton.rx != 0 &&
_uart_singleton.tx != 0 ? _uart_singleton :
NULL ;
}
...
这可以防止uart.c之外的任何代码直接调用rx
和tx
函数或访问任何其他成员。