C即使参数无效,功能也接受值

时间:2015-07-19 17:54:43

标签: c function

我是编程新手,我在定义函数之前阅读,我们需要定义它的原型。如果我们不希望我们的函数接受任何值,那么我们将void写为参数。所以只是为了检查它我编写了这个小程序,在定义函数原型的同时,我将它的参数写为void,而在编写它时,定义写了一个as作为它的参数(希望我能得到)一个错误,但我从来没有一个)。然后我编译并运行程序,它给了我这个输出

此程序打印从1到3的所有数字的平方

1的平方为1:

2的平方为4:

3的平方是9:

在此之后,我将定义中的参数更改为float a(仅检查程序是否仍然有效),这次我得到了不同的输出,如下所示

此程序打印从1到3的所有数字的平方

1的平方为0:

2的平方为0:

3的平方为0:

任何人都可以解释一下这里发生了什么吗?为什么我的编译器没有抛出错误以及为什么我为int和float获得两个完全不同的输出?我使用visual studio professional 2013和更新4!

//program to calulate square using functions 

#include <stdio.h>
#pragma warning (disable:4996)

int square(void);

int main()
{

    int i;

    printf("This program prints the square of all the numbers starting from 1 to 3");

    for (i = 1; i <= 3; i++)  
            printf("\n\nthe square of %d is %d : \t",i,square(i));

    getch();
    return 0;
}


square(a)
{

    a = a*a;
    return a;

}

1.program screenshot with int as parameter definition

2 个答案:

答案 0 :(得分:2)

旧C标准允许在没有参数的情况下声明函数,然后假设参数的类型为int。只要一切都匹配,一切正常,但如果事情不匹配,可能会发生有趣的事情。

这一切都归结为calling convention。调用代码将参数放在某处(通常是堆栈和寄存器),然后函数从某个地方获取它们,如果这是&#34;某处&#34;是一样的,数据类型匹配,一切正常。当他们不匹配时,你会得到不确定的行为。

所以int版本有效,因为一切都匹配。编译器警告您,它无法知道您的代码是否真的有用(或者在以后的C标准版本和C ++中给出实际错误),但这只是警告,这意味着您需要确保它和#39;没关系(你真的不想做,它是编译器的工作,所以启用警告并修复它们!)。

您提到的float版本是未定义的行为。计算机能够做的任何事情都可能发生(包括闯入您的银行账户并在下次使用网上银行时清空它,这基本上是很多恶意软件实际感染计算机,利用编程错误)。但是在这里你可能得零,因为浮点参数和返回值在FPU寄存器中传递,函数没有改变,因此返回值恰好为零。

答案 1 :(得分:0)

符合要求的C编译器必须在您的问题中为该程序发出至少一个诊断。

您的square函数宣布为

int square(void);

表示不接受任何参数并返回int结果。然后将其称为:

square(i)
传递一个参数的

。这是约束违规,这意味着编译器必须发出诊断(可能是警告或致命错误)。

然后定义为:

square(a) { /* ... */ }

这是一种旧式的定义。它表示square采用int参数并返回int结果(在过时的&#34;隐式int&#34;规则下)。但是这个定义在调用时是不可见的,因此编译器将仅使用声明来处理调用。

根据Microsoft's documentation,这个:

#pragma warning (disable:4996)

禁用&#34;已弃用&#34;的警告功能。它不应该适用于您的程序中的任何内容,因此您应该在错误的调用square(i)上收到警告或致命错误。

您的编译器是错误的,或者更有可能是您的问题中的代码或编译器行为的描述不正确。

请复制并粘贴您问题中的确切代码并尝试进行编译。如果它确实在没有警告或错误的情况下进行编译,那么您的编译器或您使用它的方式就会出现严重问题。

(当然声明,定义和对square的调用都应该是一致的,但你的问题是关于编译器没有诊断错误的原因,而不是如何在源代码中修复错误代码。)

至于为什么使用intfloat获得不同的输出,如果函数的声明和定义不一致,则任何调用都会导致未定义的行为。当您将定义更改为使用float时,生成的代码可能会传递int值,该值将函数错误地解释为float值。结果毫无意义。

更新:现在我已经看过您的屏幕截图,看起来您的编译器正在做一些我没想到的事情。它警告声明int square(void)有一个void参数列表。该声明本身就完全有效;它只是一个问题,因为以下定义使用square参数定义int。它必须决定警告之后声明它看到了不兼容的定义。

让我感到惊讶的是,它并没有对电话square(i)发出警告。该调用与定义(跟随它)一致,但与声明(在其之前)不一致。

C旨在一次性处理。构造的合法性取决于它之前的代码,而不是它后面的代码。

但是C标准强加的唯一要求是编译器必须至少发出一个诊断。它没有说明诊断的措辞,也不需要它是一个致命的错误。在这种情况下,代码违反了约束(因为square的声明和定义是不兼容的),并且在我看来应该拒绝该程序 - 但警告符合标准&# 39;要求。

无论编译器的作者做出什么决定,它确实会产生一些警告信息,你不应该忽略它们。它(可能间接地)指出了代码的问题,你应该解决这些问题。编译器警告您的代码的事实有时比警告的实际内容更具信息性。