majianjia / nnom

A higher-level Neural Network library for microcontrollers.
Apache License 2.0
900 stars 242 forks source link

[Discussion] Forward declaration error in C99 #120

Closed JerrySkywalker closed 5 months ago

JerrySkywalker commented 3 years ago

Hi. I'm currently working around with tricore platform and trying to implement nnom on tc26x/tc37x. When porting I encountered forward declaration errors with typedef in nnom.h.

For example, in line 256 and 275 it used forward declaration like this:

// nn wrappers
typedef struct _nnom_mem_block_t nnom_mem_block_t;

typedef struct _nnom_buf
{
    nnom_mem_block_t *mem;
    size_t size;
    uint8_t type;
} nnom_buf_t;

// a memory block to store pre-assign memories during compiling. then assigned to each tensor after.   
typedef struct _nnom_mem_block_t
{
    void *blk;      // data block location
    size_t size;    // the maximum size for this block
    uint8_t owners; // how many layers own this block
    uint8_t state;  // empty? filled? for static nn, currently only used in compiling
} nnom_mem_block_t;

which is totally fine when i use nnom in stm32 projects. But when i used tricore's ctc compiler, it gave me errors like previous declaration of "nnom_mem_block_t".

So I digged it up a little and found a possible explanation is that the current style of forward declaration only works under C11 standard. Since infineon's ctc compiler only supports C99 in their free Aurix Development Studio, problem occurs.

After that I experimented on NXP IDE and STM32 IDE with gcc(c11) together with ADS and found some alternative style as follows.

//No.1 Valid usage for both gcc(c11) and tricore ctc(c99) compiler
typedef struct _student student_t;

struct _intern_a{
    struct _student *stu;
};

struct _intern_b{
    student_t *stu;
};

struct _student{
        student_t *p;
        int id;
};
//No.2 Valid usage for both gcc(c11) and tricore ctc(c99) compiler
struct _student;

typedef struct _student{
        struct _student *p;
        int id;
}student_t;

(Negative example: this won't work under C99 standard.)

//No.3 Invalid usage for tricore ctc(c99) compiler,but work just fine with gcc(c11) compiler
typedef struct _student student_t;

typedef struct _student{
        student_t *p;
        int id;
}student_t;

I‘ve used first method to refactor nnom src, and now it seems to be just fine.

I think the current style is totally fine because mainstream chip manufacturers use C11 as their gcc's default C standard (In fact infineon provide TASKING toolsets who claims to support C11 standard, but it is too expensive for individuals), but considering maximum portability, is it necessary to refactor this part to adapt C99 standard?

jonnor commented 5 months ago

This has been fixed in linked merge request, and should be closed. CC @majianjia