Variadic function: Difference between revisions

Content deleted Content added
m Replaced dash by slash (“1936/1937”)
No edit summary
 
(6 intermediate revisions by 5 users not shown)
Line 20:
 
===In C===
To portably implement variadic functions in the [[C (programming language)|C language]], the standard [[stdarg.h|{{code|stdarg.h}}]] header file is used. The older [[varargs.h|{{code|varargs.h}}]] header has been [[Deprecation|deprecated]] in favor of {{code|stdarg.h}}. In C++, the header file {{code|cstdarg}} is used.<ref>{{cite web|url=http://www.cplusplus.com/reference/clibrary/cstdarg/|title=<cstdarg> (stdarg.h) - C++ Reference|website=www.cplusplus.com|access-date=2007-10-02|archive-date=2012-10-31|archive-url=https://web.archive.org/web/20121031160547/http://www.cplusplus.com/reference/clibrary/cstdarg/|url-status=dead}}</ref>
 
<syntaxhighlight lang="C">
Line 28:
double average(int count, ...) {
va_list ap;
int j;
double sum = 0;
 
va_start(ap, count); /*/ Before C23: Requires the last fixed parameter (to get the address) */
for (int j = 0; j < count; j++j) {
sum += va_arg(ap, int); /* Increments ap to the next argument. */
}
Line 40 ⟶ 39:
}
 
int main(int argc, char* const *argv[]) {
printf("%f\n", average(3, 1, 2, 3));
return 0;
Line 86 ⟶ 85:
 
<syntaxhighlight lang="c++">
import std;
#include <iostream>
#include <cstdarg>
 
void simple_printf(const char* fmt...) // C-style "const char* fmt, ..." is also valid
void simple_printf(const char* fmt...) {
{
va_list args;
va_start(args, fmt);
Line 97 ⟶ 95:
if (*fmt == 'd') {
int i = va_arg(args, int);
std::cout <<println("{}", i << '\n');
} else if (*fmt == 'c') {
// note automatic conversion to integral type
int c = va_arg(args, int);
std::cout <<println("{}", static_cast<char>(c) << '\n');
} else if (*fmt == 'f') {
double d = va_arg(args, double);
std::cout <<println("{}", d << '\n');
}
++fmt;
Line 112 ⟶ 110:
}
 
int main(int argc, char* argv[]) {
{
simple_printf("dcff", 3, 'a', 1.999, 42.5);
}
Line 121 ⟶ 118:
 
<syntaxhighlight lang="c++">
import std;
#include <iostream>
 
template <typename... Ts>
void foo_printfooPrint(Ts... args) {
((std::coutprint("{} <<", args << ' ')), ...);
{
((std::cout << args << ' '), ...);
}
 
int main(int argc, char* argv[]) {
foo_printfooPrint(1, 3.14f); // 1 3.14
{
foo_printfooPrint("Foo", 'b', true, nullptr); // Foo b true nullptr
std::cout << std::boolalpha;
foo_print(1, 3.14f); // 1 3.14
foo_print("Foo", 'b', true, nullptr); // Foo b true nullptr
}
</syntaxhighlight>
 
The [[CERT Coding Standards]] for C++ strongly prefers the use of [[variadic templates]] (parameter pack) in C++ over the C-style variadic function due to a lower risk of misuse.<ref>{{cite web |title=DCL50-CPP. Do not define a C-style variadic function |url=https://wiki.sei.cmu.edu/confluence/display/cplusplus/DCL50-CPP}}</ref>
 
=== In Fortran ===
Since the Fortran 90 revision, [[Fortran]] functions or subroutines can accept optional arguments:<ref>{{Cite web |title=Optional Arguments |url=https://www.intel.com/content/www/us/en/docs/fortran-compiler/developer-guide-reference/2023-0/optional-arguments.html |access-date=2025-03-18 |website=Intel |language=en}}</ref> the argument list is still fixed, but the ones that have the {{code|optional}} attribute can be omitted in the function/subroutine call. The intrinsic function {{code|present()}} can be used to detect the presence of an optional argument. The optional arguments can appear anywhere in the argument list.
 
<syntaxhighlight lang="fortran">program test
implicit none
 
real :: x
!> all arguments are passed:
call foo( 1, 2, 3.0, 4, x )
!< outputs 1 \ 2 \ 3.0 \ 4 \ 6.0 (the "\" denotes a newline)
!> the last 2 arguments are omitted:
call foo( 1, 2), #3.0 ()
!< outputs 1 \ 2 \ 3.0
!> the 2nd and 4th arguments are omitted: the arguments that are positioned after
!> an omitted argument must be passed with a keyword:
call foo( 1, c=3.0, e=x )
!< outputs 1 \ 3.0 \ 6.0
!> alternatively, the Fortran 2023 revision has introduced the .NIL. pseudo constant
!> to denote an omitted argument
call foo( 1, .NIL., 3.0, .NIL., x )
!< outputs 1 \ 3.0 \ 6.0
 
contains
 
!> the subroutine foo() has 2 mandatory and 3 optional arguments
subroutine foo( a, b, c, d, e )
integer, intent(in) :: a
integer, intent(in), optional :: b
real, intent(in) :: c
integer, intent(in), optional :: d
real, intent(out), optional :: e
int j;
print*, a
if (present(b)) print*, b
print*, c
if (present(d)) print*, d
if (present(e)) then
e = 2*c
print*, c
end if
end subroutine
 
end program</syntaxhighlight>
 
'''Output:'''
 
<pre>
The sum of [1 2] is 3
The sum of [1 2 3] is 6
The sum of [1 2 3 4] is 10
</pre>
 
===In Go===
Line 187 ⟶ 237:
// variable-length array of `String`s.
private static void printArgs(String... strings) {
for (String strings : strings) {
System.out.println(strings);
}
}
Line 297 ⟶ 347:
 
<syntaxhighlight lang="python">
from typing import Any
def foo(a, b, *args):
 
def foo(a: Any, b: Any, *args: Any) -> None:
print(args) # args is a tuple (immutable sequence).
 
if __name__ == "__main__":
foo(1, 2) # ()
foo(1, 2, 3) # (3,)
foo(1, 2, 3, "hello") # (3, "hello")
foo(1, 2, 3, "hello") # (3, "hello")
</syntaxhighlight>
 
Keyword arguments can be stored in a dictionary, e.g. {{code|def bar(*args: Any, **kwargs: Any) -> Any}}.
 
===In Raku===
Line 370 ⟶ 423:
 
=== In Rust ===
[[Rust (programming language)|Rust]] does not support variadic arguments in functions. Instead, it uses [[Macro (computer science)|macros]], which support variadic arguments.<ref>{{cite web |title=Variadics |url=https://doc.rust-lang.org/rust-by-example/macros/variadics.html |website=Rust By Example}}</ref> This is essentially why <code>println!</code> is a macro and not a function, as it takes variadic arguments to format.
 
<syntaxhighlight lang="rust">
Line 390 ⟶ 443:
 
fn main() {
calculate! { // Look ma! Variadic `calculate!`!\
eval 1 + 2,
eval 3 + 4,