函数原型 - 关闭参数检查

时间:2017-02-04 00:06:08

标签: c function function-prototypes

从K& R Book on C,我收集到如果函数原型声明省略了参数(如在int foo();中),则关闭类型和参数检查,并且没有任何关于与之兼容的参数的假设旧版本的C,因此它不会破坏遗留代码。

但是下面的代码抛出了原型不匹配的编译错误:

#include <stdio.h>
void test();
int main(void) {
    test(34.5f);
}

void test(float a) {
    printf("%f\n", a);
}

错误:

C:\***.c:7:6: error: conflicting types for 'test'
 void test(float a) {
      ^

有任何解释吗?

5 个答案:

答案 0 :(得分:5)

当多次声明一个函数时,所有声明都必须具有兼容类型(C11 6.2.7 / 2)。在您的代码中f被声明两次 - 该定义也算作声明。

&#34;兼容功能类型的定义&#34;在C11 6.7.6.3/15中:

  

要兼容两种功能类型,两者都应指定兼容的返回类型。此外,参数类型列表(如果两者都存在)应在参数的数量和省略号终止符的使用中一致;相应的参数应具有兼容的类型。如果一个类型具有参数类型列表而另一个类型由函数声明符指定,该函数声明符不是函数定义的一部分且包含空标识符列表,则参数列表不应具有省略号终止符且类型为每个参数应与应用默认参数促销产生的类型兼容。如果一个类型具有参数类型列表,另一个类型由包含(可能为空)标识符列表的函数定义指定两者都应在参数数量上达成一致,并且每个原型参数的类型应与从默认参数促销应用到相应标识符类型所产生的类型兼容。 (在确定类型兼容性和复合类型时,使用函数或数组类型声明的每个参数都被视为具有调整类型,并且使用限定类型声明的每个参数都被视为具有其声明类型的非限定版本。)

因此void test()void test(float)不兼容。换句话说,在看到void test();之后,任何原型都必须只使用默认参数提升未更改的类型。 <{1}}在这些促销活动中更改为float

我相信自第一个C标准以来一直如此。

答案 1 :(得分:1)

使用 public static Uri startChooseImage(Activity parent, String tag, String message, boolean useCamera, int requestId) { Uri uriImage = FileProvider.getUriForFile(parent, "com.dyt.fileprovider", new File( Environment.getExternalStorageDirectory() + File.separator + tag)); /* Uri uriImage = Uri.fromFile(new File( Environment.getExternalStorageDirectory() + File.separator + tag));*/ Intent selIntent = new Intent("android.intent.action.PICK").setType("image/*"); selIntent.setFlags(FLAG_GRANT_READ_URI_PERMISSION); selIntent.setFlags(FLAG_GRANT_WRITE_URI_PERMISSION); Intent chooserIntent = Intent.createChooser(selIntent, message); if (useCamera) { List<Intent> intentsList = new ArrayList(); Intent camIntent = new Intent("android.media.action.IMAGE_CAPTURE"); camIntent.setFlags(FLAG_GRANT_READ_URI_PERMISSION); camIntent.setFlags(FLAG_GRANT_WRITE_URI_PERMISSION); PackageManager pm = parent.getPackageManager(); List<ResolveInfo> listCam = pm.queryIntentActivities(camIntent, 0); for (ResolveInfo res : listCam) { Intent finalIntent = new Intent(camIntent); finalIntent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name)); finalIntent.putExtra("output", uriImage); intentsList.add(finalIntent); } chooserIntent.putExtra("android.intent.extra.INITIAL_INTENTS", (Parcelable[])intentsList.toArray(new Parcelable[intentsList.size()])); } parent.startActivityForResult(chooserIntent, requestId); return uriImage; } 类型的参数定义函数。

double

问题在于此次通话

void test(double a) {
    //...
}

使用默认参数promotion将参数转换为double类型。

答案 2 :(得分:1)

根据错误消息,具有默认促销的参数类型不能与空参数名称列表声明匹配。所以问题是float会被提升为int,这会导致与函数定义的float参数不匹配。

<强>声明:

void test();

它告诉编译器存在一个函数test,它没有参数而没有返回值。

<强>定义:

void test(float a)

它告诉编译器test()实际上是什么,并且也提供了声明。

答案 3 :(得分:0)

所以,最后从这里给出的所有答案和一点点阅读,这是我学到的东西(我把它作为一个答案发布,以便对将来可能会遇到这个问题的人有所帮助):

  • 当我调用test(23.4f)时 - 参数被自动“强制”为double并将被称为test(double),因为没有指定原型(对于参数,至少)
  • 由于我使用任何参数进行的任何调用都将转换为“默认促销”,因此我不能将函数声明为test(float),因为它永远不会被使用/调用。因此,test(double)有效,test(float)无效。

如果我错了,请纠正我,我会编辑我的答案。

答案 4 :(得分:-1)

您告诉gcc编译c11代码,而不是K&amp; R.

我查看了-std=个选项,但没有一个能够突出显示有用。也许完全省略语言标准参数会有所帮助。或者将其指定为c89

在c11中,总是需要完整形状的原型。因此,第一次使用将函数赋予参数= (void)。在pre-c ++中,这确实意味着&#34;可能会有或没有传递参数&#34;。