When using pointer is useful

Go To Last Post
21 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi 

some where i read when u want to call function it is better pass pointer instead of variable .

here is my simple test:

as you see the function that work by pointer has less assembly code   

 

 15          int Increment(int var2){  
   \                     Increment:
   \   00000000   019C               MOVW    R19:R18, R25:R24
   \   00000002   01C8               MOVW    R25:R24, R17:R16
     16            PORTB=++var2;
   \   00000004   9601               ADIW    R25:R24, 1
   \   00000006   018C               MOVW    R17:R16, R25:R24
   \   00000008   01C8               MOVW    R25:R24, R17:R16
   \   0000000A   B905               OUT     0x05, R16
     17            return PORTB;
   \   0000000C   B105               IN      R16, 0x05
   \   0000000E   E010               LDI     R17, 0
   \   00000010   01C9               MOVW    R25:R24, R19:R18
   \   00000012   9508               RET
   \   00000014                      REQUIRE _A_PORTB
     18          }
int IncrementByPointer(int *var2){  
   \                     IncrementByPointer:
     11            PORTB=((*var2)+1);
   \   00000000   01F8               MOVW    R31:R30, R17:R16
   \   00000002   8100               LD      R16, Z
   \   00000004   9503               INC     R16
   \   00000006   B905               OUT     0x05, R16
     12            return(PORTB);
   \   00000008   B105               IN      R16, 0x05
   \   0000000A   E010               LDI     R17, 0
   \   0000000C   9508               RET
   \   0000000E                      REQUIRE _A_PORTB
     13          //  return *var2;
     14          }

 

 

But in this sample code it's inverse :

     24            while ((*P_Ram)<10)
     25                   ++(*P_Ram);
   \                     ??main_1:
   \   00000012   91E0....           LDS     R30, P_Ram
   \   00000016   91F0....           LDS     R31, (P_Ram + 1)
   \   0000001A   8100               LD      R16, Z
   \   0000001C   8111               LDD     R17, Z+1
   \   0000001E   5F0F               SUBI    R16, 255
   \   00000020   4F1F               SBCI    R17, 255
   \   00000022   8300               ST      Z, R16
   \   00000024   8311               STD     Z+1, R17
   \                     ??main_0:
   \   00000026   91A0....           LDS     R26, P_Ram
   \   0000002A   91B0....           LDS     R27, (P_Ram + 1)
   \   0000002E   91ED               LD      R30, X+
   \   00000030   91FC               LD      R31, X
   \   00000032   973A               SBIW    R31:R30, 10
   \   00000034   F374               BRLT    ??main_1

 

 

     26            while (var<20)
   \                     ??main_2:
   \   00000036   91E0....           LDS     R30, var
   \   0000003A   91F0....           LDS     R31, (var + 1)
   \   0000003E   9774               SBIW    R31:R30, 20
   \   00000040   F44C               BRGE    ??main_3
     27                  ++var;
   \   00000042   ....               LDI     R30, LOW(var)
   \   00000044   ....               LDI     R31, (var) >> 8
   \   00000046   8100               LD      R16, Z
   \   00000048   8111               LDD     R17, Z+1
   \   0000004A   5F0F               SUBI    R16, 255
   \   0000004C   4F1F               SBCI    R17, 255
   \   0000004E   8300               ST      Z, R16
   \   00000050   8311               STD     Z+1, R17
   \   00000052   CFF1               RJMP    ??main_2

 

So when it's useful to use pointer?

 

Best Regards

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is always wiser to just write in the HLL.

Make sure that you get the syntax correct and understand it completely.

 

Incrementing a variable is far better done in straightforward statement e.g.

     uint8_t var8;
     int16_t var16;
     
     ...
     var8++;
     var16++;
     ...
     

There is no advantage in using pointers for simple operations.    

However,   if you have complex structures with many instances that you need to do different operations on.

 

You pass the address of the struct to the function.    The function performs the operation(s).

 

Look at the C libraries.   especially <string.h>.     Most things are done with string pointers e.g. char*

 

 

IMHO,    life gets complicated when you start reading ASM disassemblies.    Cliff and I disagree !!!

 

David.

Last Edited: Mon. Nov 3, 2014 - 11:34 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

some where i read when u want to call function it is better pass pointer instead of variable .

I don't know when "better" comes into it. The decision you have to make is whether it is better to pass by value or by reference. You generally choose to pass by value when you just need numeric values passed into a routine. You pass by reference when you both want to pass something in but also have the opportunity to update the source. Often you'll do it when you want to return more than one result. So a simple pass by value might be:

int add(int a, int b) {
    return a + b;
}

int main(void) {
    PORTB = add(3, 4);
}

That sets the output to 7. A pass by reference example might be:

void div_remainder(int a, int b, int * dividend, int * remainder) {
    *dividend = a / b;
    *remiander = a % b;
}

int main(void) {
    int div, rem;
    div_remainder(17, 4, &div, &rem);
    PORTB = div;
    PORTD = rem;
}

That needs the address of "div" and "rem" passed in so that they can both be updated.

 

It's anyone's guess which is "better". As I say it's simply the case of picking the most appropriate (value or reference).

 

If you google "parameter by value by reference" you hit other links such as:

 

http://courses.washington.edu/cs...

http://www.cplusplus.com/article...

etc.

 

which may make a better job of explaining when to use one or the other.

Cliff and I disagree !!!

Actually on this occasion I'm in 100% agreement with David. This has nothing to do with the generated assembler. It's a high level choice - you use value when all you need are values. You use reference when you need references (pointers). The choice has nothing to do with the code generated (in each case one would hope the compiler will make its best endeavours to generate the "right" code for the chosen mechanism). You'll learn more by reading a good book on C programming (or at least doing the Google I suggested) than by examining your own navel fluff (the asm!).

Last Edited: Mon. Nov 3, 2014 - 12:27 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
There is no advantage in using pointers for simple operations.

It's not a matter of whether the operation is "simple" or not - it's whether you want to be able to see changes outside the function or not!

 

But there are some things in 'C' where you have no other choice - like arrays.

 

Passing a large struct by value may not be a good idea if the compiler does that by copying the contents to the stack...

   

But, as already noted, this is all standard 'C' stuff - should be covered in a decent textbook.

To add to the suggestions already given: http://blog.antronics.co.uk/2011/08/08/so-youre-thinking-of-starting-with-c/

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Rubbish.    You can alter objects by function or by dereferencing addresses.    Or by straightforward regular assignment statements.

 

I still reckon that you should look at the 'scene' from a HLL point of view.

 

Choose the method and style that is clearest to you.

Then let the Compiler get on with doing its work.

 

If you dive into ASM code,    you end up obscuring things.

 

Yes,    if you are unsure of 'how' to do something,   just ask the question here.    Preferably with a real situation as an example.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
Rubbish.  

Where?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

 

david.prentice wrote:

Rubbish.  

 

Where?

 

It's not a matter of whether the operation is "simple" or not - it's whether you want to be able to see changes outside the function or not!

Sorry.     Perhaps I was being pedantic.     Most people don't go around dereferencing pointers.  

 

Most embedded programs have global data.    So you can access a struct via regular dot syntax.     And the compiler will use absolute addressing.

But I still don't think that the low-level details are helpful.

 

Any regular C textbook will explain the difference between pass by value and pass by reference.     And give you plenty of example exercises.

If anything,    you should concentrate on the HLL operation.      (especially when a Compiler might choose to implement your code legally but not how you expect)

 

David.

Last Edited: Mon. Nov 3, 2014 - 02:25 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

  Most people don't go around dereferencing pointers.  

I may be a bear of very little brain but now I'm confused. If people don't dereference pointers what exactly do they do with them?!?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I guess that you would write:

 

uint8_t foo;
...
foo++;

rather than

uint8_t foo;
...
*((uint8_t*)(&foo))++;

but it would be perfectly legal.

 

Likewise,    you would say:

   struct bar_struct {
       uint16_t one;
       uint32_t two;
   } bar;
   
   ...
   bar.two++;
   ...
   // or even:
   
   struct bar_struct *p = &bar;
   ...
   p->two++;
   ...
   

In other words,   you would use simple straightforward statements that simple mortals can maintain.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But David, what do your examples have to do with functions, particularly with the decision to pass by value or pass by pointer?

 

For me, the reason to pass by pointer in the OP's first example was totally negated by passing the result back as the return value. If I were to pass by pointer in that situation, my function would be this:

void Increment(int *pVar)
{
    (*pVar)++;
    PORTB = *pVar;
}

Of course, the OP's second example shows no sign of a function either, so it is unclear as to whether or not is is helpful or even desired.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

 

It's not a matter of whether the operation is "simple" or not - it's whether you want to be able to see changes outside the function or not!

 

Sorry.     Perhaps I was being pedantic.     Most people don't go around dereferencing pointers.  

 

Most embedded programs have global data.    So you can access a struct via regular dot syntax.     And the compiler will use absolute addressing.

But I still don't think that the low-level details are helpful.

 

....

 

biting my lip .....

 

Good software does NOT have global data, Firmware included. Global data is an antipattern.

 

 

All pointers will be dereferenced unless they are not used in which case they don't exist.

 

Use pointers where you need them;

* passing nontrivial data objects is one good reason.

* Passing data you want to modify is another

 

Passing a simple object through a pointer is a known expensive operation if you're not modifying the object.

i.e. passing a uint8 uses a 16 bit ( or bigger) pointer ( usually) so it's more expensive.

 

bottom line, use pointers when you need them and not if you don't :)

 

Stay out of the assembler IMHO, you don't care.

Just think, like said above, in the HLL untill you absolutely have to go into the assem.

I can't remember the last time I've looked at the compiler output, it's just not a good use of time

Keith Vasilakes

Firmware engineer

Minnesota

Last Edited: Mon. Nov 3, 2014 - 05:50 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My understanding of the OP's question was:

 

"When is using a pointer useful?"

 

So using Increment() function is fairly pointless when you could just write :

int foo;

...
foo++;                //looks straightforward to me
PORTB = foo;
...
Increment(&foo);      //does exactly the same
...

Now if the Increment() function was 20 lines long,    I would see a lot of sense in using a function rather than reams of inline statements.

From a readability point of view,   Lengthy_function_that_does_several_things(&foo) is preferable to lots of pages.

From an efficiency point of view,   you might ask the Compiler to Optimise for speed.    In which case it might unroll the function.

 

In other words,   let the Compiler take the strain.

 

Of course there are many occasions when you want to pass by reference but NOT change the object.    e.g. you pass a pointer and the function makes a local copy of the object.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:

My understanding of the OP's question was:

 

"When is using a pointer useful?"

Yes, that was how he titled his post - but what he actually asked was:

 

Quote:
some where i read when u want to call function it is better pass pointer instead of variable

 

Which is specifically about passing stuff (ie, parameters) to functions.

 

So that was what my reply was about.

 

But I agree that the thread title and the body question are inconsistent - so who knows what he really meant??

 

Maybe he will come back and clarify...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Mon. Nov 3, 2014 - 08:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for all replies

It is always wiser to just write in the HLL.

Make sure that you get the syntax correct and understand it completely.

what Do u mean "always wiser "?

So What dose mean more efficient code ?

your C code is not running on microcontroller  .is it ?

 

This has nothing to do with the generated assembler. It's a high level choice - you use value when all you need are values. You use reference when you need references (pointers)

yes but it effects the assembler .something that is suppose to run.

 

 

You'll learn more by reading a good book on C programming (or at least doing the Google I suggested) than by examining your own navel fluff (the asm!). 

agree 

 

But there are some things in 'C' where you have no other choice - like arrays.

Passing a large struct by value may not be a good idea if the compiler does that by copying the contents to the stack...

So some times we have done it because of efficiency ?

 

 

generally i don't look at compiler out put .

but sometimes i chose special object to improve it in my future code .

and if i don't look at compiler output  .how can i relies that my way in wrong ?

 

but those link are really useful .

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

'Always wiser' is obviously a generalisation.

 

Straightforward simple C code will generally produce very efficient ASM code.    The C Compiler can generate what it sees best.

Yes,   the C compiler will get everything correct.   (if you obey the syntax rules).     So there is little need to question the accuracy of the translation.

 

Efficiency means 'least number of cycles' and sometimes 'small amount of flash memory'.

 

Another rule of thumb:  "if it looks simple,  elegant and easy to read,   then it will work well"

 

I always think of K&R.    They have excellent writing and elegant code examples.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

yes but it effects the assembler .something that is suppose to run.

Of course it changes the assembler. But that has very little to do with it. The point(sic) is that you use a pointer when you need to use a pointer and don't when you don't. This has nothing to do with the Asm generated - that's just a consequence of what you chose as the most appropriate solution for getting access to the data values.

 

(but I still don't agree with David/Keith - examining assembler IS sometimes justified - then again I did 15-20 years of Asm before I ever looked at C so it's quite difficult to get out of that mindset! It's probably also why I'd still be more tempted than Keith to use globals. C++ that I battle with these days makes my head explode!)

Last Edited: Tue. Nov 4, 2014 - 10:49 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Moderation in all things. -- ancient proverb

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If there are many parameters, which I have to pass to a function, I prefer using a pointer, even when I do not want to modify the origin.

Instead of

uint8_t myFunction(uint8_t a, uint8_t b, uint16_t c, uint32_t d, ...)
{
    ...
    return a-b;
}

I prefer

typedef struct {
   uint8_t a;
   uint8_t b;
   uint16_t c;
   uint32_t d;
   ...
} myStruct_t;

uint8_t myFunction(const myStruct_t *myStruct)
{
    ...
    return myStruct->a - myStruct->b;
}

The risk of mixing-up parameters unintentionally (e.g. a with b), is minimized.

 

In the beginning was the Word, and the Word was with God, and the Word was God.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

skotti wrote:
The risk of mixing-up parameters unintentionally (e.g. a with b), is minimized.

But it's the use of a 'struct' which gives you that - it has nothing to do with using a pointer!

 

(you could pass the struct by value).

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There are basically 2 scenario's in which I would use a pointer.
1) you need to modify the data inside the function
2) the data is too large so that you don't want to copy it when passed to a function
Other than that, just use whichever is easier and/or makes the code look cleaner.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Another rule of thumb:  "if it looks simple,  elegant and easy to read,   then it will work well"

 

 

I wonder what Dostoyevsky's C would look like?

 

Would Freud anguish over a switch statement?