re#define before or after #include

FredCailloux
Posts: 69
Joined: Sat Mar 28, 2015 4:45 am
Location: Quebec - Canada

re#define before or after #include

Post by FredCailloux » Sun Mar 06, 2016 2:51 am

Here is the pertinent part of my sketch for which I have difficulties figuring out how to implement redefinition of a #define line.
I am building a Class for my LS7366 chip to run with the Digilent DSPI library. The Class SPI7366 is built so that it is using the DSPI0 object by default. At least that's what I am trying to implement. So I use the lines:

Code: Select all

#ifndef SPIPORT  // in the header file SPI7366.h
#define SPIPORT DSPI0 
#endif
in my header file, hoping that the preprocessor will define the word SPIPORT back to DSPI0 when the file gets included.
If, in further projects I want to use the DSPI2 object, all I would have to do is insert a line in my sketch to redefine the SPIPORT to DSPI2 as in:

Code: Select all

#define SPIPORT DSPI2  // in a further sketch
And it doesn't work. ;) For some reason that I cant figure out the preprocessor is either choking with an error or just define my object name to some strange thing that render the Class inoperable. In an attempt to debug the situation I forced the Class header to define the object name LScom to DSPI2 as in:

Code: Select all

  DSPI2 LScom;   // forced definition of SPI object named LScom in the SPI7366.h header file
And it started working like water flowing in a river. Here is a more complete (but partial) pertinent part of the code:

Code: Select all

// Implementation Sketch		
#include <SPI7366.h> /* 		
#define SPIPORT DSPI2		
SPI7366	LSspi;	
void setup() {	LSspi.initSPI();	
	LSspi.enableCount( ) ; }	
void loop() {	LSspi.read1Count( );	
	myCount = LSspi.getCount( ) ;	
	Serial.println (myCount) ;	
	delay(1000) ; }	
		
#ifndef _SPI7366_H // // header file SPI7366.h
	#define _SPI7366_H	
	#include <stdint.h>	
	#include <DSPI.h>	
	#ifndef SPIPORT	
	#define SPIPORT DSPI0 	
	#endif	
		
	class SPI7366 {	
	public:	
	SPI7366();	// Class SPI7366 constructor
	SPIPORT LScom;	// define SPI object named LScom
	};	
#endif		
		
		
#include <SPI7366.h>	// SPI7366.cpp file	
SPI7366::SPI7366( ) { }		
		
void SPI7366::begin() {  }		
		
void SPI7366::initSPI(){		
LScomm.begin() ;		
LScomm.setSpeed(250000);		
delay(10);		
Serial.println ("init:");}		
I tried putting the #define SPIPORT DSPI2 before the #include SPI7366.h as a first line but it doesn't work either. Of course it could not work because when the #define SPIPORT DSPI2 line is executed the preprocessor doesn't have the pertinent code to apply the #definition cause the SPI7366.h file is not loaded already. So it's kind of a head to tail problem. There's got to be a solution to this, it's just that it's beyond my skill so far.

So, here is the question: How can I implement this preprocessor behavior so that I can redefine the SPIPORT word to something else when it as already been defined ?
Prashant Tripathi :idea: Knowing is to the Self what knowledge is to the ego

User avatar
majenko
Site Admin
Posts: 2164
Joined: Wed Nov 09, 2011 7:51 pm
Location: UK
Contact:

Re: re#define before or after #include

Post by majenko » Sun Mar 06, 2016 12:14 pm

You can't.

When you #define something it is only #defined in the file that you #define it in, and in any files that are #included within that file. It's not #defined in any other files, nor in any files included in any other files. That includes the .cpp file.

Compilation is made up of a number of compilation units where each is completely separate. At the end of compilation they are linked together to form the resultant hex file.

Simply put, you get (amongst other things):
  • Sketch INO + Header = Sketch.o
  • Library CPP + Header = Library.o
  • Sketch.o + Library.o = HEX file
#defining something in the Sketch INO doesn't define it in the Library CPP because it's not defined in it nor in any file that is #included by it.

There are two basic ways around the problem - the hard, cryptic, but efficient way, and the easy, understandable, though maybe less efficient way. I always use the latter since it is so much easier to know what is going on.

The first way is to use C++ templates to provide the DSPI port as part of the constructor:

Code: Select all

LSspi<DSPI0> myLS;
If you're curious about that method you can read up about C++ templates, but they're not for the faint of heart (also it means all your code ends up in the header file which is something I don't like, even if it is templated).

The second way is to pass a pointer to a DSPI object as a parameter to the constructor and then store that pointer in your class. You then use that pointer for all your SPI calls. It's the method I always use:

Code: Select all

class foo {
    private:
        DSPI *_spi;
    public:
        foo(DSPI &spi) : _spi(&spi) {}
        foo(DSPI *spi) : _spi(spi) {}
        void begin() {
            _spi->begin();
        }
};

DSPI2 spi;
foo MyFoo(spi);
Note the double constructor there - that allows you to use either a reference or a pointer - so you can either use "&spi" in the constructor or just "spi" and it doesn't matter which - means the end user doesn't have to remember if it's a pointer or not that he needs to pass.

For some systems I also create special profile classes if you want to use things in specific sockets. For instance, for the OLED PMOD I have a set of special wrapper classes like this:

Code: Select all

class SSD1306_PMOD_D : public SSD1306 {
    public:
        SSD1306_PMOD_D() : SSD1306(new DSPI0(), 24, 28, 31, 30, 29) {}
};
It just creates a new class that inherits the main class with default parameters - note that because of the double constructor above you can use "new DSPI0()" in the constructor - since it creates a pointer. Using that class is then as simple as:

Code: Select all

SSD1306_PMOD_D oled;
Why not visit my shop? http://majenko.co.uk/catalog
Universal IDE: http://uecide.org
"I was trying to find out if it was possible to only eat one Jaffa Cake. I had to abandon the experiment because I ran out of Jaffa Cakes".

FredCailloux
Posts: 69
Joined: Sat Mar 28, 2015 4:45 am
Location: Quebec - Canada

Re: re#define before or after #include

Post by FredCailloux » Mon Mar 07, 2016 1:30 am

All this is a bit beyond my expertise, hence, I will have to do some digestive thinking here (and study). And then, I'll most probably come back to you with some more questions... Anyhow, teaching very appreciated. I will rethink my class, this approach appear to be the most elegant and functional way to go. Thanks
Prashant Tripathi :idea: Knowing is to the Self what knowledge is to the ego

FredCailloux
Posts: 69
Joined: Sat Mar 28, 2015 4:45 am
Location: Quebec - Canada

Re: re#define before or after #include

Post by FredCailloux » Tue Mar 08, 2016 3:59 am

Hello Majenko, In my bit of code, on the original post, I list the sketch, the header and the cpp files (at least part of them). As listed in this example, the cpp file is related to the header only with the DSPI object called LSspi (which by default is suppose to take DSPI0 definition). If I can manage to re-edit the header file only, I will have what I want, ie: changing the DSPI object from DSPI0 to DSPI2 or DSPI1. Nowhere is this strategy I attempted to modify the cpp file. So, please let me rephrase my question with better accuracy if I may:
How can I implement this preprocessor behavior so that I can redefine the SPIPORT word in the header file to something else when it has already been defined in the header ? OR, Is there a way to be able to change the word SPIPORT to something else (DSPI2 or DSPI1) within the header file, whether I do it before or after the #include SPI7366 header or by another strategy ? I was thinking to maybe use conditional #define directive to check one defined variable in the sketch that would command the preprocessor to #define SPIPORT based on a choice, a little bit like a Switch Case clause kind of preprocessor command, is there such a thing ? Does that make sense ?
Thanks for your inputs
Prashant Tripathi :idea: Knowing is to the Self what knowledge is to the ego

User avatar
majenko
Site Admin
Posts: 2164
Joined: Wed Nov 09, 2011 7:51 pm
Location: UK
Contact:

Re: re#define before or after #include

Post by majenko » Tue Mar 08, 2016 9:54 am

What you have to remember is that a header file isn't an individual entity in its own right. When you #include the file it literally replaces the #include statement with the content of the file. That means it is replaced direct into the cpp file in one instance, and also replaced into your sketch in another instance. So you have two copies of it, and the two are completely separate.

So doing any kind of definition only affects the file that it is defined in - your sketch in this case.

It's like if you have two pieces of paper and write "hello = goodbye. Hello" on one and just "hello" on the other. Only one of them knows that hello = goodbye - on the other hello is just hello.

The only possible way you can do it with a #define is if that #define is in a file that is #included by the header file, and that gets a bit pointless, since the user may as well just edit the header file itself.

The only other "global" place where you can define something is on the command line with -D, but that limits you to what you can do and where. In MPIDE you can't do it at all. In UECIDE you can define a special control file in the library that gives you menu entries to set -D options. In the Arduino IDE again you can't do it.

Sent from my SM-T555 using Tapatalk
Why not visit my shop? http://majenko.co.uk/catalog
Universal IDE: http://uecide.org
"I was trying to find out if it was possible to only eat one Jaffa Cake. I had to abandon the experiment because I ran out of Jaffa Cakes".

FredCailloux
Posts: 69
Joined: Sat Mar 28, 2015 4:45 am
Location: Quebec - Canada

Re: re#define before or after #include

Post by FredCailloux » Tue Mar 08, 2016 9:00 pm

OK then, I am convinced. I am going to go with your method. So lets get back to your example code here for sake of understanding:

Code: Select all

1-	class foo 	{
2-		private:
3-			DSPI *_spi;
4-		public:
5-			foo(DSPI &spi) 	: _spi(&spi) {}
6-			foo(DSPI *spi) 	: _spi( spi) {}
7-					 void begin() 	{
8-						_spi->begin();
9-                                }
10-               };
11-
12-   DSPI2 spi;
13-   foo MyFoo(spi);
I did some reading on templates and classes and, of course, all kinds of questions are popping out :?
So, i went on an tried to analyze as much as I could and here is my understanding. I would appreciate if you could read and let me know if I have it or if I am going the wrong track here:

From line 1 to 10 would be lines of code part of the header file ( or would they appear in the cpp file) ?
Lines 12 and 13 would be lines of code part of the INO sketch

Line 12 instantiate an object of type class DSPI2 which is inherited from the class DSPI, named spi
Line 13 instantiate an object of type foo, using the object spi as a constructor parameter, this object is named MyFoo
Line 3 when instantiated, the class object spi will create a variable of type pointer to an object DSPI, this pointer is named _spi.
Line 3 this is not the same object spi then the one instantiated at line 12, it is distinct has it is named _spi.
Line 5 list the class constructor code, using an intrinsic variable of type pointer to DSPI address, named spi. :?:
Line 5 this DSPI address pointer is utilized give value to the private _spi pointer (here I have a question ) :?:
Line 6 is another class constructor using a variable of type pointer to DSPI content, named spi (same as line 5) :?:
Line 5 and 6 are both constructors. Implementing the Overloading capabilities of classes in C++.
Line 5 and 6 Giving capability to the class foo to accept either a pointer to address of the object DSPI or pointer to the content of object DSPI :?:
Line 7 is the intrinsic begin() function of any class in C++. It will be executed when the MyFoo object is instanciated.
Line 8 is the intrinsic begin() function of object _spi.

Now the questions: Line 5 and 6 are two constructors using a different parameter format. &spi and *spi :?:
I have never seen a variable pointer type defined as such ( type &var), such as in (DSPI &spi). Does that mean: variable of type DSPI named spi and refered to by it's address &spi ? Couldn't we just write this line as such (DSPI spi)?
I now am confused a little. *spi is the content of the spi object. spi is the object proper. &spi is it not the address of the object spi?
My confusion is from line 6 as well. &spi will give a value to *_spi (OK) (*spi) will be used in the construction as (spi) alone ? why not (*spi) and if so, this would generate an error because _spi is a pointer to object DSPI, not spi itself. How come your code would work ?
please elaborate in this context.

Thank you for your valuable input. Fred
Prashant Tripathi :idea: Knowing is to the Self what knowledge is to the ego

User avatar
majenko
Site Admin
Posts: 2164
Joined: Wed Nov 09, 2011 7:51 pm
Location: UK
Contact:

Re: re#define before or after #include

Post by majenko » Tue Mar 08, 2016 9:39 pm

LOL... questions galore ;) Ok... here we go:
From line 1 to 10 would be lines of code part of the header file ( or would they appear in the cpp file) ?
Both. I combined them for simplicity. You would split it as you have it now - definition of the class in the header and the code for the class (there is only the begin method there) in a cpp file.
Lines 12 and 13 would be lines of code part of the INO sketch
That is correct.
Line 12 instantiate an object of type class DSPI2 which is inherited from the class DSPI, named spi
Line 13 instantiate an object of type foo, using the object spi as a constructor parameter, this object is named MyFoo
Correct.
Line 3 when instantiated, the class object spi will create a variable of type pointer to an object DSPI, this pointer is named _spi.
Line 3 this is not the same object spi then the one instantiated at line 12, it is distinct has it is named _spi.
No, _spi and spi are the exact same object. _spi is a pointer to the address of spi.
Line 5 list the class constructor code, using an intrinsic variable of type pointer to DSPI address, named spi. :?:
Line 5 this DSPI address pointer is utilized give value to the private _spi pointer (here I have a question ) :?:
Line 6 is another class constructor using a variable of type pointer to DSPI content, named spi (same as line 5) :?:
Line 5 and 6 are both constructors. Implementing the Overloading capabilities of classes in C++.
Line 5 and 6 Giving capability to the class foo to accept either a pointer to address of the object DSPI or pointer to the content of object DSPI :?:
This is where the fun is - a * is a pointer, an & is a reference. They both perform the same job - making 2 variables share the same memory space and thus be the same variable with different names and scopes - but they do it in different ways.

Pointers are a really fun topic and not one that is easy for the novice to get their head around (it took me a number of years, but then I didn't have me for a teacher ;) )

You have a variable, say "spi". You get the address of the variable as a number using "&spi". That address can be assigned to a pointer which is created as "*_spi".

So say the object "spi" has been created and is located in memory at address 69.
You create the pointer variable _spi. Let's say that is located at address 123.
Into the variable _spi you place the number 69. This is the "pointer" aspect of it in that it "points" to where the "spi" variable is.
Because _spi is a pointer and not a real object you have to access it in a special way. In fact there are two ways of accessing it, depending on what you are doing.

In general, to access the members of an object through a pointer you just replace "." with "->", so "spi.begin()" becomes "_spi->begin()". This tells the compiler to "dereference" the pointer and act on the object that it is pointing to.

If it's not an object that is being pointed to but a normal variable, like an "int", then you need to manually dereference the pointer by adding a * to the beginning of it, such as "*intptr = 3", but you can ignore most of that for the time being.

That is all the "classic" way of dealing with pointers - the way that has been in C since the dawn of time. C++ introduced a new way - references.

These perform the exact same job but in a different way - one that can be a little tidier, though more obscured.

References are only ever created when passing a variable to a function as a parameter. You specify a reference as "&varname" in the parameter list, such as

Code: Select all

void foo(DSPI &spi) {
    ...
}
That creates a new variable "spi" and places it at the same memory location as the object you pass to the function. This is a real object, but since it shares the same memory location it is the same object as the one you pass. And it has the advantage that you can still access it in the exact same way, so "outsidespi.begin()" stays as "insidespi.begin()" (for example) - the "." stays as a "."

So we have two constructors:

Code: Select all

foo(DSPI *spi)    : _spi( spi) {}
That says "Give me a pointer to a DSPI object and I will store that address in my _spi variable.

You would call that as

Code: Select all

foo myFoo(&spi)
Then we have:

Code: Select all

foo(DSPI &spi)    : _spi(&spi) {}
That says "Give me a DSPI object and I will create a new one at the same address with the same data. I will then get the address of that new object and store it in my _spi variable".

You call it as:

Code: Select all

foo myFoo(spi);
So either way the _spi pointer is assigned the address of your "spi" object from your class - either through being manually passed the pointer or through a reference to the object and then getting the address of that reference itself.

It all gets so confusing because of the repeated use for the same symbols (& and *) to mean different things in different places.

You have to just remember:

A * in a variable declaration is a pointer. A * in a variable assignment is a dereference.
A & in a function prototype is a "byref" indicator. An & in a variable assignment is a "Get me the address of this variable".

Line 7 is the intrinsic begin() function of any class in C++. It will be executed when the MyFoo object is instanciated.
No, "begin" is an Arduinoism. It's used to get around a problem known as the "Static Initialization Order Fiasco" and is manually called by the user in their sketch.
Line 8 is the intrinsic begin() function of object _spi.
Not intrinsic - see above.

I hope that is as clear as mud :)
Why not visit my shop? http://majenko.co.uk/catalog
Universal IDE: http://uecide.org
"I was trying to find out if it was possible to only eat one Jaffa Cake. I had to abandon the experiment because I ran out of Jaffa Cakes".

FredCailloux
Posts: 69
Joined: Sat Mar 28, 2015 4:45 am
Location: Quebec - Canada

Re: re#define before or after #include

Post by FredCailloux » Tue Mar 08, 2016 10:21 pm

Mud it is, but it gets clearer every minute :D
and You are my teacher ;)
Now... let me digest for a while...
thanks again
Prashant Tripathi :idea: Knowing is to the Self what knowledge is to the ego

FredCailloux
Posts: 69
Joined: Sat Mar 28, 2015 4:45 am
Location: Quebec - Canada

Re: re#define before or after #include

Post by FredCailloux » Tue Mar 08, 2016 10:54 pm

in my INO sketch, instead of two lines such as

Code: Select all

DSPI2	spiChoice	            ;
LS7366	MyLS7366 ( spiChoice ) ;
Could I replace with

Code: Select all

LS7366	MyLS7366 ( DSPI2 )     ;
What difference would that make, since I will not ever have to address that DSPI object ever in the sketch,
I don't need a variable name here, do I ?
Prashant Tripathi :idea: Knowing is to the Self what knowledge is to the ego

User avatar
majenko
Site Admin
Posts: 2164
Joined: Wed Nov 09, 2011 7:51 pm
Location: UK
Contact:

Re: re#define before or after #include

Post by majenko » Tue Mar 08, 2016 11:15 pm

Almost.

There you are referencing the class, not an instance of the class. You need to create a "new" instance of the class:

Code: Select all

LS7366   MyLS7366 ( new DSPI2() );
Why not visit my shop? http://majenko.co.uk/catalog
Universal IDE: http://uecide.org
"I was trying to find out if it was possible to only eat one Jaffa Cake. I had to abandon the experiment because I ran out of Jaffa Cakes".

Post Reply