Discussion:
is it possible to have functions with 0, 1, or 2 args?
(too old to reply)
Mark Summerfield
2024-08-05 08:26:04 UTC
Permalink
Given

```
// vaargs.h
#pragma once

#define NARGS(...) NARGS_(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
#define NARGS_(_5, _4, _3, _2, _1, N, ...) N

#define CONC(A, B) CONC_(A, B)
#define CONC_(A, B) A##B

// va_test.h
#include "vaargs.h"

#define va_test(...) CONC(va_test, NARGS(__VA_ARGS__))(__VA_ARGS__)
int va_test0();
int va_test1(int);
int va_test2(int, int);

// va_test.c

#include "va_test.h"

int va_test0() { return va_test2(3, 11); }
int va_test1(int a) { return va_test2(3, a); }
int va_test2(int a, int b) { return a + b; }

// va_tests.c
#include "va_test.h"
#include <stdbool.h>
#include <stdio.h>

int main() {
int i = va_test();
if (i != 14) {
fprintf(stderr, "FAIL: va_test() expecte 14 go %d\n", i);
}
i = va_test(5);
if (i != 8) {
fprintf(stderr, "FAIL: va_test() expecte 8 go %d\n", i);
}
i = va_test(2, 9);
if (i != 11) {
fprintf(stderr, "FAIL: va_test() expecte 11 go %d\n", i);
}
}
```

This does *not* work for the `va_test()` call. But if I supply 1 or 2 args
it works great.

The rational is that I'd like to create a function `new_thing()` which
takes an optional size, e.g.,

```
thing new_thing0() { return new_thing1(10); }
// above uses default size of 10
thing new_thing1(int size) { ... }
```
Stefan Ram
2024-08-05 09:06:42 UTC
Permalink
Post by Mark Summerfield
The rational is that I'd like to create a function `new_thing()` which
takes an optional size, e.g.,
I'm hella stoked on writing code that's chill in C. So,
in a sitch like this, I might roll with a function that's
/always/ down to take an argument and just hit it with a
"-1" if I'm not trying to lock down a size.

The "va_list" jazz in C, courtesy of the <stdarg.h> header, lets
functions roll with a flexible number of args. It's like a buffet
line for arguments, where you can scoop them up one by one using
those gnarly macros "va_start", "va_arg", and "va_end".

But here's the rub - the function's not psychic, so it can't just
divine how many args are coming down the pike. You got to clue it in
somehow, like passing a head count or dropping a hint about where to
pump the brakes. The coder doesn't have to play bean counter though;
he could just slap a "Dead End" sign at the tail of the arg parade!

main.c

#include <stdio.h>
#include <stdarg.h>

int f( int const n, ... )
{ va_list args; /* to hold the variable arguments */
va_start( args, n ); /* Initialize the "va_list" variable with the */
int result; /* variable arguments, starting after n */
switch( n )
{ case 0: result = f( 2, 3, 11 ); break;
/* va_arg(args, int) retrieves the next argument from the "va_list"
of type "int" */
case 1: result = f( 2, 3, va_arg( args, int )); break;
case 2:
result = va_arg( args, int )+ va_arg( args, int ); break; }
va_end( args ); /* Clean up the "va_list" */
return result; }

int main( void )
{ printf
( "%d\n", 14 == f( 0 )&& 8 == f( 1, 5 )&& 11 == f( 2, 2, 9 )); }

transcript

1
Stefan Ram
2024-08-05 09:32:25 UTC
Permalink
Post by Mark Summerfield
This does *not* work for the `va_test()` call. But if I supply 1 or 2 args
it works great.
Here's an

SSCCE, a short self-contained correct compilable example, aka,
MWE - minimal working example.

Some coders whip up these examples themselves for their post!

It's a quick and dirty demo that can be compiled and run to
show what's buggin' them.

In this case, it's hella clear the macros are trippin', thinkin'
the number of args is "1" when it's actually zilch, nada, zero.

main.c

#include <stdio.h>

#define NARGS(...) NARGS_(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
#define NARGS_(_5, _4, _3, _2, _1, N, ...) N
#define va_test(...) NARGS(__VA_ARGS__)

int main( void ){ printf( "%d\n", va_test() ); }

transcript

1
Stefan Ram
2024-08-05 09:45:37 UTC
Permalink
Post by Mark Summerfield
#define NARGS(...) NARGS_(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
Up top, C's totally buggin' about the diff between one argument
and zilch, 'cause that comma in "__VA_ARGS__," is always chillin'
there. We could 86 it with the fresh "__VA_OPT__(,)", but not
all C implementations are down to clown with that yet . . .
Lawrence D'Oliveiro
2024-08-07 23:04:31 UTC
Permalink
Post by Mark Summerfield
#define NARGS(...) NARGS_(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
Up top, C's totally buggin' about the diff between one argument and
zilch, 'cause that comma in "__VA_ARGS__," is always chillin'
there. We could 86 it with the fresh "__VA_OPT__(,)", but not all C
implementations are down to clown with that yet . . .
Make sure to assume the B-Boy stance when you say that.
Tim Rentsch
2024-08-11 17:43:03 UTC
Permalink
Post by Stefan Ram
This does *not* work for the `va_test()` call. But if I supply 1 or 2 args
it works great.
Here's an
SSCCE, a short self-contained correct compilable example, aka,
MWE - minimal working example.
Some coders whip up these examples themselves for their post!
It's a quick and dirty demo that can be compiled and run to
show what's buggin' them.
In this case, it's hella clear the macros are trippin', thinkin'
the number of args is "1" when it's actually zilch, nada, zero.
main.c
#include <stdio.h>
#define NARGS(...) NARGS_(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
#define NARGS_(_5, _4, _3, _2, _1, N, ...) N
#define va_test(...) NARGS(__VA_ARGS__)
int main( void ){ printf( "%d\n", va_test() ); }
transcript
1
It appears you have missed the point of the question. What is being
sought is a way to distinguish between macro calls like va_test()
and macro calls like va_test(x). The above definition of va_test()
doesn't do that.
Michael S
2024-08-05 12:19:46 UTC
Permalink
On Mon, 05 Aug 2024 08:26:04 +0000
Mark Summerfield <***@qtrac.eu> wrote:

According to my understanding, vararg functions without arguments will
become possible in C23. But since fully functional C23 compilers do not
exist yet, right now the answer to your question is "No".
Tim Rentsch
2024-08-12 05:20:36 UTC
Permalink
Post by Michael S
On Mon, 05 Aug 2024 08:26:04 +0000
According to my understanding, vararg functions without arguments will
become possible in C23. But since fully functional C23 compilers do not
exist yet, right now the answer to your question is "No".
Even in C99 varargs functions can be called without arguments.
The question here is more subtle. In fact it is possible even
in C99 and C11 to do what he wants, but it isn't easy, and it
is far from obvious how to go about it. Still, if the question
is "can this be done?", the answer is Yes even now.
Richard Harnden
2024-08-12 08:33:25 UTC
Permalink
Post by Tim Rentsch
Post by Michael S
On Mon, 05 Aug 2024 08:26:04 +0000
According to my understanding, vararg functions without arguments will
become possible in C23. But since fully functional C23 compilers do not
exist yet, right now the answer to your question is "No".
Even in C99 varargs functions can be called without arguments.
The question here is more subtle. In fact it is possible even
in C99 and C11 to do what he wants, but it isn't easy, and it
is far from obvious how to go about it. Still, if the question
is "can this be done?", the answer is Yes even now.
How does va_start know where to, um, start from if there's no last named
argument?
Tim Rentsch
2024-08-12 09:28:24 UTC
Permalink
Post by Richard Harnden
Post by Tim Rentsch
Post by Michael S
On Mon, 05 Aug 2024 08:26:04 +0000
According to my understanding, vararg functions without arguments will
become possible in C23. But since fully functional C23 compilers do not
exist yet, right now the answer to your question is "No".
Even in C99 varargs functions can be called without arguments.
The question here is more subtle. In fact it is possible even
in C99 and C11 to do what he wants, but it isn't easy, and it
is far from obvious how to go about it. Still, if the question
is "can this be done?", the answer is Yes even now.
How does va_start know where to, um, start from if there's no last
named argument?
Sorry, I meant to say macros, not functions (using ... and __VA_ARGS__).
The original question is about macro definitions, not function
definitions, and I didn't read carefully enough.
Richard Harnden
2024-08-12 10:37:39 UTC
Permalink
Post by Tim Rentsch
Post by Richard Harnden
Post by Tim Rentsch
Post by Michael S
On Mon, 05 Aug 2024 08:26:04 +0000
According to my understanding, vararg functions without arguments will
become possible in C23. But since fully functional C23 compilers do not
exist yet, right now the answer to your question is "No".
Even in C99 varargs functions can be called without arguments.
The question here is more subtle. In fact it is possible even
in C99 and C11 to do what he wants, but it isn't easy, and it
is far from obvious how to go about it. Still, if the question
is "can this be done?", the answer is Yes even now.
How does va_start know where to, um, start from if there's no last
named argument?
Sorry, I meant to say macros, not functions (using ... and __VA_ARGS__).
The original question is about macro definitions, not function
definitions, and I didn't read carefully enough.
No worries.

So ... how can you do it with macros?

And, even if it's possible, is it a good idea?
Tim Rentsch
2024-08-12 22:39:10 UTC
Permalink
Post by Richard Harnden
Post by Tim Rentsch
Post by Richard Harnden
Post by Tim Rentsch
Post by Michael S
On Mon, 05 Aug 2024 08:26:04 +0000
According to my understanding, vararg functions without arguments will
become possible in C23. But since fully functional C23 compilers do not
exist yet, right now the answer to your question is "No".
Even in C99 varargs functions can be called without arguments.
The question here is more subtle. In fact it is possible even
in C99 and C11 to do what he wants, but it isn't easy, and it
is far from obvious how to go about it. Still, if the question
is "can this be done?", the answer is Yes even now.
How does va_start know where to, um, start from if there's no last
named argument?
Sorry, I meant to say macros, not functions (using ... and __VA_ARGS__).
The original question is about macro definitions, not function
definitions, and I didn't read carefully enough.
No worries.
So ... how can you do it with macros?
I'm still working on preparing an answer to that question.
Post by Richard Harnden
And, even if it's possible, is it a good idea?
An excellent question. I expect there are two schools of thought. :)
Stefan Ram
2024-08-05 14:04:45 UTC
Permalink
Subject: Re: is it possible to have functions with 0, 1, or 2 args?
FWIW, in math, there's no function that takes zero arguments.
But in something called "universal algebra", there's a thing
like that: so-called "operations of arity 0". (Basically, that's
just a fancy term for a constant.)
Blue-Maned_Hawk
2024-08-05 18:46:40 UTC
Permalink
Post by Mark Summerfield
The rational is that I'd like to create a function `new_thing()` which
takes an optional size, e.g.,
```
thing new_thing0() { return new_thing1(10); }
// above uses default size of 10 thing new_thing1(int size) { ... }
```
If i were you, i would have put the desired end result first in the
message and attempted solution afterwards, as i consider this to put the
most relevant information first. I'm also pretty sure that whatever
newsreader you're using is screwing up the line breaks in your message—i
would recommend seeking a fix for that wherever you find support for your
newsreader.

With that out of the way…

I question why you want a subroutine with “an optional size”. What does
it do when the size _isn't_ given? If it does something completely
different (e.g. creating only a partial object instead of a full object),
i would just have two separate subroutines, one sized and one not. If it
uses a default size, then i'd be worried about it causing problems in code
written to use it being difficult to read later on because it hides
information from the reader.

Nevertheless, if you're undeterred, i think that you're on the right track
with the macros that you've created. Luckily for you, it seems as though
this appears to be a wheel that has already been invented: the P99
preprocessor library seems to define some macros that can apparently be
used for such a thing: <https://gustedt.gitlabpages.inria.fr/p99/p99-
html/group__default__arguments.html>

As a side note, i don't know of a single newsreader that supports
interpretation of markdown syntax in messages.
--
Blue-Maned_Hawk│shortens to Hawk│/blu.mɛin.dʰak/│he/him/his/himself/Mr.
blue-maned_hawk.srht.site
Consistent except for all the inconsistencies!
Tim Rentsch
2024-08-12 05:15:52 UTC
Permalink
Post by Mark Summerfield
Given
```
// vaargs.h
#pragma once
#define NARGS(...) NARGS_(__VA_ARGS__, 5, 4, 3, 2, 1, 0)
#define NARGS_(_5, _4, _3, _2, _1, N, ...) N
#define CONC(A, B) CONC_(A, B)
#define CONC_(A, B) A##B
// va_test.h
#include "vaargs.h"
#define va_test(...) CONC(va_test, NARGS(__VA_ARGS__))(__VA_ARGS__)
int va_test0();
int va_test1(int);
int va_test2(int, int);
// va_test.c
#include "va_test.h"
int va_test0() { return va_test2(3, 11); }
int va_test1(int a) { return va_test2(3, a); }
int va_test2(int a, int b) { return a + b; }
// va_tests.c
#include "va_test.h"
#include <stdbool.h>
#include <stdio.h>
int main() {
int i = va_test();
if (i != 14) {
fprintf(stderr, "FAIL: va_test() expecte 14 go %d\n", i);
}
i = va_test(5);
if (i != 8) {
fprintf(stderr, "FAIL: va_test() expecte 8 go %d\n", i);
}
i = va_test(2, 9);
if (i != 11) {
fprintf(stderr, "FAIL: va_test() expecte 11 go %d\n", i);
}
}
```
This does *not* work for the `va_test()` call. But if I supply 1 or 2 args
it works great.
The rational is that I'd like to create a function `new_thing()` which
takes an optional size, e.g.,
```
thing new_thing0() { return new_thing1(10); }
// above uses default size of 10
thing new_thing1(int size) { ... }
```
The short answer is, it is possible, from C99 onwards, to define a
macro va_test(...) that does what you want. It isn't easy, but
it is possible.

If it's really important to define a macro that behaves like what
you describe, and you can't find a suitable workaround, feel free
to ask again and I can try to find and work through materials I
have somewhere, to give an explanation of how to do what you want.
Please note that I am making no guarantees about whether I can
accomplish that, only that I can try to do so.
Loading...