简体   繁体   中英

Shared pointer without malloc AVR

The title may not be clear so I'll give an example.

I am trying to make a system of "data streams" in C.

Type STREAM :

typedef struct {
    void (*tx) (uint8_t b);
    uint8_t (*rx) (void);
} STREAM;

I have a file uart.h with uart.c which should provide a STREAM for UART.

I decided it'll be best to expose it as a pointer, so it can be passed to functions without using ampersand.

This is the kind of functions I want to use it with (example):

/** Send signed int */
void put_i16(const STREAM *p, const int16_t num);

Here's my UART files:

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
}

I'm not sure about this. It works, but is it the right way to do it? Should I just use Malloc instead?

Why I ask this, it's a library code and I want it to be as clean and "correct" as possible

The global pointer is unnecessary ( as are all globals ), and unsafe - it is non-const; any code with access to the pointer could modify _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;
}

So long as all the functions that access STREAM members are defined withing uart.c, then you can also benefit from making STREAM an opaque type (Lundin's suggestion in comment) by using an incomplete struct declaration in the header thus:

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 ;
}

...

This prevents any code outside of uart.c from calling the rx and tx functions directly or accessing any other members.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM