Compiler issue with "extern"

When I add "extern" declarations of variables in the header file of the code which is using those variables (which are declared & defined in another file) that works fine. Except in 1 particular case: if the file which is using the "extern" variable is the main .ino file (the one with "setup" and "loop") then I get a compiler error: *"variable_name does not name a type; did you mean ...".
AFAIK it is best practice to put extern references always in a header file and not in de code file. Why is this not working for the main header file?
Am I doing something wrong?

please post the code

The sketch is called "Smartfloat" and contains the software to monitor the fuel level in a fuel tank.
In file "Smartfloat.h":

#pragma once

/*--------------------------------+
*  All of this has global scope   *
*---------------------------------*/

#define SYS_JOBLIST_SIZE  16                                                    // size of array to hold job list and job requests


/*------------------+
*     Debugging     *
*-------------------*/

#define DEBUG_MAIN          true                                                // debug Smartfloat.ino

/******************************************************************************
*                            SmartFloat / ESP32 pins                          *
*******************************************************************************/

#define buzzPin             GPIO_NUM_17                                         // buzzer (output)
#define btcLedPin           GPIO_NUM_18                                         // Blue bluetooth connection LED (output)
#define errLedPin           GPIO_NUM_19                                         // Red error LED (output)
#define fuelLedPin          GPIO_NUM_21                                         // Green fuel status LED (output)
#define pwrLedPin           GPIO_NUM_23                                         // Green power LED (output)

#define stripSensorDacPin   GPIO_NUM_25                                         // DAC CH1 50 mV - 2.5 V (output)
#define stripSensorAdcPin   GPIO_NUM_33                                         // ADC to verify correct DAC output (input)

// WARNING: SmartFloat PCB 3.1 rev0 needs wire bridges between GPIO 25 (PIN 9) and GPIO 33 (PIN 8), GPIO 25 and C of D6
// This error has been fixed in PCB rev 1.

#define FLS_FloatSensorPin  GPIO_NUM_34                                         // ADC Float Sensor 0.5 - 2 V (analog input)
#define PWR_vBattPin        GPIO_NUM_35                                         // vBatt = 0 - 3 V (analog input)
#define FLS_StripHeaterPin  GPIO_NUM_36                                         // Fuelstrip heater signal (digital input)
#define FLS_FloatSwitchPin  GPIO_NUM_39                                         // Strip Sensor Heater (digital input)

/******************
*   I/O values    *
*******************/

#define ON                  1                                                   // I/O value
#define OFF                 0                                                   // I/O value

#define SECONDS_IN_HOUR     3600                                                // seconds in 1 hour


/*---------------------+
 * Version Information *
 *---------------------*/

const char * versionString = "0.0.1";                                    // development software version

// Notification


/*---------------------+
 * External references *
 *---------------------*/

extern buzzer_t buzzer;                                                         // Buzzer.ino**
extern char BT_ownMacAddress[];
extern bt_spp_status_t bt_spp_status;
... etc...

The variables are used in file Smartfloat.ino like this:

void loop() {  
  
 /*---------------------------+
  * Execute once every 100 ms *
  *---------------------------*/
  
  if (xSemaphoreTake(smartFloatTimerSemaphore, 0) == pdTRUE)                          // fuelTimer fires every 100 ms
  {
    if(buzzer.active) BUZZ_PlayTune();                                      // play buzzer tune
    if(!engineRunning)
     {Monitor PWR, else monitor PWR every second}
    if(++smartFloatTimer == 10)
     { handle fuel monitoring actions and clear smartFloatTimer }
    BT_SuperviseIncomingStream();                                           // check if BT incoming character stream is flowing
    BT_SuperviseOutgoingStream();                                           // check if BT outgoing character stream is flowing
    VBATT_MonitorVbatt();                                                   // monitor battery voltage
    FLS_MonitorFuelLevel();                                                 // monitor float sensor value
    //FLS_MonitorZFESheater();                                                // monitor fuel strip heater
    //FLS_ShowFuelLevel();                                                    // output fuel level
    LED_LEDmonitor();                                                       // handle LED blinking
	}
	etc...

Buzzer.h contains the declaration of the struct "buzzer_t"

	typedef struct
{
  bool          active;                                                         // true when buzzer is engaged
  uint8_t       pinValue;                                                       // ON or OFF
  buzzStatus_t  status;                                                         // SOUND, SILENCE, WAIT4NEXT
  unsigned int  tune;                                                           // the tune to play
  uint8_t       bitIndex;                                                       // index in tune bit pattern
  uint8_t       waitCounter;                                                    // counter for pause  between tunes
  uint8_t       playList[BUZZ_TUNE_PLAYLIST_SIZE];                              // queue for more tunes to be played
  uint8_t       playListIndex;                                                  // index for playlist
} buzzer_t;

an finally the code file "buzzer.ino" contains the definition of the variable:


buzzer_t    buzzer;                                                             // buzzer object
buzzTunes_t buzzTunes;                                                          // different bitpatterns representing tunes

Post the complete code, not snippets that we have to piece together ourselves.

which variable? where is it defined, declared and used?

The complete error message:

`In file included from D:\Gilbert\Documents\Arduino\ESP32\Code\SmartFloat_3_1_1\SmartFloat_3_1_1.ino:26:
D:\Gilbert\Documents\Arduino\ESP32\Code\SmartFloat_3_1_1\SmartFloat.h:59:8: error: 'buzzer_t' does not name a type; did you mean 'timer_t'?
 extern buzzer_t buzzer;                                                         // Buzzer.ino
        ^~~~~~~~
        timer_t
D:\Gilbert\Documents\Arduino\ESP32\Code\SmartFloat_3_1_1\SmartFloat.h:61:8: error: 'bt_spp_status_t' does not name a type; did you mean 'TaskStatus_t'?
 extern bt_spp_status_t bt_spp_status;
        ^~~~~~~~~~~~~~~
        TaskStatus_t

exit status 1

Compilation error: 'buzzer_t' does not name a type; did you mean 'timer_t'?`

I don't think that you want to walk through 8700 lines of code for this.
When I move the extern declarations from Smartfloat.h to Smartfloat.ino, the problem goes away.
All other files have the extern declarations in the header file and the compiler seems to be happy with that.

The obvious question is, where did you define the buzzer_t and bt_spp_status_t types?

Did you include the header files in which they are defined in the SmartFloats.h file before the extern declarations?

buzzer_t: struct declared in buzzer.ino and defined and used in buzzer.ino like this:
in buzzer.h:

typedef struct
{
  bool          active;                                                         // true when buzzer is engaged
  uint8_t       pinValue;                                                       // ON or OFF
  buzzStatus_t  status;                                                         // SOUND, SILENCE, WAIT4NEXT
  unsigned int  tune;                                                           // the tune to play
  uint8_t       bitIndex;                                                       // index in tune bit pattern
  uint8_t       waitCounter;                                                    // counter for pause  between tunes
  uint8_t       playList[BUZZ_TUNE_PLAYLIST_SIZE];                              // queue for more tunes to be played
  uint8_t       playListIndex;                                                  // index for playlist
} buzzer_t;

in buzzer.ino:

buzzer_t    buzzer;                                                             // buzzer object

bt_spp_status_t: enum declared in BTspp.h and defined and used in BTspp.ino like this:
in BTspp.h:

typedef enum 
{
  BT_SPP_IDLE,                                                                  // ready to accept incoming messages
  BT_SPP_RECEIVING,                                                             // incoming stream in progress
  BT_SPP_SENDING,                                                               // outgoing stream in progress, change to IDLE when done
  BT_SPP_READY2PROCESS,                                                         // incoming stream complete, ready for parsing
  BT_SPP_PROCESSING,                                                            // incoming stream parsing in progress
  BT_SPP_FAIL,                                                                  // something bad happened, re-init after delay
  BT_SPP_CLOSED                                                                 // SPP connection closed
} bt_spp_status_t;

in BTspp.ino:


bt_spp_status_t bt_spp_status;                                                  // status of BT serial communication link

Interesting detail: extern char BT_ownMacAddress[]; is also part of the group of extern references, but doesn't cause a problem. The difference is that BT_ownMacAddress[] is declared and defined in the BTspp.ino file. No declaration in the BTspp.h file.
I'll give it a try and merge the offending declarations into declaration + definition in their .ino file to see if the problem goes away. Surely not in agreement with recommended practice, but what the heck... Moving the extern declarations to the .ino file is also not "clean" code.

:clock1: oesn't Smartfloat.h need to include the . h where the buzzer_t struct is defined?

1 Like

Tried that. This works. Thanks. I thought that "include" always goes in the ino file and that's how it works for all other files. Maybe this doesn't cause problems for the compiler because most other files have been included previously at some point ?

PS: moving the offending declarations from the.h file to the corresponding .ino file didn't work.

Sketch uses 1110901 bytes (84%) of program storage space. Maximum is 1310720 bytes.
Global variables use 42968 bytes (13%) of dynamic memory, leaving 284712 bytes for local variables. Maximum is 327680 bytes.

See My Post #5 in this Thread for a basic guide to breaking large projects into separate .h / .cpp files.

Thanks for the clarification. I tried to stick to gfvalvo's recommended way of working, but with ino files iso cpp. Turns out that the IDE follows a different thinking...
However, when I comment out all "extern" references in my sketch the compiler complains about missing variabe declarations like this:

D:\Gilbert\Documents\Arduino\ESP32\Code\SmartFloat_3_1_1\Buzzer.ino: In function 'void BUZZ_SetTune(buzzTune_t)':
D:\Gilbert\Documents\Arduino\ESP32\Code\SmartFloat_3_1_1\Buzzer.ino:80:7: error: 'generalErrorCounters' was not declared in this scope

Did you see the last line at the link I posted??
image

The rest of the code should be in .cpp files.

Yes, I saw that.
I'm not used to program in "pure" c++. For me that means opening another can of worms ;-). I'll try that with a future (smaller) project.

True. But apart from the issue which started this thread, everything is fine. There's no value for me in changing to cpp in this project.
Thanks for the advice.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.