2

In C, when you declare a function without parameters, that function can accept any number of parameters. Example:

int sum() {
  // some code
}

int subs(void) {
  // some code
}

int main() {
    sum(1, 2, 3, 4, 5, 6); // This is valid
    subs(1, 2, 3, 4, 5, 6); // This is NOT valid
}

How to tell, in the first case(sum), if some parameters are provided?

Thanks in advance

Werem
  • 534
  • 2
  • 5
  • 16
  • 5
    You can't. There is no way in C for a function to count its arguments, or even detect if any were passed. That's why variadic functions, like `printf` for example, must use some other mechanism to know what arguments were passed into the call (in the case of `printf` that's the format string). – dxiv Jan 24 '21 at 00:09
  • 1
    Maybe you instead want a [variadic function](https://en.wikipedia.org/wiki/Variadic_function#In_C) (also https://xyproblem.info/) – costaparas Jan 24 '21 at 00:10
  • You ought declare a function with no arguments as `(void)`, otherwise, it is implementation specified. – sgtcortez Jan 24 '21 at 00:11

3 Answers3

1

How to tell, in C, if parameters to a function are provided?

It's not possible. From C perspective there is no possibility to know if any arguments are provided to such function nor what their count is.

when you declare a function without parameters, that function can accept any number of parameters

Yes, when you declare a function without parameters. And it does not necessarily means the function accepts any number of parameters. In the code you presented:

int sum() {
  // some code
}

it's the sum function definition. In a definition, when the function has no parameters, then, well, the function really really has no parameters - it's as if int sum(void). It's from C11 6.7.6.3p14, emphasis mine:

An identifier list declares only the identifiers of the parameters of the function. An empty list in a function declarator that is part of a definition of that function specifies that the function has no parameters. The empty list in a function declarator that is not part of a definition of that function specifies that no information about the number or types of the parameters is supplied.

The code you presented is invalid - sum takes no parameters.

So:

sum(1, 2, 3, 4, 5, 6); // This is also NOT valid
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • thanks for your answer. Regarding what you said, the code I presented as valid, it compiles without warnings. How it can be invalid? version compiled with gcc ``` gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 ``` parameters: ``` -O0 -Wpedantic -g -Wall -std=c99 -g3 -DOS_$(DETTECTED_OS) ``` – Werem Jan 24 '21 at 11:38
  • https://stackoverflow.com/questions/12643202/why-does-gcc-allow-arguments-to-be-passed-to-a-function-defined-to-be-with-no-ar `I presented as valid, it compiles without` C is a magic language with undefined behavior. There is no requirement for a compiler to break compilation if the code is invalid. `with gcc` Gcc just don't cares - and just handles empty argument list by always ignoring arguments, even when it's a definition. I believe it's for supporting raw assembly code. Still, sorry, the code is not valid. – KamilCuk Jan 24 '21 at 11:49
1

As a workaround you can pass a reference to the array with types information and references to variables.

typedef enum
{
    CHAR_T,
    INT_T,
    FLOAT_T,
}TYPES_t;


typedef struct
{
    TYPES_t type;
    void *arg;
}ARG_t;



int foo(ARG_t *args)
{
    size_t argnum = 0;

    while(args -> arg)
    {
        printf("Parameter %zu has type pointer to ", argnum);
        switch(args -> type)
        {
            case CHAR_T:
                printf("char and value of the refenced object is %c\n", *(char *)args -> arg);
                break;
            case INT_T:
                printf("int and value of the refenced object is %d\n", *(int *)args -> arg);
                break;
            case FLOAT_T:
                printf("float and value of the refenced object is %f\n", *(float *)args -> arg);
                break;
        }
        args++;
    }
}


int main(void)
{
    int i = 1234;
    char c = 'c';
    float f = 9876.543;
    ARG_t args[10] = {{CHAR_T, &c}, {INT_T, &i}, {FLOAT_T, &f}, {0,}};

    foo(args);
}
0___________
  • 60,014
  • 4
  • 34
  • 74
0

The way you tell is to read the documentation for the function being called.

The caller is responsible for passing arguments that are acceptable to the function being called.

This is true not just for the number of parameters but for their values. For example, a function named SquareRoot might be specified to return the square root of a non-negative value it is passed but to have undefined behavior if a negative value is passed. In this case, the caller is responsible for passing a non-negative value.

So we see that declaring function parameters and having the compiler report errors in the numbers or types of arguments is just a part of the task of ensuring functions are called correctly.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312