4

Hi fellow programmers,

I started to program Arduino a little deeply and popped out the following error when I was writing a class to read the pulses of a Hall effect flow rate sensor:

SensorDeVazao.cpp.o: In function `SensorDeVazao::Resetar()':
SensorDeVazao.cpp:141: undefined reference to `SensorDeVazao::SensorHandle'
SensorDeVazao.cpp:141: undefined reference to `SensorDeVazao::SensorHandle'
SensorDeVazao.cpp:141: undefined reference to `SensorDeVazao::SensorHandle'
SensorDeVazao.cpp:141: undefined reference to `SensorDeVazao::SensorHandle'
SensorDeVazao.cpp:141: undefined reference to `SensorDeVazao::SensorHandle'
SensorDeVazao.cpp.o:SensorDeVazao.cpp:141: more undefined references to `SensorDeVazao::SensorHandle' follow
collect2: error: ld returned 1 exit status

The code is divided in two files, a *.h and a *.cpp, so it is uncircumstantial to paste the code here (pos-edited: the codes are the following: *.h: codepad.org/UyLfik6W *.cpp: codepad.org/5KJmraCC). But I will explain the context:

SensorHandle is a static object of the own class SensorDeVazao (Brazilian Portuguese to FlowRateSensor) and it is used in an glue function used by the attachinterrupt to read the pulses I've mentioned previously. The function claimed in the error log ("Resetar", Brazilian Portuguese for reset) don't use the variable "SensorHandle". Last but not least, the message shown in the second line appears subsequently multiple times in the error window.

I hope, I provided all the informations to help you solve this issue. Thank you for the attention.

PS.: Sorry if this is a duplicated post. If yes, please forward it in the comments below.

  • 1
    Sorry Bruno but we need to see the code to know whats going on. Can you post the code around line 141 (130 - 150) if nothing else? I think it is very stange that it is looking for SensorDeVazao::SensorHandle within the class (unless that is a quirk of the compiler). – Code Gorilla Feb 7 '17 at 13:11
  • I've posted below at @frarugi's comment. – Bruno Henrique Peixoto Feb 7 '17 at 13:18
  • 1
    @BrunoHenriquePeixoto Usually it is better to add them directly to the question (just edit the post and put at the bottom the two links) so people coming here will know that they are here – frarugi87 Feb 7 '17 at 13:19
  • 1
    Thank you for the advice. I was not sure about the privilege to add links to the question. – Bruno Henrique Peixoto Feb 7 '17 at 13:24
4

Without seeing the actual code (BTW why can't you add it? Is it top-secret?) I can't be sure, but usually this happens when you don't define a variable but just declare it. Example:

// File myclass.h
class A { 
public:     
  static int i;
};

// File myclass.cpp
void myfunc() {
    A::i = 0;
}

If you actually declare it the error should go away:

// File myclass.h
class A { 
public:     
  static int i;
};

// File myclass.cpp
int A::i = 0;

void myfunc() {
    A::i = 0;
}

Remember that the class definition (so the class {}) can go in a header file, but the variables definition MUST go in a source file (so the .cpp one) AND if you have multiple source files you have to put this in ONLY ONE file (usually the file where you implement the functions).

This only applies to static variables.

EDIT: Further explanation.

You should understand the difference between declaration and definition of a variable.

Definition is just stating "there exist a variable called i, which is an integer"; for instance the statement extern int i; defines a variable. All the variables listed in a class are only defined there.

Declaring a variable is one more step: it tells the compiler to reserve the space in memory (this operation is called allocation) and so to physically create the variable. Always keep this in mind.

Little example. Let's say you have a library, using files lib.h and lib.cpp, and files A.cpp and B.cpp both referencing the library (they have a statement saying #include "lib.h"). When writing a library without a class you usually write global variables in this way:

// header file: lib.h
extern int i;

// source file: lib.cpp
int i;

(note: it is better to always define an initialization value, so for instance int i = 0;). The two files (A and B) both have the line extern int i; in they, which means "there exist a variable called i, and someone else is allocating the space for it. Result: the compiler will link all those definitions to the same memory location, thus actually sharing the variable. If you wrote int i; in the header file each cpp file would have its i variable allocated, so each would point to a different block of memory.

Now, for the classes. If you write

class A {
public:
    int a;
    static int b;
}

you have two variables. A gets instantiated when you instantiate an object, so does not have any problems. But b... well, b is just defined, never declared. So there is no place in memory where b actually resides (the reference is undefined).

To deal with this, you have to manually declare it in a cpp file, with the syntax int A::b;. This way you are reserving some space for that variable

| improve this answer | |
  • Oh, damn, I've been discovered. Haha. Sure, I'll post it, but I'm a little bit skeptical in regard to this definition in *.cpp thing. *.h: codepad.org/UyLfik6W *.cpp: codepad.org/5KJmraCC – Bruno Henrique Peixoto Feb 7 '17 at 13:14
  • The header file looks fine at a first glance, so I'm pretty confident that adding SensorDeVazao* SensorDeVazao::SensorHandle = NULL; (or whatever value you should initialize it) before the functions in your SensorDeVazao.cpp file will solve your problem – frarugi87 Feb 7 '17 at 13:17
  • It worked like a charm. Thank you, Sir! :D But now an explanation is required. – Bruno Henrique Peixoto Feb 7 '17 at 13:29
  • 2
    Much appreciated. You've excelled in the explanation. :D – Bruno Henrique Peixoto Feb 7 '17 at 14:58
  • 1
    Where is my cookie? I demand my cookie! ;P I think asking for how things work is a better way to continuosly learn something new and trick the time about aging. :) – Bruno Henrique Peixoto Feb 7 '17 at 18:06
1

An explanation of what is happening:

When you define a class you indicate what variables will be in it.

When you then instantiate the class (MyClass c;) the variables within the newly instantiated object get allocated.

Static variables never get instantiated. After all - which instance of the class should instantiate them when you create one? And if you never create one? So it's simple: static variables never get created by the class definition or anything else. It is up to you to provide the storage space for that variable, which means statically allocating it in your C++ code as has been demonstrated.

| improve this answer | |
  • Thank you once more for the clear explanation. This code will work with sensors in the University of São Paulo in Brazil. The students and I are very much appreciated. :) – Bruno Henrique Peixoto Feb 7 '17 at 14:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.