我是编程新手,我在定义函数之前阅读,我们需要定义它的原型。如果我们不希望我们的函数接受任何值,那么我们将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;
}
答案 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
的调用都应该是一致的,但你的问题是关于编译器没有诊断错误的原因,而不是如何在源代码中修复错误代码。)
至于为什么使用int
与float
获得不同的输出,如果函数的声明和定义不一致,则任何调用都会导致未定义的行为。当您将定义更改为使用float
时,生成的代码可能会传递int
值,该值将函数错误地解释为float
值。结果毫无意义。
更新:现在我已经看过您的屏幕截图,看起来您的编译器正在做一些我没想到的事情。它警告声明int square(void)
有一个void参数列表。该声明本身就完全有效;它只是一个问题,因为以下定义使用square
参数定义int
。它必须决定警告之后声明它看到了不兼容的定义。
让我感到惊讶的是,它并没有对电话square(i)
发出警告。该调用与定义(跟随它)一致,但与声明(在其之前)不一致。
C旨在一次性处理。构造的合法性取决于它之前的代码,而不是它后面的代码。
但是C标准强加的唯一要求是编译器必须至少发出一个诊断。它没有说明诊断的措辞,也不需要它是一个致命的错误。在这种情况下,代码违反了约束(因为square
的声明和定义是不兼容的),并且在我看来应该拒绝该程序 - 但警告符合标准&# 39;要求。
无论编译器的作者做出什么决定,它确实会产生一些警告信息,你不应该忽略它们。它(可能间接地)指出了代码的问题,你应该解决这些问题。编译器警告您的代码的事实有时比警告的实际内容更具信息性。