Author Topic: creating a function but not always using all the arguments  (Read 10575 times)

0 Members and 1 Guest are viewing this topic.

Offline Simon

  • Global Moderator
  • *****
  • Posts: 15946
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
creating a function but not always using all the arguments
« on: August 25, 2019, 11:20:27 am »
So if i write a function that has a number of input arguments but I don't use them all what happens? will they just be assumed as 0? i am sure i have seen this in Arduino library functions.
 

Offline oPossum

  • Super Contributor
  • ***
  • Posts: 1250
  • Country: us
  • The other white meat.
Re: creating a function but not always using all the arguments
« Reply #1 on: August 25, 2019, 11:26:34 am »
In C++ you indicate optional arguments by specifying default values.

For example...  int foo(int a, int b = 0, int c = 5, char * s = NULL);

The first argument has no default, so it is required. The others are optional. You can not skip an optional argument.

foo(1, , 3, "test");  <-- skip not allowed

foo(); <-- required argument missing

foo(1, 2);  <-- OK
 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 15946
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: creating a function but not always using all the arguments
« Reply #2 on: August 25, 2019, 11:29:05 am »
So does this work in C?
 

Offline MosherIV

  • Super Contributor
  • ***
  • Posts: 1528
  • Country: gb
Re: creating a function but not always using all the arguments
« Reply #3 on: August 25, 2019, 11:33:25 am »
Arguments are passed by value, that is a copy is taken and put on the stack. The function then takes the value from the stack.
Nothing will happen if you do not use the value.
The compiler may warn you that you have not used a variable.

Since variables are passed as copies, you cannot change input parameters from inside functions.
Instead, you have to pass in by reference. In other words, pointers.

Edit: no, C does not support default parameter values.

Both C and C++ support parameter specifiers 'const' which tells the compiler that the copy of variable on the stack cannot be changed.
« Last Edit: August 25, 2019, 11:40:56 am by MosherIV »
 

Offline oPossum

  • Super Contributor
  • ***
  • Posts: 1250
  • Country: us
  • The other white meat.
Re: creating a function but not always using all the arguments
« Reply #4 on: August 25, 2019, 11:45:41 am »
C does supports varargs, but you get no compile time sanity checking, and no defaults without some extra work.

printf() is an example of a function that uses varargs

https://en.wikipedia.org/wiki/Variadic_function
 

Online RoGeorge

  • Super Contributor
  • ***
  • Posts: 3177
  • Country: ro
Re: creating a function but not always using all the arguments
« Reply #5 on: August 25, 2019, 11:51:52 am »
Optional arguments may or may not be possible, depending on the language and the function definition.  Same for arguments sent by value or by reference.  In some languages the default is to send arguments by value, in other languages the default is to send them by reference.

For C++ it is possible to have optional arguments, not so much for C.
https://stackoverflow.com/questions/27795767/optional-arguments-in-c-function

Arduino is a mixture of C and C++ libraries.

Note:  statistics show OP beginning with the conclusive word "so" have a 69% less chance to be read.   :)

Offline Simon

  • Global Moderator
  • *****
  • Posts: 15946
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: creating a function but not always using all the arguments
« Reply #6 on: August 25, 2019, 12:06:26 pm »


Note:  statistics show OP beginning with the conclusive word "so" have a 69% less chance to be read.   :)

And 50% of statistics are made up  ;D

"So" I am confused now as i seem to interpret people saying yes and no to the same question. The context is that i am wrining for the ARM GCC compiler which i beleive is C?

As i have the posibilitfy of setting up several pins on one register write and thus save a lot of repetition of code (that may or may not be optimised out) i aim to write a function that has as arguments the setup parameters followed by the pins that it has to affect. So I can just put the string in of bits that will go straight into the 16 bits of the register or i can specify the pins one at a time. But i will hardly ever setup all 16 so many of the arguments would remain blank.
 

Offline donotdespisethesnake

  • Super Contributor
  • ***
  • Posts: 1091
  • Country: gb
  • Embedded stuff
Re: creating a function but not always using all the arguments
« Reply #7 on: August 25, 2019, 12:11:42 pm »


Note:  statistics show OP beginning with the conclusive word "so" have a 69% less chance to be read.   :)


"So" I am confused now as i seem to interpret people saying yes and no to the same question.

