Pages: [1]   Go Down
Author Topic: Multiple source files and global variables  (Read 2150 times)
0 Members and 1 Guest are viewing this topic.
Ontario, Canada
Offline Offline
Jr. Member
**
Karma: 0
Posts: 96
Love OpenSource...
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I have a large sketch that I would like to break into multiple source files. Basically a library but not use a class (I have to understand classes much better first). The functions make use of global variables that I need to access in the main sketch and in the functions itself. I created an very small example that recreates the problem/scenario.

I am getting the following errors
Code:
func.cpp.o: In function `toggle()':
func.cpp:16: undefined reference to `state'
func.cpp:17: undefined reference to `pin'
func.cpp:19: undefined reference to `state'
func.cpp:21: undefined reference to `pin'
func.cpp:23: undefined reference to `state'
func.cpp.o: In function `toggleSetup()':
func.cpp:10: undefined reference to `pin'
var_test.cpp.o: In function `setup':
var_test.cpp:11: undefined reference to `pin'

My main sketch var_test.ino
Code:
// var_test.ino

#include <SoftwareSerial.h>
#include "func.h"

void setup() {
  // put your setup code here, to run once:
  pin = 5;
  toggleSetup();
}

void loop() {
  toggle();
  delay(3000);
}

The file with the functions func.cpp
Code:
// func.cpp

#include <Arduino.h>
#include "func.h"

SoftwareSerial testSerial(2, 3);

void toggleSetup()
{
  pinMode(pin, OUTPUT);
  testSerial.begin(9600);
}

void toggle()
{
  if (state == 0) {
    digitalWrite(pin, HIGH);
    testSerial.print('H');
    state = 1;
  } else {
    digitalWrite(pin, LOW);
    testSerial.print('L');
    state = 0;
  }
}

The header file func.h
Code:
// func.h

#include <SoftwareSerial.h>

extern char state;
extern char pin;

void toggleSetup();
void toggle();
Logged


Ontario, Canada
Offline Offline
Jr. Member
**
Karma: 0
Posts: 96
Love OpenSource...
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I found my answer...

The variable needs to be declared in the header file (func.h) just like a function prototype. But it cannot be initialized in the header file. Instead the initialization can happen in either source file. Since my global vars are specific to the library, it makes the most sense to put the initialization into the func.cpp file.

In my actual project I initialized all the global variables in the header file. I did not do that in the example I posted, but the results are nonetheless the same. So here is a func.cpp with which the project will build just fine.

Code:
// func.cpp

#include <Arduino.h>
#include "func.h"

SoftwareSerial testSerial(2, 3);

char state = 0;
char pin = 5;

void toggleSetup()
{
  pinMode(pin, OUTPUT);
  testSerial.begin(9600);
}

void toggle()
{
  if (state == 0) {
    digitalWrite(pin, HIGH);
    testSerial.print('H');
    state = 1;
  } else {
    digitalWrite(pin, LOW);
    testSerial.print('L');
    state = 0;
  }
}
Logged


West Des Moines, Iowa USA
Offline Offline
Sr. Member
****
Karma: 2
Posts: 428
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

although state and pin are declared to be extern in func.h, and although func.h has been included to help the linker resolve references to them, you have not defined these two variables in the code you've shown. You need to do that.
Logged

There's always a better way!

Ontario, Canada
Offline Offline
Jr. Member
**
Karma: 0
Posts: 96
Love OpenSource...
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I had declared them in func.h. But I have to initialize the variable in a global scope in the cpp or ino file. The variable cannot be initialized in the header file. That is the mistake I made.
Logged


West Des Moines, Iowa USA
Offline Offline
Sr. Member
****
Karma: 2
Posts: 428
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Exactly so (This distinction between declaring a variable and defining it is important). Note that initialization is not a requirement for definition.
Logged

There's always a better way!

Ontario, Canada
Offline Offline
Jr. Member
**
Karma: 0
Posts: 96
Love OpenSource...
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

To get this right...

Code:
unsigned long time = 200;
char pin;
pin = 5;

Line 1: declare and initialize the variable time
Line 2: declare the variable pin
Line 3: initialize the variable pin

What exactly is defining a variable?
Logged


West Des Moines, Iowa USA
Offline Offline
Sr. Member
****
Karma: 2
Posts: 428
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Definition takes place when code results in memory allocation.

Declaration (when not in combination with definition) simply informs the compiler of attributes.

char *strcpy(char *d,char *s);
extern int foo;

are declarations while

char *strcpy(char *d,char *s) { /*code */ }
int foo;
int foo = 42;

are definitions.
Logged

There's always a better way!

Ontario, Canada
Offline Offline
Jr. Member
**
Karma: 0
Posts: 96
Love OpenSource...
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Oh... this means then,

"extern int foo;" -> declares a variable which essentially informs the compiler we intent to use it
"int foo;" -> defines the variable and causes memory to be allocated, but the content is undefined
"int foo = 42;" -> defines and initializes the variable, memory is allocated and set to the value (42)

Thank you!
Logged


Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 176
Posts: 12283
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Almost...

"int foo;" -> defines the variable and causes memory to be allocated, but the content is undefined initialized to zero
Logged

Pages: [1]   Go Up
Jump to: