Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a parameter have type but no name?

I saw a question that got marked as a dupe, but one part of the question did not get answered by the dupe, and I did not find a suitable dupe to correct it. So here goes.

I once saw a declaration like this:

int (*function)(int, float);

I don't really understand it. It takes two arguments, but they have no name. How does that work? I mean, when declaring a function like this:

int f(int x, int y) {
    return x+y;
}

How would that even be possible without identifiers? I have noticed that this don't work and even gives a compiler error for the first line saying that

int f(int, int) {
    return /* What should I even write here? */ ;
}

I get two errors:

f.c:1:7: error: parameter name omitted
 int f(int, int)
       ^~~
f.c:1:7: error: parameter name omitted
 int f(int, int)
            ^~~
like image 352
klutt Avatar asked Jul 09 '19 23:07

klutt


2 Answers

It can easiest be explained with function prototypes. A function prototype declares a function but does not define it.

One purpose of prototypes is that it makes it possible with different compilation units. You put the prototypes in a header file and the definition in the source file. This makes it possible to compile an object file. When you then include the header file and link with the object file, you don't need to recompile the functions.

Another reason is that it allows for one-pass compilation. The compiler only needs to read the source once. Read more about it here: https://pediaa.com/what-is-the-difference-between-single-pass-and-multipass-compiler/

They are also useful if you for some reason want two functions to call each other. Consider this example:

void fun1(void) {
    fun2();
}

void fun2(void) {
    fun1();
}

Sure it would be an endless loop, but the point is that this would not compile. fun2 would compile, but when we come to fun1 we don't know that fun2 exists. The solution is to use function prototypes.

void fun2(void);

void fun1(void) {
    fun2();
}

void fun2(void) {
    fun1();
}

When you see that this is the purpose, it is quite obvious that function prototypes is just a declaration. It does not do anything. The declaration int f(float, char*); simply says that there exists a function with the name f. It returns an int, and it takes float and a char* as argument. So for your question, since it never do anything with the parameters, it does not need to have a name to reference them by. Only the definition does. That's why you can get the compiler error error: parameter name omittedthat you posted in the question:

Your example is not a function, but a function pointer. The same reason applies there. You can make a function pointer point at a function, but it is only the function definition that needs identifiers for the parameters. Read more about function pointers here

You can actually use different names for the parameters in the declaration and definition if you want. One potential use for this (I'm not saying if it is good or bad. Just showing that it's possible) is to use descriptive names for the variables in the prototype but shorter in the definition. This compiles well for example:

void backwards(const char *inputString, char *outputString);

void backwards(const char *is, char *os) {
    size_t l = strlen(is);
    for(size_t n=0; n<l; n++)
        os[l-n-1]=is[n];
    os[l]='\0';
}

One valid reason to to this is that the header file is usually used as an interface, so it makes sense to say that the identifiers have to be more descriptive there. Again, I'm just showing that it is possible and does not say that you should or should not do this.

While speaking of prototypes, it can be worth mentioning a fact many people don't know. The prototype void f(); does NOT declare a function taking no arguments. It declares a function taking an unspecified number of arguments. The correct way to declare a function taking no arguments is void f(void);. This can be important when it comes to function pointers. Look at this example that I copied from another answer I made:

$ cat main.c 
int foo() { return 0; }
int bar(int a) { return a; }

int main(void)
{
    int (*f)();
    f=foo;
    f=bar;
    int(*g)(void);
    g=foo;
    g=bar;
}

This generates this warning:

$ gcc main.c 
main.c: In function ‘main’:
main.c:11:3: warning: assignment to ‘int (*)(void)’ from incompatible pointer type ‘int (*)(int)’ [-Wincompatible-pointer-types]
  g=bar;
   ^

When it comes to regular function prototypes, you can skip the arguments completely if you wish. This compiles and runs just fine:

void foo();

int main() {
    foo(5,6);
}

void foo(int x, int y) {
    printf("The sum is: %d\n", x+y);
}

The above does not work in C++, as C++ does not support prototypes with unspecified arguments. In C++, void f(); is exactly the same thing as void f(void);. This is the reason why C cannot support function overloading while C++ can.

Lastly, one compiling example with the snippet you provided:

// Declaration of function pointer
int (*function)(int, float);
// Declaration of function
int foo(int, float);
// Definition of function
int foo(int x, float y) {
    return x;
}
// Assign the function pointer
function = foo;

TL;DR

You can basically declare a function prototype in two (excluding variadic functions) ways:

  1. <return type> <name>(); which declares a function with unspecified arguments, and will fit with any function definition with proper name and return type, irregardless of the arguments.
  2. <return type> <name>(<type> [<name>], <type> [<name>] ... ); which declare a function with specified argument types. The names are not mandatory, and can be different from those in the definition. The proper way of declaring a function with NO arguments is <return type> <name>(void);
like image 97
klutt Avatar answered Nov 19 '22 04:11

klutt


in function declaration/prototyping the parameter name is optional .Declaration must have parameters data type but identifier name is optional ...

like image 2
Sushil Gyawali Avatar answered Nov 19 '22 04:11

Sushil Gyawali