Is there a limit

to the number of variables that can be passed to a user defined function, other than for the obvious (running out of) memory considerations?
I ask out of curiosity, not for any practical reason.

From the standard:

2 The limits may constrain quantities that include those described below or others. The bracketed number
following each quantity is recommended as the minimum for that quantity. However, these quantities are
only guidelines and do not determine compliance.

— Nesting levels of compound statements, iteration control structures, and selection control structures [256].
— Nesting levels of conditional inclusion [256].
— Pointer, array, and function declarators (in any combination) modifying a class, arithmetic, or incomplete
type in a declaration [256].
— Nesting levels of parenthesized expressions within a full-expression [256].
— Number of characters in an internal identifier or macro name [1 024].
— Number of characters in an external identifier [1 024].
— External identifiers in one translation unit [65 536].
— Identifiers with block scope declared in one block [1 024].
— Macro identifiers simultaneously defined in one translation unit [65 536].
[b]Parameters in one function definition [256].[/b]
[b]Arguments in one function call [256].[/b]
— Parameters in one macro definition [256].
— Arguments in one macro invocation [256].
— Characters in one logical source line [65 536].
— Characters in a string literal (after concatenation) [65 536].
— Size of an object [262 144].
— Nesting levels for #include files [256].
— Case labels for a switch statement (excluding those for any nested switch statements) [16 384].
— Data members in a single class [16 384].
— Enumeration constants in a single enumeration [4 096].
— Levels of nested class definitions in a single member-specification [256].
— Functions registered by atexit() [32].
— Functions registered by at_quick_exit() [32].
— Direct and indirect base classes [16 384].
— Direct base classes for a single class [1 024].
— Members declared in a single class [4 096].
— Final overriding virtual functions in a class, accessible or not [16 384].
— Direct and indirect virtual bases of a class [1 024].
— Static members of a class [1 024].
— Friend declarations in a class [4 096].
— Access control declarations in a class [4 096].
— Member initializers in a constructor definition [6 144].
— Scope qualifications of one identifier [256].
— Nested external specifications [1 024].
— Recursive constexpr function invocations [512].
— Full-expressions evaluated within a core constant expression [1 048 576].
— Template arguments in a template declaration [1 024].
— Recursively nested template instantiations, including substitution during template argument deduction
(14.8.2) [1 024].
— Handlers per try block [256].
— Throw specifications on a single function declaration [256].
— Number of placeholders (20.9.9.1.4) [10].

More fun is the var_args - va_arg - C++ Reference -

works on Arduino too

#include <stdarg.h>     /* va_list, va_start, va_arg, va_end */

int FindMax (int n, ...)
{
  int val, largest;
  va_list vl;
  va_start(vl, n);
  largest = va_arg(vl, int);
  for (int i = 1; i < n; i++)
  {
    val = va_arg(vl, int);
    largest = max(largest, val);
  }
  va_end(vl);
  return largest;
}

void setup()
{
  Serial.begin(115200);
  Serial.print("Start ");
  Serial.println(__FILE__);

  int m = FindMax(7, 702, 422, 631, 834, 892, 104, 772);
  Serial.print("The largest value is: ");
  Serial.println(m);
}

void loop()
{
}

I don't think Adruinos are to spec. You need to look at how much stack is consumed
for each function call. All the parameters are put onto a stack frame.
If you have a stack size of 64 bytes, you obviously can't send
128 bytes of parameters, as an example.
Unless you need to save the variables, it is more efficient to pass
a pointer to an array or a structure holding the values.
In a call, it has make a copy of the values into the stack frame for each
usage. It is not particularly efficient but it is the way C keeps things
straight so code writing is more transparent. For small programs, it makes
more sense to keep many variables
as globals but for safety, it is recommended to not use globals too much.
Dwight

dwightthinker:
I don't think Adruinos are to spec. You need to look at how much stack is consumed
for each function call. All the parameters are put onto a stack frame.
If you have a stack size of 64 bytes, you obviously can't send
128 bytes of parameters, as an example.
Unless you need to save the variables, it is more efficient to pass
a pointer to an array or a structure holding the values.
In a call, it has make a copy of the values into the stack frame for each
usage. It is not particularly efficient but it is the way C keeps things
straight so code writing is more transparent. For small programs, it makes
more sense to keep many variables
as globals but for safety, it is recommended to not use globals too much.
Dwight

Yeah, of course the limiting factor is the available memory. However the limits I posted are the minimum supported for a compliant (not strict standard) compiler. GCC which the IDE uses allows all of these minimums (and usually supports more, or has a flag which can be set allowing it).

However regardless of the Arduino's capability, things like constexpr functions, templates and other compile time based code, the compilers maximums can be reached even when writing for an Arduino.

pYro_65:
From the standard:
*-- *Parameters in one function definition [256].
*-- *Arguments in one function call [256].

Thanks pYro.
It seems obvious to me that those two limits have to be the same.

Henry_Best:
Thanks pYro.
It seems obvious to me that those two limits have to be the same.

It is quite, however the second one also applies to variable functions like what rob mentioned.

If you want to pass that many arguments, then one way of managing it is with a struct that holds the arguments. But if you are doing that - maybe what you really need is for your struct to have its own subfunctions. In other words - a class.

That is - long argument lists are a code smell that indicate that maybe your 'function' should be an object.

PaulMurrayCbr:
If you want to pass that many arguments, then one way of managing it is with a struct that holds the arguments. But if you are doing that - maybe what you really need is for your struct to have its own subfunctions. In other words - a class.

I don't. I was curious as to what the limit is for it's own sake, not for any practical purpose.
It's now a piece of fairly useless (to me) information lodged in my brain, probably to be forgotten in a few weeks time.

Henry_Best:
It's now a piece of fairly useless (to me) information lodged in my brain, probably to be forgotten in a few weeks time.

Hah! It will stay lodged forever, like a stubborn piece of celery string caught between the teeth. But, we all learned something useful.