C++ - Teaching old dog new tricks?

Status
Not open for further replies.
I like tni's program too, that's so amazing to learning c++.
 
Yes - it is reading TNI code examples is one of the reasons I started looking at some of the new stuff..

Now I am wondering about something in new SPI code that probably is obvious to others, but wondering.

That is for the constructor, instead of simply passing in a pointer or reference to some other objects/structures, it instead passes in these values as:
uintptr_t values, and then has helper function to cast the value to a reference to that structure.

Example:

The Constructor:
Code:
	constexpr SPIClass(uintptr_t myport, uintptr_t myhardware)
		: port_addr(myport), hardware_addr(myhardware) {
	}
Where for example port_addr is defined as:
Code:
	uintptr_t port_addr;
And everywhere that wishes to use this as a reference calls helper function:
Code:
KINETISK_SPI_t & port() { return *(KINETISK_SPI_t *)port_addr; }

Like:
Code:
port().PUSHR = *p_write++ | SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0);

So wondering reason for this? My guess is it may have to do with the issue of order of object constructors being called?

Also wonder if helper function port() should be marked inline? Also side not, actually think this function should be marked as public and not private... As other libraries may wish to grab this as well to handle multiple buses... But that is different subject.

Edit: It appears to be required if our constructor is defined as consstexpr
 
Last edited:
Edit: It appears to be required if our constructor is defined as consstexpr

I'm wondering if this type of declaration and usage is to avoid security holes?
(no passing by reference and local usage as reference)
Is not Pascal like this?
 
Now I am wondering about something in new SPI code that probably is obvious to others, but wondering.

That is for the constructor, instead of simply passing in a pointer or reference to some other objects/structures, it instead passes in these values as:
uintptr_t values, and then has helper function to cast the value to a reference to that structure.

...

Edit: It appears to be required if our constructor is defined as consstexpr
Correct. It's the equivalent of these Wire changes:
https://github.com/PaulStoffregen/Wire/pull/7

Constexpr doesn't allow reinterpret_cast (or C-style casts that are equivalent). The standard memory mapped register definitions contain reinterpret_casts, so they can't be used (and reinterpret_cast is required to initialize pointers / references to memory mapped locations). (GCC is inconsistent about enforcing this depending on the context and different versions have different behavior.)

Also wonder if helper function port() should be marked inline?
In-class definitions are automatically inline. 'port()' does get inlined.

I'm wondering if this type of declaration and usage is to avoid security holes?
Having a constexpr constructor fixes initialization order issues. E.g., if someone has a global instance of some object that uses Wire or SPI in the constructor, they might not be initialized when they are used (if they don't have the constexpr constructor):
https://forum.pjrc.com/threads/4308...ensyduino-1-36?p=139042&viewfull=1#post139042

EDIT:
Another nice side effect of constexpr is that GCC optimizes better and eliminates unused virtual functions (you may have noticed that recent TD releases use less flash):
https://github.com/PaulStoffregen/cores/pull/232#issuecomment-301611338
 
Last edited:
Thanks!

I am putting up a WIP version of SPIN using this, which I will talk about on other thread.
 
Status
Not open for further replies.
Back
Top