Alexandre Michaud
Alexandre Michaud

Reputation: 241

What is reason for compile errors from .h file of custom library class in Arduino IDE

I am developing a program for a robot using Energia (a fork of Arduino). I decided to create a library composed of a single class to handle position and distance calculations.

When I try to use the class I am seeing compiler errors that I do not understand.

Here is my .h file:

#ifndef Position
#define Position
#include "Energia.h"
class Position
{
    public:
        Position(int PinEcho, int PinTrig);
        float getDistance(char* Distance);
        float getDistanceMoy(int Nombre,char* unite);
    private:
        int _pinEcho;
        int _pinTrig;

};
#endif

And the .cpp file contains:

#include "Energia.h" //Arduino.h if we are using Arduino
#include "Position.h"

Position::Position(int pinEcho,int pinTrig)
{
    pinMode(pinEcho, OUTPUT);
    pinMode(pinTrig, INPUT);
    digitalWrite(pinTrigger, LOW);
    int _pinEcho = pinEcho;
    int _pinTrig = pinTrig;
    const unsigned long MEASURE_TIMEOUT = 25000UL;
    const float SOUND_SPEED = 340 / 1000;
}

float Position::getDistance(char* mode){
    digitalWrite(pinTrigger, LOW);
    digitalWrite(pinTrigger, HIGH);
    delayMicroseconds(10);
    digitalWrite(pinTrigger, LOW);
    long mesure = pulseIn(pinEcho,HIGH,MEASURE_TIMEOUT);
    float distance = mesure / 2 * SOUND_SPEED;
    if(mode =="cm") distance = distance / 10;
    if(mode =="dm") distance = distance / 100;
    if(mode == "m") distance = distance / 1000;
    return distance;
}

float Position::getDistanceMoy(int maxi,char* mode){
    int i=0, j=0;
    int distMoy = 0;
    while(i != maxi ){
        digitalWrite(pinTrigger, LOW);
        digitalWrite(pinTrigger, HIGH);
        delayMicroseconds(10);
        digitalWrite(pinTrigger, LOW);
        long mesure = pulseIn(pinEcho,HIGH,MEASURE_TIMEOUT);
        float distance = mesure / 2 * SOUND_SPEED;
        if(distance != 0){
            distMoy += distance;
            j++;
        }
        i++;
    }
    distMoy = distMoy/j;
    if(mode =="cm") distMoy = distMoy / 10;
    if(mode =="dm") distMoy = distMoy / 100;
    if(mode == "m") distMoy = distMoy / 1000;
    return distMoy;
}

Then I import the library on Arduino with #include <Position.h> and then initialize it:

Position position(Variable1,Variable2);

But when I want to use it and Energia (or Arduino) I get these errors:

In file included from C:\Users\alex9\Documents\Energia\sketch_may10a\sketch_may10a.ino:1:0:
C:\Users\alex9\Documents\Energia\libraries\Position/Position.h:15:18: error: expected unqualified-id before 'int'
         Position(int PinEcho, int PinTrig);
                  ^
C:\Users\alex9\Documents\Energia\libraries\Position/Position.h:15:18: error: expected ')' before 'int'
C:\Users\alex9\Documents\Energia\libraries\Position/Position.h:13:1: error: an anonymous struct cannot have function members
 {
 ^
C:\Users\alex9\Documents\Energia\libraries\Position/Position.h:22:1: error: abstract declarator '<anonymous class>' used as declaration
 };
 ^
sketch_may10a:8: error: expected constructor, destructor, or type conversion before '(' token
 Position position(PinEcho,PinTrig);
                  ^
exit status 1 expected constructor, destructor, or type conversion before '(' token

I don't understand these error messages and don't know what I need to fix. Could someone help me?

Upvotes: 1

Views: 481

Answers (2)

Richard Chambers
Richard Chambers

Reputation: 17573

In your .h file you have the following lines of text which are Preprocessor commands to:

  • check to see if the Preprocessor macro "Position" is defined
  • if it is not defined then define it as empty or no text

Once the Preprocessor does this macro definition for the macro "Position" then as the Preprocessor continues to do its source text processing, one of the things it does is everytime it finds the token "Position" it will replace that token with its defined value which in this case is the empty string.

#ifndef Position
#define Position

You must remember when using the Preprocessor that it is an additional processing step that has nothing to do with compilation. It is a text only processing step which is used to modify the source text before it is fed into the compiler which is a totally separate step.

You can check what is happening by running the Preprocessor by itself and looking at the resulting output file. How that is done will vary between compilers though typically it is a compiler switch.

The typical way to put Preprocessor guards in a .h file is to do something like this example. This Preprocessor macro for an include file guard is made up of the name of the include file followed by the letter "H" followed by the word "included" with the various parts connected with underscores:

#ifndef POSITION_H_INCLUDED
#define POSITION_H_INCLUDED

By using this macro name it is much less likely that you will have a clash between the macro name and some variable or class or struct name/label or other text token within the source file.

This naming convention does a couple of things for you.

First it uses all upper case which is the defacto standard for Preprocessor macro names.

Secondly it is pretty descriptive of the intent of this macro name.

Thirdly the probability of some other text token being the same is fairly remote so the likelihood of an error such as you are running into is small.

Naming Approaches for Large Bodies of Source Code

However with a large project, as in hundreds of thousands of lines of code with thousands of files, it is possible that the same name is used for different include files in different libraries. This same issue is why the namespace concept was invented with C++.

So a more complex name using some additional text added to the macro name would increase the probability of the macro name being unique. One approach would be to add the name of the library or the name of the manufacturer to the macro name.

#ifndef POSITION_H_INCLUDED_POSITION_LIB_MICHAUD
#define POSITION_H_INCLUDED_POSITION_LIB_MICHAUD

A simple approach is to add the date and time into the macro name as in:

#ifndef POSITION_H_INCLUDED_20180517_1021_00
#define POSITION_H_INCLUDED_20180517_1021_00

Some IDEs will do something similar for you as part of generating source code for classes and that sort of thing. Here is an example from an older Visual Studio C++ IDE that generated an MFC class include file. This is kind of overkill in that it appears the IDE generates a GUID, which is pretty unique, and uses that to create what is like 99.999999999% likely to be a unique Preprocessor macro name or identifier. Notice that as part of generating this macro name, the IDE used the name of the include file, the letter "H", and the word "included" along with the GUID.

#if !defined(AFX_OPOSCASHDRAWER_H__86921069_045D_4880_A41A_5A18F0E5FABD__INCLUDED_)
#define AFX_OPOSCASHDRAWER_H__86921069_045D_4880_A41A_5A18F0E5FABD__INCLUDED_

Also notice that the IDE generated Preprocessor directive is using the defined() operator. This allows you to use more complex logical operations with the #if directive of the Preprocessor.

See this Wikipedia article, C Preprocessor for more details about the Preprocessor. This material should apply to most C++ versions of the Preprocessor as well.

Upvotes: 4

Alberto Valero
Alberto Valero

Reputation: 440

You should not name the Class the same way you name your define

A define is like an alias, so, your Class name is being set to the define value, in your case empty string.

Upvotes: 0

Related Questions