typedef struct

This is a simple piece of code. Uses a FIFO buffer as necessary. In this case not as the bits needing it have been removed for brevity. The other key bit is a simple function that calculates a moving average. The moving average uses a struct to hold the pertinent data. I compile from the command line and it works fine (either form). I move it into the IDE, 1.8.6, and in this form,

// mov_avg3
#include    <time.h>

typedef struct
{
    byte        index:3;
    byte        ndex2:5;        // (unused)
    uint16_t    data[8];
    uint16_t    avg;
    uint32_t    sum;
} mov_avg;

//=======1=========2=========3=========4=========5=========6=========7=========8
//=======1=========2=========3=========4=========5=========6                FIFO
// FIFO
//
#define BUFLGTH 64
typedef struct
{
    byte data[64];
    uint16_t next:   6;
    uint16_t first:  6;
    uint16_t unused: 4;
} FIFO;
//=======1=========2=========3=========4=========5=========6        FIFO inlines
inline byte     getBufLen(FIFO *buffer)   
                    {return (buffer->next >= buffer->first)?
                    (buffer->next - buffer->first):
                    ((BUFLGTH - buffer->first) + buffer->next);}
inline byte     isFull(FIFO *buffer)      
                    {return (getBufLen(buffer) == BUFLGTH)?1:0;}
inline byte     isEmpty(FIFO *buffer)     
                    {return (buffer->next == buffer->first)?1:0;}
inline void     clearBuf(FIFO *buffer)    
                    {buffer->next = buffer->first = 0;}
//=======1=========2=========3=========4=========5=========6        FIFO peekBuf
byte peekBuf(FIFO *buffer, byte index)
{
    index = (buffer->first + index);
    return buffer->data[index];
}
//=======1=========2=========3=========4=========5=========6          FIFO getCh
byte getCh(FIFO *buffer)
{
    byte byte = buffer->data[buffer->first];
    buffer->first = (buffer->first + 1);
    return byte;
}
//=======1=========2=========3=========4=========5=========6          FIFO addCh
void addCh(FIFO *buffer, byte ch)
{
    byte _temp = (buffer->next + 1);
    buffer->data[buffer->next] = ch;
    buffer->next = _temp;
}
//=======1=========2=========3=========4=========5=========6                FIFO
/*
typedef struct
{
    byte        index:3;
    byte        ndex2:5;        // (unused)
    uint16_t    data[8];
    uint16_t    avg;
    uint32_t    sum;
} mov_avg;
*/
//=======1=========2=========3=========4=========5=========6=========7=========8
//=======1=========2=========3=========4=========5======== variable declarations
// variable declarations
mov_avg MA;
//=======1=========2=========3=========4=========5=========6=========7=========8
//=======1=========2=========3=========4=========5=========6            add_data
//
void add_data(mov_avg *avg, byte ch)
{
    avg->sum  += ch;
    avg->sum  -= avg->data[avg->index];
    byte _temp = (avg->index + 1);
    avg->data[avg->index] = ch;
    avg->index = _temp;
    avg->avg   = (avg->sum + 4) >> 3;
}
//=======1=========2=========3=========4=========5=========6=========7=========8
//=======1=========2=========3=========4=========5=========6                 ran
//
byte ran(uint16_t min, uint16_t max)
{
    return ((rand() % (max - min + 1)) + min);  
}
//=======1=========2=========3=========4=========5=========6=========7=========8
//=======1=========2=========3=========4=========5=========6                main
//
void setup()
{
    Serial.begin(38400);
    srand(time(NULL));
    for(byte i = 1; i <= 99; i++)
    {
        Serial.print(i);
        Serial.print("\t");

        byte data = ran(10, 90);
        add_data(&MA, data);

        Serial.print(data);
        Serial.print("\t");
        Serial.println(MA.avg);
    }
}

void loop()
{
    
}

and it runs fine. Note the struct definition at the top, ahead of the FIFO bits. After the FIFO bits you’ll see the same struct commented out. When I comment out the struct at the top and un-comment the other, as such,

// mov_avg3
#include    <time.h>
/*
typedef struct
{
    byte        index:3;
    byte        ndex2:5;        // (unused)
    uint16_t    data[8];
    uint16_t    avg;
    uint32_t    sum;
} mov_avg;
*/
//=======1=========2=========3=========4=========5=========6=========7=========8
//=======1=========2=========3=========4=========5=========6                FIFO
// FIFO
//
#define BUFLGTH 64
typedef struct
{
    byte data[64];
    uint16_t next:   6;
    uint16_t first:  6;
    uint16_t unused: 4;
} FIFO;
//=======1=========2=========3=========4=========5=========6        FIFO inlines
inline byte     getBufLen(FIFO *buffer)   
                    {return (buffer->next >= buffer->first)?
                    (buffer->next - buffer->first):
                    ((BUFLGTH - buffer->first) + buffer->next);}
inline byte     isFull(FIFO *buffer)      
                    {return (getBufLen(buffer) == BUFLGTH)?1:0;}
inline byte     isEmpty(FIFO *buffer)     
                    {return (buffer->next == buffer->first)?1:0;}
inline void     clearBuf(FIFO *buffer)    
                    {buffer->next = buffer->first = 0;}
//=======1=========2=========3=========4=========5=========6        FIFO peekBuf
byte peekBuf(FIFO *buffer, byte index)
{
    index = (buffer->first + index);
    return buffer->data[index];
}
//=======1=========2=========3=========4=========5=========6          FIFO getCh
byte getCh(FIFO *buffer)
{
    byte byte = buffer->data[buffer->first];
    buffer->first = (buffer->first + 1);
    return byte;
}
//=======1=========2=========3=========4=========5=========6          FIFO addCh
void addCh(FIFO *buffer, byte ch)
{
    byte _temp = (buffer->next + 1);
    buffer->data[buffer->next] = ch;
    buffer->next = _temp;
}
//=======1=========2=========3=========4=========5=========6                FIFO

typedef struct
{
    byte        index:3;
    byte        ndex2:5;        // (unused)
    uint16_t    data[8];
    uint16_t    avg;
    uint32_t    sum;
} mov_avg;

//=======1=========2=========3=========4=========5=========6=========7=========8
//=======1=========2=========3=========4=========5======== variable declarations
// variable declarations
mov_avg MA;
//=======1=========2=========3=========4=========5=========6=========7=========8
//=======1=========2=========3=========4=========5=========6            add_data
//
void add_data(mov_avg *avg, byte ch)
{
    avg->sum  += ch;
    avg->sum  -= avg->data[avg->index];
    byte _temp = (avg->index + 1);
    avg->data[avg->index] = ch;
    avg->index = _temp;
    avg->avg   = (avg->sum + 4) >> 3;
}
//=======1=========2=========3=========4=========5=========6=========7=========8
//=======1=========2=========3=========4=========5=========6                 ran
//
byte ran(uint16_t min, uint16_t max)
{
    return ((rand() % (max - min + 1)) + min);  
}
//=======1=========2=========3=========4=========5=========6=========7=========8
//=======1=========2=========3=========4=========5=========6                main
//
void setup()
{
    Serial.begin(38400);
    srand(time(NULL));
    for(byte i = 1; i <= 99; i++)
    {
        Serial.print(i);
        Serial.print("\t");

        byte data = ran(10, 90);
        add_data(&MA, data);

        Serial.print(data);
        Serial.print("\t");
        Serial.println(MA.avg);
    }
}

void loop()
{
    
}

I get the following errors,

Arduino: 1.8.6 (Windows 7), Board: "Arduino/Genuino Uno"

WARNING: Category '' in library ArduinoUnit is not valid. Setting to 'Uncategorized'
mov_avg3:74:15: error: variable or field 'add_data' declared void

 void add_data(mov_avg *avg, byte ch)

               ^

mov_avg3:74:15: error: 'mov_avg' was not declared in this scope

mov_avg3:74:24: error: 'avg' was not declared in this scope

 void add_data(mov_avg *avg, byte ch)

                        ^

mov_avg3:74:34: error: expected primary-expression before 'ch'

 void add_data(mov_avg *avg, byte ch)

                                  ^

exit status 1
variable or field 'add_data' declared void

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

I’ve relocated the struct to various positions and it seems that before or after the first inline FIFO function,

inline byte     getBufLen(FIFO *buffer) 
    {return (buffer->next >= buffer->first)?
    (buffer->next - buffer->first):
    ((BUFLGTH - buffer->first) + buffer->next);}

seems to make the difference as to whether it compiles or not.

Any thoughts?

Have you tried to locate the complete sketch, generated by the IDE in the temporary folder, and check if any obscure modifications are made to the code?

Usually you would declare a struct as:

struct TYPE_NAME {
  struct fields
} VARIABLE_NAME;

So try to move your "VARIABLE_NAME" (mov_avg) to "TYPE_NAME".

That works fine with a straight struct. When you typedef it, as is done with FIFO and I use that often for many buffers, the type goes at the end so you use it like any other data type. Bear in mind that from the command line it compiles and runs. It's only in the IDE and with that particular placement that there's an error.

struct SOMESTRUCT
{
  ...
  ...
};

SOMESTRUCT someVar;

To my knowledge, you don't need a typedef; I have never used it when working with structs.

Without the typedef, you must declarestruct SOMESTRUCT someVar; no?

Some purists say that's a better way to go as it avoids potential naming conflicts from libraries.

typedef is legacy from C.

For edification, this is the exact same code except for the change-out of Serial.print for printf,

// mov_avg3
#include    <stdio.h>
#include    <time.h>

#define byte    uint8_t
/*
typedef struct
{
    byte        index:3;
    byte        ndex2:5;        // (unused)
    uint16_t    data[8];
    uint16_t    avg;
    uint32_t    sum;
} mov_avg;
*/
//=======1=========2=========3=========4=========5=========6=========7=========8
//=======1=========2=========3=========4=========5=========6                FIFO
// FIFO
//
#define BUFLGTH 64
typedef struct
{
    byte data[64];
    uint16_t next:   6;
    uint16_t first:  6;
    uint16_t unused: 4;
} FIFO;
//=======1=========2=========3=========4=========5=========6        FIFO inlines
inline byte     getBufLen(FIFO *buffer)   
    {return (buffer->next >= buffer->first)?
    (buffer->next - buffer->first):
    ((BUFLGTH - buffer->first) + buffer->next);}

inline byte     isFull(FIFO *buffer)      
                    {return (getBufLen(buffer) == BUFLGTH)?1:0;}
inline byte     isEmpty(FIFO *buffer)     
                    {return (buffer->next == buffer->first)?1:0;}
inline void     clearBuf(FIFO *buffer)    
                    {buffer->next = buffer->first = 0;}
//=======1=========2=========3=========4=========5=========6        FIFO peekBuf
byte peekBuf(FIFO *buffer, byte index)
{
    index = (buffer->first + index);
    return buffer->data[index];
}
//=======1=========2=========3=========4=========5=========6          FIFO getCh
byte getCh(FIFO *buffer)
{
    byte byte = buffer->data[buffer->first];
    buffer->first = (buffer->first + 1);
    return byte;
}
//=======1=========2=========3=========4=========5=========6          FIFO addCh
void addCh(FIFO *buffer, byte ch)
{
    byte _temp = (buffer->next + 1);
    buffer->data[buffer->next] = ch;
    buffer->next = _temp;
}
//=======1=========2=========3=========4=========5=========6                FIFO

typedef struct
{
    byte        index:3;
    byte        ndex2:5;        // (unused)
    uint16_t    data[8];
    uint16_t    avg;
    uint32_t    sum;
} mov_avg;

//=======1=========2=========3=========4=========5=========6=========7=========8
//=======1=========2=========3=========4=========5======== variable declarations
// variable declarations
mov_avg MA;
//=======1=========2=========3=========4=========5=========6=========7=========8
//=======1=========2=========3=========4=========5=========6            add_data
//
void add_data(mov_avg *avg, byte ch)
{
    avg->sum  += ch;
    avg->sum  -= avg->data[avg->index];
    byte _temp = (avg->index + 1);
    avg->data[avg->index] = ch;
    avg->index = _temp;
    avg->avg   = (avg->sum + 4) >> 3;
}
//=======1=========2=========3=========4=========5=========6=========7=========8
//=======1=========2=========3=========4=========5=========6                 ran
//
byte ran(uint16_t min, uint16_t max)
{
    return ((rand() % (max - min + 1)) + min);  
}
//=======1=========2=========3=========4=========5=========6=========7=========8
//=======1=========2=========3=========4=========5=========6                main
//
int main()
{
    //Serial.begin(38400);
    srand(time(NULL));
    for(byte i = 1; i <= 99; i++)
    {
        //Serial.print(i);
        //Serial.print("\t");
        printf("%i\t", i);
        byte data = ran(10, 90);
        add_data(&MA, data);

        //Serial.print(data);
        //Serial.print("\t");
        //Serial.println(MA.avg);
        printf("\t%i", MA.avg);
    }
}

and the compiler results,

NPP_EXEC: "avr-gcc"
NPP_SAVE: D:\Programming\moving average\mov_avg3.c
CD: D:\Programming\moving average
Current directory: D:\Programming\moving average
C:\avr-gcc-8.1.0-x86-mingw\bin\avr-gcc.exe -Wall -mmcu=atmega328p -DF_CPU=16000000UL -Os -std=c11 -Os -ffunction-sections -fdata-sections -MMD -flto -fno-fat-lto-objects mov_avg3.c -o mov_avg3.o
Process started >>>
<<< Process finished. (Exit code 0)
C:\avr-gcc-8.1.0-x86-mingw\bin\avr-objcopy -O ihex mov_avg3.o mov_avg3.hex
Process started >>>
<<< Process finished. (Exit code 0)
C:\avr-gcc-8.1.0-x86-mingw\bin\avr-size mov_avg3.hex
Process started >>>
   text	   data	    bss	    dec	    hex	filename
      0	   2268	      0	   2268	    8dc	mov_avg3.hex
<<< Process finished. (Exit code 0)
================ READY ================

when compiled using a command line macro in Notepad++.

You do not need to specify "typedef", leaving it out will not require a "struct x y" variable declaration.

struct MYSTRUCT1 { int value; };

struct { int value; } MYSTRUCT2;

MYSTRUCT1 ms1;

int main() {
  MYSTRUCT1.value = 2; //Illegal
  MYSTRUCT2.value = 2; //Legal
  ms1.value = 2; //Obvious
}

Did you try to examine the amalgamated sketch in the temporary folder? Did you try to move your struct name as suggested?

I did not as that does not appear to be the answer. The question remains, why does it compile, unchanged, from the command line and not from within the IDE?

And, by the way, changing

typedef struct
{
    byte        index:3;
    byte        ndex2:5;        // (unused)
    uint16_t    data[8];
    uint16_t    avg;
    uint32_t    sum;
} mov_avg;

to

struct mov_avg
{
    byte        index:3;
    byte        ndex2:5;        // (unused)
    uint16_t    data[8];
    uint16_t    avg;
    uint32_t    sum;
};

results in the following errors,

mov_avg3.c:74:1: error: unknown type name 'mov_avg'; use 'struct' keyword to refer to the type
 mov_avg MA;
 ^~~~~~~
 struct 
mov_avg3.c:78:15: error: unknown type name 'mov_avg'
 void add_data(mov_avg *avg, byte ch)
               ^~~~~~~
mov_avg3.c: In function 'main':
mov_avg3.c:107:9: warning: implicit declaration of function 'add_data' [-Wimplicit-function-declaration]
         add_data(&MA, data);
         ^~~~~~~~
mov_avg3.c:112:26: error: request for member 'avg' in something not a structure or union
         printf("\t%i", MA.avg);

without making these additional changes,

struct mov_avg MA;

void add_data(struct mov_avg *avg, byte ch)

DKWatson: I did not as that does not appear to be the answer. The question remains, why does it compile, unchanged, from the command line and not from within the IDE?

Maybe because the IDE performs some modifications to the source code before it is compiled? This would have been disclosed by now, had you investigated the sketch in the temp folder as suggested ;)

EDIT: The error you posted in #10 regarding the missing "struct" declaration should not happen in the IDE.

Danois90: Maybe because the IDE performs some modifications to the source code before it is compiled?

That's the issue though, isn't it? This is not the first time I have found code compiled by the IDE to not work when it does otherwise. This is the main reason I don't use the IDE. How can one guarantee the performance of a system when there are 'magic' things being done 'behind the scenes' by people who only think they know what they're doing. As a hobbyist platform, it's probably fine, but if there is no direct answer to the question, without shifting code around or investigating temp files, then people need to be aware that not all errors are linked to either the code or the compiler.

Some years back I wrote code that had some fairly tight timing loops. It would only work from the IDE if I switched off all optimization. Others tried to convince me it was because the code was bad, except the code compiled and worked fine with full optimization from the command line. So yes, there are modifications being done by the IDE and therein lies the problem. As these are undocumented it's a bit scary to think of what may be being added/changed without our knowledge.

DKWatson: So yes, there are modifications being done by the IDE and therein lies the problem. As these are undocumented it's a bit scary to think of what may be being added/changed without our knowledge.

You can still review the amalgamated source code in the temp folder in order to see what the IDE does to the sketch, so I would not consider the modifications to be "scary" or "undocumented". I think the goal of the IDE is to "javaify" or "javascriptify" the C code in order to make it more digestable to new developers and I think that is fine. Eventually, developers may grow out of the IDE and start to use other IDE's or even the command line.

I hope you find the culprit in the temp folder, would be interresting to know :)

EDIT: I guess the problem to be that the IDE generates a method prototype in the top of the source file before the declaration of the struct. To the prototype, the struct is undefined:

void myvoid(mystruct *ms); //Generated by the IDE, mystruct is an undefined type here

struct mystruct { whatever };

void myvoid(mystruct *ms) {
  //mystruct has been defined here and is therefore a valid type
}

Thanks for the thought. I'm not really that interested in finding workarounds for the IDE, or haven't the time is probably a better way to state it. I have a solution. I just though that bringing it to the attention of the Forum might garner a quick answer. Failing that, at least bring it to mind that these mysterious workings are going on behind the green door.

sterretje: To my knowledge, you don't need a typedef...

...in C++. struct and class are identical except the default scope. But, there is no harm in using typedef.

C, on the other hand, is not C++. If @DKWatson wants the code to work with the C compiler then typedef (or a tagged struct) is a necessity.

Point of note, my adherence to C is not some classical fetish. Most (all) modern compilers ship with both and certainly if you have a C++ compiler you can compile almost all C code (generic type macros are still shunned). There are however, legacy sites that only have a C compiler or legacy individuals who never learned C++. Can't really ask them to change.

Prototype generation in 1.8.6 and 1.8.7 is b0rken.

Grab a fixed arduino-builder from https://github.com/arduino/arduino-builder/pull/294#issuecomment-421968368

@oqibidipo There are many issues with .6 and .7, I agree. Based on your comment I just moved the code to 1.8.5 and unfortunately same problem. No problem though, I just moved it to in front of FIFO and it's working fine, all platforms, Still would be interested in knowing what the issue is, but I'm not going to lose sleep over it. No implementation is perfect, it's up to us to make it work.

The issue is the prototype generated by the IDE, you would know that by now had you investigated the temporary file generated by the IDE. When using the Arduino IDE, you can declare a method below/after the "loop" method and still be able to call it from within the "loop" method (non standard C behaviour). The reason for that is that the IDE will create a method prototype and insert it above all other methods in the sketch. That would also be above the struct declared in the middle of the sketch, thus the struct type does not exist to the prototype. When you move the struct above the first method (getBufLen) then the issue vanishes, because now all prototypes are inserted below the struct, thus the type is valid to the prototypes generated.

You would have discovered this, had you followed my suggestion in the first answer, and I do not understand why you are so inclined not to perform this simple investigation?