我写故我在

I write, therefore I am

C 函数声明

Posted by ieipi 于 五月 15, 2011

国内有多少书声称函数必需先声明再调用? 比如<<程序员面试宝典>>P72例7. 那么实际情况呢?
Test 1: 同一个文件

int
main ( int argc, char *argv[] )
{
    double i1, i2;
    /*case 1: no declarations*/
    /*case 2: */
    //int fun1();
    /*case 3: */
    //double fun1();
    /*case 4: */
    //int fun1(int);
    i1 = fun1();
    i2 = fun1(i1);
    printf ( "i1=%d\n", i1);
    printf ( "i2=%d\n", i2);
    return EXIT_SUCCESS;
}				/* ----------  end of function main  ---------- */
fun1(int a, int b)
{
    double d = 3.1234567;
    printf ( "d=%.8f\n", d);
    return d;
}

结果:
case1 和 case2 输出结果相同,均为:

d=3.12345670
d=3.12345670
f1=3.00000000
f2=3.00000000

case3 和 case4 编译错误.
分析:
1).函数名是external object,默认具有全局(global)可见性. 函数原型声明只用于帮助编译器进行类型检查.
2).对于变量,编译器必需进行类型检查,所以必需”先声明后使用”.对于函数可以关闭类型检查(老版C 语言).
3).编译器如果遇到一个事先未声明的标示符,并且紧跟着一个左半括号(即形如”foo(“的语句),就把它默认处理为函数名.并且默认返回类型为int,形参表则不做任何假设.(即默认扩展为函数声明int foo();).
4).对于形参表为空的声明(例如 double atof(); ),编译器将关闭对形参表的类型检查,但是对于返回类型,仍将进行类型检查.
5).一个最简单的函数定义为:

foo() {}

问题:调用此函数的返回结果是多少?
Test 2: 两个文件

/*foo.c*/
foo()
{
    double d = 3.1234567; 
    printf ( "d=%.8f\n", d);
    return d; 
}
/* main.c*/
    int
main ( int argc, char *argv[] )
{
    double f1; 
    /* case 1: no declaration */
    f1 = foo(3, 4); 
    printf ( "f1 = %.8f\n", f1 );

    /* case 2: declaration */
    /*int foo(); */
    /*f1 = foo(); */
    /*printf ( "f1 = %.8f\n", f1 );*/

    /* actually incompatible prototype declaration. */
    /*double foo(int, int); */
    /*f1 = foo(3, 4); */
    /*printf ( "f1 = %.8f\n", f1 );*/

    return EXIT_SUCCESS;
}				/* ----------  end of function main  ---------- */

结果(编译时必需同时编译foo.c和main.c):
case1 和case2 的结果相同

d=3.12345670
f1 = 3.00000000

case3 的结果为:

d=3.12345670
f1 = -nan

分析:
1).编译器的编译检查只能局限在同一个源文件范围类,涉及到多个源文件的情况由连接器解决.
2).链接时只检查函数名,而不检查参数表和返回值(所以c中函数无法重载)
3).注意case3的结果输出为NaN,这是因为foo函数默认返回int型,而该int型的二进制表示恰好不符合浮点数的表示规则.
总结
1.”函数需要先声明后使用”,是一个好的编程规范,但并不是语言特性所要求的.
2.函数声明只用来帮助编译器进行类型检查.若函数定义和声明在同一个文件中,则可以检查定义,声明和调用是否匹配;
若定义和声明不在同一个文件,则只需函数声明和调用保持一致,并且与定义同名.

Advertisements

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

 
%d 博主赞过: