参数如何具有类型但没有名称? [英] How can a parameter have type but no name?

查看:96
本文介绍了参数如何具有类型但没有名称?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到一个被标记为欺骗的问题,但是该问题的一部分没有得到欺骗的回答,并且我没有找到合适的欺骗来纠正它.这样吧.

我曾经看到这样的声明:

int (*function)(int, float);

我不太了解.它有两个参数,但没有名称.这是如何运作的?我的意思是,在声明这样的函数时:

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

如果没有标识符怎么办?我注意到这行不通,甚至在第一行给出了

的编译器错误

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

我遇到两个错误:

f.c:1:7: error: parameter name omitted
 int f(int, int)
       ^~~
f.c:1:7: error: parameter name omitted
 int f(int, int)
            ^~~

解决方案

最容易用功能原型进行解释.函数原型声明一个函数,但不定义.

原型的一个目的是使使用不同的编译单元成为可能.您将原型放在头文件中,并将定义放在源文件中.这样就可以编译目标文件.然后,在包含头文件并与目标文件链接时,无需重新编译功能.

如果您出于某些原因希望两个函数相互调用,它们也很有用.考虑以下示例:

void fun1(void) {
    fun2();
}

void fun2(void) {
    fun1();
}

当然,这将是一个无休止的循环,但要点是,这将无法编译. fun2可以编译,但是当我们进入fun1时,我们不知道fun2存在.解决方案是使用函数原型.

void fun2(void);

void fun1(void) {
    fun2();
}

void fun2(void) {
    fun1();
}

当您看到这是目的时,很明显函数原型只是一个声明.它没有任何事情.声明int f(float, char*);仅表示存在名称为f的函数.它返回一个int,并以floatchar*作为参数.因此,对于您的问题,由于它永远不会对参数做任何事情,因此不需要使用名称来引用它们.只有定义可以.这就是为什么您可以获得在问题中发布的编译器错误error: parameter name omitted的原因:

您的示例不是函数,而是函数指针.同样的原因也适用于此.您可以将函数指针指向一个函数,但是只有函数定义需要参数标识符.在此处

了解更多有关函数指针的信息

如果需要,实际上可以为声明和定义中的参数使用不同的名称.一个潜在的用途(我不是说它是好是坏.只是表明它是可能的)是对原型中的变量使用描述性名称,但在定义中使用较短的名称.例如,这可以很好地编译:

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';
}

这样做的一个有效原因是头文件通常用作接口,因此可以说标识符必须在此处更具描述性.再一次,我只是表明这是可能的,而不是说您应该或不应该这样做.

在谈到原型时,值得一提的是许多人不知道的事实.原型void f();不声明不带参数的函数.它声明一个带有未指定数量的参数的函数.声明不带参数的函数的正确方法是void f(void);.对于函数指针,这可能很重要.看一下我从另一个答案中复制来的这个示例:

$ 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;
}

这会产生以下警告:

$ 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;
   ^

对于常规函数原型,如果需要,可以完全跳过参数.这样可以编译并正常运行:

void foo();

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

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

以上内容在C ++中不起作用,因为C ++不支持带有未指定参数的原型.在C ++中,void f();void f(void);完全相同.这就是为什么C无法支持C ++的函数重载的原因.

最后,一个包含您提供的代码片段的编译示例:

// 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

您基本上可以通过两种方式(不包括可变函数)声明函数原型:

  1. <return type> <name>();会声明带有 unspecified 参数的函数,并且将与具有正确名称和返回类型的任何函数定义匹配,而与参数无关.
  2. <return type> <name>(<type> [<name>], <type> [<name>] ... );声明具有指定的参数类型的函数.名称不是强制性的,可以与定义中的名称不同.声明不带参数的函数的正确方法是<return type> <name>(void);

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)
            ^~~

解决方案

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.

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);

这篇关于参数如何具有类型但没有名称?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