View previous topic :: View next topic |
Author |
Message |
kWoody_uk
Joined: 29 Jan 2015 Posts: 47 Location: United Kingdom
|
More pointer confusion [SOLVED] |
Posted: Mon Oct 10, 2016 6:13 am |
|
|
Hi guys,
I thought I had a reasonable understanding of pointers until the following problem popped up:-
Code: |
void func1( void )
{
int8 * srcDataPtr;
// Set up pointer to access channel data within struct
srcDataPtr = &Uart2ParseBuf.data;
if ( flags.channels & 0b00000011 ) {
func2( &SpiPicABuf, srcDataPtr );
}
if ( flags.channels & 0b00001100 ) {
func2( &SpiPicBBuf, srcDataPtr );
}
}
void func2( SpiBufT * buf, int8 * dataPtr )
{
bufSpiData( &buf->tx, *dataPtr );
// Increment the pointer - I want this to increment the original
// address pointed to by srcDataPtr in func1 too... How?
dataPtr++;
}
|
I know that when I'm passing srcDataPtr to func2 it will make a copy of it at a different address. But when I increment the pointer in func2 how do I get it to change the address of the original pointer created in func1, i.e. srcDataPtr?
I've tried using **ptr as the argument to func2 but this doesn't seem to work.
Please help,
Thanks in advance,
Keith
Last edited by kWoody_uk on Tue Oct 11, 2016 2:55 am; edited 2 times in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Mon Oct 10, 2016 8:08 am |
|
|
Think about it:
Uart2ParseBuf.data - variable in memory
srcDataPtr - address of this variable
You can copy this latter as many times as you want, it still points to the same address.
Now you don't actually show func2 being called at all, but if it was being called where bufChDataForSpi is shown, then:
inside the routine, would increment the value being pointed to by DataPtr.
This is all down to operator precedence.
increments the local copy of the pointer. Effectively does nothing, since this is lost when the routine exits.... |
|
|
kWoody_uk
Joined: 29 Jan 2015 Posts: 47 Location: United Kingdom
|
|
Posted: Mon Oct 10, 2016 9:27 am |
|
|
Hi Ttelmah,
Sorry, I didn't make myself clear: I have edited my first post to correct my simplification of function names. And you are correct: I did intend to call func2.
I do understand what you're saying about the dataPtr increment being useless inside func2, but how would I change the address pointed to by the srcDataPtr (in func1) from inside of func2 - when I'm just working on a copy of the pointer?
Sorry if this is unclear.
Keith |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Mon Oct 10, 2016 11:45 am |
|
|
Why would you want to change the address?.
You can increment the contents as I show.
If you want to change the address, then just have the function return the new value. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1353
|
|
Posted: Mon Oct 10, 2016 11:59 am |
|
|
pointer to a pointer: **var_name
Code: |
void func2( SpiBufT * buf, int8 ** dataPtr )
{
bufSpiData( &buf->tx, **dataPtr );
// Increment the pointer - I want this to increment the original
// address pointed to by srcDataPtr in func1 too... How?
(*dataPtr)++;
}
|
Code: |
if ( flags.channels & 0b00001100 ) {
func2( &SpiPicBBuf, &srcDataPtr );
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Tue Oct 11, 2016 1:22 am |
|
|
He is not actually doing that though.
It appears that he simply has an 'address' of some sort held in a structure.
He then takes a pointer to that address and passes this to a routine. He then seems to just want to increment the original address. The routine has a copy of the original pointer. No need for double references at all. If he increments the contents of the pointer, he is incrementing the original address.
However, general comment. every level of indirection you use (pointers to pointers etc.), costs _time_. Look at how ex_sisr.c, handles it's serial buffered data. Simply has counts, which can be incremented, and used as indexes to an array. Even this costs some time, but it's a lot simpler and has less overhead than multiple levels. Also makes limit checking easy, since otherwise if you increment the contents of a pointer to a pointer, how is the code going to know what limits it should apply to this?. Sure fire way of ending up with data disasters.... Think carefully about whether a simpler approach would be better.
To do what he is describing (increment the address at the 'middle' layer), as Jeremiah shows, you have to pass the address of this variable to the next routine (or you could use pass by reference). However this makes you potentially have the danger of the three addresses getting incorrectly aligned to each other, talking to different locations, and makes limit checking even harder... |
|
|
kWoody_uk
Joined: 29 Jan 2015 Posts: 47 Location: United Kingdom
|
|
Posted: Tue Oct 11, 2016 2:51 am |
|
|
Thanks jeremiah,
That's exactly what I wanted to do. I did try to use pointer to pointer syntax, but I didn't get it quite right. I was using MPLAB sim to help me understand the C but it was flummoxing me!
Ttelmah:-
Quote: |
He then takes a pointer to that address and passes this to a routine. He then seems to just want to increment the original address. The routine has a copy of the original pointer. No need for double references at all. If he increments the contents of the pointer, he is incrementing the original address.
|
I did want to increment the original address pointed to by srcDataPtr inside func2, but I then wanted it to remain incremented after func2 exited, and not revert to the original address pointed to by srcDataPtr.
I was getting stuck by the fact that when the pointer was passed to func2, a copy of the pointer was being made inside the function. I then incremented the address pointed to by the pointer, but after the function exited, this increment is lost, so the next time I used the func2 call the address pointed to was back to the original (pointed to by srcDataPtr).
A diagram would have been easier to explain, but I didn't know how to add images on here.
Point taken on extra time though Ttelmah. How would you do "pass by reference"? Is this the thing mentioned in CCS manual?
Thanks all for your help as usual.
Keith |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19537
|
|
Posted: Tue Oct 11, 2016 3:01 am |
|
|
'Pass by reference', is technically a C++ ability. However CCS supports a slightly 'limited' form of it, though it will do exactly what you appear to want:
Code: |
void func1( void )
{
int8 * srcDataPtr;
// Set up pointer to access channel data within struct
srcDataPtr = &Uart2ParseBuf.data;
if ( flags.channels & 0b00000011 ) {
//No & or * here
func2( &SpiPicABuf, srcDataPtr );
}
if ( flags.channels & 0b00001100 ) {
func2( &SpiPicBBuf, srcDataPtr );
}
}
void func2( SpiBufT * buf, int8 &dataPtr )
//note the '&' here
{
//dataPtr is now a reference _[u]to[/u]_ srcDataPtr. If you increment
//it here srcDataPtr will actually get incremented
bufSpiData( &buf->tx, *dataPtr );
//This will actually increment srcDataPtr
dataPtr++;
}
|
Look at 'Reference Parameters' in the manual. |
|
|
kWoody_uk
Joined: 29 Jan 2015 Posts: 47 Location: United Kingdom
|
|
Posted: Tue Oct 11, 2016 3:11 am |
|
|
Thanks Ttelmah - much appreciated.
Keith |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1353
|
|
Posted: Tue Oct 11, 2016 6:09 am |
|
|
One thing to watch out for when passing by reference: I don't know how other compilers do it, but in PCD, it tends to inline the function automatically when I have a reference parameter. Depending on the function, this can blow up the size of your code.
The other option you have is the one Ttelmah mentioned earlier about returning the new pointer value:
Code: |
int8 * func2( SpiBufT * buf, int8 * dataPtr )
{
bufSpiData( &buf->tx, *dataPtr );
// Increment the pointer - I want this to increment the original
// address pointed to by srcDataPtr in func1 too... How?
dataPtr++;
return dataPtr;
}
|
Code: |
if ( flags.channels & 0b00001100 ) {
srcDataPtr = func2( &SpiPicBBuf, srcDataPtr );
}
|
|
|
|
kWoody_uk
Joined: 29 Jan 2015 Posts: 47 Location: United Kingdom
|
|
Posted: Tue Oct 11, 2016 8:58 am |
|
|
Thanks for the tips jeremiah. I'll watch out for those things.
I must admit, I've never used reference parameters - I'm not much of a C++ guy so just haven't found a use for them yet.
It certainly looks as if returning the new pointer value would be more transparent and more efficient code-wise.
Keith |
|
|
|