Some people misinterpreted the question. I think you asked "what if I don't pass all the parameters?" (Answer: a compiler error).

Of course, if you pass parameters that are not used, the answer is largely irrelevant, so I'm not sure why people answered that.

You may also have seen overloaded functions in C++, which are not available in C.
Bob
"All you said is just a bunch of opinions."
 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 15946
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: creating a function but not always using all the arguments
« Reply #8 on: August 25, 2019, 12:15:53 pm »

Some people misinterpreted the question. I think you asked "what if I don't pass all the parameters?" (Answer: a compiler error).


Thankyou, i will have to look at how i acheive what i want then. I suppose I can build up my mask as a seperate operation and then pass it to the function.
 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 15946
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: creating a function but not always using all the arguments
« Reply #9 on: August 25, 2019, 12:18:31 pm »
On the other hand when I create a new project it asks if i want o create a new C/C++ project for AVR/ARM. but then i am still learning C never mind C++
 

Offline oPossum

  • Super Contributor
  • ***
  • Posts: 1250
  • Country: us
  • The other white meat.
Re: creating a function but not always using all the arguments
« Reply #10 on: August 25, 2019, 12:26:42 pm »
Some people misinterpreted the question. I think you asked "what if I don't pass all the parameters?" (Answer: a compiler error).

There will not be an error if the function has default arguments. (C++ only)

There will not be an error if it is a variadic function (C and C++)
 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 15946
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: creating a function but not always using all the arguments
« Reply #11 on: August 25, 2019, 12:28:09 pm »
variadic ?
 

Offline rhodges

  • Regular Contributor
  • *
  • Posts: 244
  • Country: us
  • Available for embedded projects.
    • My public libraries, code samples, and projects for STM8.
Re: creating a function but not always using all the arguments
« Reply #12 on: August 25, 2019, 12:31:10 pm »
I suppose I can build up my mask as a seperate operation and then pass it to the function.
That is probably a good option. Consider something like this:
Code: [Select]
#define OPTION_A 0x01 /* one bit */
#define OPTION_B 0x02
#define OPTION_C 0x04
#define OPTION_X 0x10 /* two bits */
#define OPTION_Y 0x20 /* two bits */
#define OPTION_Z 0x30 /* two bits */

something_init(OPTION_A | OPTION_C | OPTION_Y);
Currently developing STM8 and STM32. Past includes 6809, Z80, 8086, PIC, MIPS, PNX1302, and some 8748 and 6805. Check out my public code on github. https://github.com/unfrozen
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 21451
  • Country: nl
    • NCT Developments
Re: creating a function but not always using all the arguments
« Reply #13 on: August 25, 2019, 12:37:55 pm »
So does this work in C?
No. Only in C++.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 

Offline oPossum

  • Super Contributor
  • ***
  • Posts: 1250
  • Country: us
  • The other white meat.
Re: creating a function but not always using all the arguments
« Reply #14 on: August 25, 2019, 12:41:40 pm »
 

Online cv007

  • Frequent Contributor
  • **
  • Posts: 616
Re: creating a function but not always using all the arguments
« Reply #15 on: August 25, 2019, 12:43:50 pm »
>As i have the posibilitfy of setting up several pins on one register write and thus save a lot of repetition of code

Your solution may be worse- in size or usage, than just dealing with one pin at a time. Let's say you have 20 pins to deal with- in the big picture, this will result in code you may still have to get the magnifying glass out to find. If you can work out a way to 'combine' the register writes, you gain very little but now you have to figure out which pins belong to which ports, what their port settings will be such as pullup, input, output, etc. Keep it simple, deal with 1 pin at a time.

simple C example to setup in/out for a pin-
https://godbolt.org/z/EPZcAD

now do 20 of them, not a big deal.

 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 15946
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: creating a function but not always using all the arguments
« Reply #16 on: August 25, 2019, 01:01:08 pm »
Not really. If i write code to set up each pin i will be writing the same code ove and over with some change in the numbers. but with one of the registers i can send the same configuration to 16 pins at a time if needed. Granted I will end up using it over and over as i can only send one configuration at a time.

using bit shifts and andding multiple ones together can all be done in passing the argument and will be optimized out in the compiler as the final mask..

So now i have the fun of working out what they called the registers and pondering again the wisdom of just addressing the memory space directly, I note for example that SAMc and SAMd have the same addresses for same registers so it would still be portable.
 

Online cv007

  • Frequent Contributor
  • **
  • Posts: 616
Re: creating a function but not always using all the arguments
« Reply #17 on: August 25, 2019, 01:25:03 pm »
here is a very simple incomplete version of C++ templates-
https://godbolt.org/z/I-JA_0

>If i write code to set up each pin i will be writing the same code ove and over with some change in the numbers. but with one of the registers i can send the same configuration to 16 pins at a time if needed

How do you imagine your function call will look like? Start with what you want your code to look like, and work back from there.

this is what it appears you want to do (multiple optional arguments, which will end up being a macro of some kind)-
pin_outputs( PA02, PA05, PA15, PA20);
pin_inputs( PA03, PA07, PA11, PA25);

You are not using a pic10 with 256 bytes of flash. There are bigger battles to fight, and worrying about combining register writes is not worth your time, but you can certainly give it a go.
 

Offline MosherIV

  • Super Contributor
  • ***
  • Posts: 1528
  • Country: gb
Re: creating a function but not always using all the arguments
« Reply #18 on: August 25, 2019, 01:39:25 pm »
Hi

One trick which I did not understand when I first started, is to create a struct with the regsiter set that you are trying to control.
Create 1 instance of the struct for each set of registers that you want to control.
You have to somehow point the struct to the address of the registers.

Then, all you have to do is to change the register in the struct of the instance that you are interrested in.
Your function then just takes the struct and writes the whole lot.

I first saw this for initialising UARTs.
So you could initialise multiple UARTs with the same struct but pointing to UARTs at different register adresses.
Hope that makes sense.
I did not like it when I first saw this but now I understand and appreciate this technique.
 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 15946
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: creating a function but not always using all the arguments
« Reply #19 on: August 25, 2019, 01:57:15 pm »
Hi

One trick which I did not understand when I first started, is to create a struct with the regsiter set that you are trying to control.
Create 1 instance of the struct for each set of registers that you want to control.
You have to somehow point the struct to the address of the registers.

Then, all you have to do is to change the register in the struct of the instance that you are interrested in.
Your function then just takes the struct and writes the whole lot.

I first saw this for initialising UARTs.
So you could initialise multiple UARTs with the same struct but pointing to UARTs at different register adresses.
Hope that makes sense.
I did not like it when I first saw this but now I understand and appreciate this technique.

i need to remind myself what structs are/how they work. The problem i have with the supplied headers is that they are geared up for their own ASF or IAR systems. I am now at a paint where I don't see the point inconforming to their "standards" if tht does not work for me.

The other way of doing it is to pass the part name as a parameter/argumunt to the function, that "text" will simply be a define that is replaced by the base address ofthe port, so i can define each offset once and easily add them together in other defines so that I am not writing out every address and i have some chance of porting to another SAM device by just changing a fex offset definitions.
 

Offline radiolistener

  • Super Contributor
  • ***
  • Posts: 1845
  • Country: ua
Re: creating a function but not always using all the arguments
« Reply #20 on: August 25, 2019, 02:07:49 pm »
to write a function that has as arguments the setup parameters followed by the pins that it has to affect. So I can just put the string in of bits that will go straight into the 16 bits of the register or i can specify the pins one at a time. But i will hardly ever setup all 16 so many of the arguments would remain blank.

I don't recommend to use a lot of arguments in the function, it's better to use struct and pass pointer to this struct.

Regarding to pins and bit manipulation, it's better to define clear named constants with masks and values and combine it with | and & operations instead of passing each bit separately. It will be much easier to support such code. Because when you will use a lot of variables for bits and pins it will turns into nightmare  :)
 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 15946
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: creating a function but not always using all the arguments
« Reply #21 on: August 25, 2019, 02:12:44 pm »
Yes which is why i would pass one argument that is the final bit mask. That bit mask can be made up ad hoc in the function call. The compiler will work out the mask and put it into the program leaving out all the visible calculations. But with them being visible I can easily see what i wrote. I don't like just sending hex numbers to registers as it is not clear what is happening. You can use binary but at 8 digits that is hard work to easily identify which bit is which. Unfortunately you can't put spaces into long binary numbers. at 32 bits it just becomes silly.
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 7158
  • Country: fr
Re: creating a function but not always using all the arguments
« Reply #22 on: August 25, 2019, 02:21:20 pm »
For C, the struct "trick" would be the way to go indeed IMO. (It's not a trick!)
I don't recommend using variadic functions for that. Would be cumbersome and error-prone, especially if you have several parameters of different types.

You can either reuse the same struct variable for subsequent calls, just modifying the fields you want modified (if the other fields are to retain their previous value), or if you want all the fields that are not explicitly set to be zeroed-out, you can use the C99 syntax (compound literals). Short example:

Code: [Select]
#include <stdio.h>
#include <stdint.h>

typedef struct
{
uint32_t n;
uint8_t m;
double x;
char s[32];

} MyParams_t;

static void MyFunction(MyParams_t *pParams)
{
if (pParams == NULL)
return;

printf("n = %u, m = %u, x = %g, s = '%s'\n", pParams->n, pParams->m, pParams->x, pParams->s);
}

int main(void)
{
MyParams_t Parameters;

// Initial values.
Parameters = (MyParams_t){ .n = 1, .x = 0.5 };

MyFunction(&Parameters);

// Only change selected fields.
Parameters.m = 2;
Parameters.x = -0.5;

MyFunction(&Parameters);

// Only set selected fields, the others will be zeroed-out.
Parameters = (MyParams_t){ .s = "Test" };

MyFunction(&Parameters);

return 0;
}

 

Offline sokoloff

  • Super Contributor
  • ***
  • Posts: 1490
  • Country: us
Re: creating a function but not always using all the arguments
« Reply #23 on: August 25, 2019, 02:30:30 pm »
Yes which is why i would pass one argument that is the final bit mask. That bit mask can be made up ad hoc in the function call. The compiler will work out the mask and put it into the program leaving out all the visible calculations. But with them being visible I can easily see what i wrote. I don't like just sending hex numbers to registers as it is not clear what is happening. You can use binary but at 8 digits that is hard work to easily identify which bit is which. Unfortunately you can't put spaces into long binary numbers. at 32 bits it just becomes silly.
You could use a preprocessor macro if you wanted to break up a long binary number for the author and recombine it later.

If you're using gcc (in order to get support for 0bxxxxxxxx style binary literals), you can do something like this to break up your literals for reading:

Code: [Select]
#include <stdio.h>

#define BINARY_CONST(A, B) (0b ## A ## B)

int main(void) {
  int foo = BINARY_CONST(0101, 1111);
  printf("%s = 0x%x", "BINARY_CONST(0101, 1111)", foo);
  return 0;
}

You can also have a look at the BOOST_BINARY macro package.
 

Offline Simon

  • Global Moderator
  • *****
  • Posts: 15946
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: creating a function but not always using all the arguments
« Reply #24 on: August 25, 2019, 03:03:58 pm »
Code: [Select]
#ifndef PORTS_H_
 #define PORTS_H_

// architecture offsets
 #define PORTS_OS 0x41000000UL
 #define PORTS_OS_STEP 0x80

//port offsets
 #define PORTA_OS_STEP (0*PORTS_OS_STEP)
 #define PORTB_OS_STEP (1*PORTS_OS_STEP)
 #define PORTC_OS_STEP (2*PORTS_OS_STEP)

 #define PORTA_OS (PORTA_OS_STEP*PORTS_OS_STEP)
 #define PORTB_OS (PORTB_OS_STEP*PORTS_OS_STEP)
 #define PORTC_OS (PORTC_OS_STEP*PORTS_OS_STEP)

// ports base address
 #define PORTA (PORTS_OS+PORTA_OS)
 #define PORTB (PORTS_OS+PORTA_OS)
 #define PORTC (PORTS_OS+PORTA_OS)

// port register offset definitions
 #define DIR 0
 #define DIRCLR 0x04
 #define DIRSET 0x08
 #define DIRTGL 0x0C

 #define OUT 0x10
 #define OUTCLR 0x14
 #define OUTSET 0x18
 #define OUTTGL 0x1C

 #define IN 0x20

 #define CTRL 0x24
 #define WRCONFIG 0x28
 #define EVCTRL 0x2C

 #define PMUX_OS 0x30
 #define PMUX_OS_STEP 0x1

 #define PINCFG_OS 0x40
 #define PINCFG_OS_STEP 0x1

 #define REGISTER(A, B) (A + B)

 /* PORTS_H_ */
« Last Edit: August 25, 2019, 03:05:50 pm by Simon »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf