• C专家编程 第8章 为什么程序员无法分清万圣节和圣诞节 8.5 原型在什么地方会失败


    原型在什么地方会失败
    我们需要考虑4种情况
    1.K&R C函数声明和K&R C函数定义
    能够顺利调用,所传递的参数会进行类型提升
    2.ANSI C函数声明(原型)和ANSI函数定义
    能够顺利调用,所传递的参数为实际参数。
    3.ANSI C函数声明(原型)和K&R C函数定义
    如果使用一个较窄的类型就会失败!函数调用时所传递的是实际类型,而函数期望接受的是提升后的类型。
    4.K&R C函数声明和ANSI C函数定义
    如果使用一个较窄的类型就会失败!函数调用是所传递的是提升后的类型,而函数期望接受的是实际类型。所以,如果为一个K&R C函数定义增加函数原型,而原型的参数列表中有一个short参数,在参数传递时,这个原型将导致实际传递给函数的就是short类型的参数,而根据函数的定义,他期望接受的是一个int类型的参数。可以通过在原型中强迫使用宽类型,从而使代码在第3、4中两种情况下仍能正常运行。但这种做法不仅违背了可移植性原则,而且会给维护代码的程序员带来困惑。 

     

    /*文件1
    /*旧风格的函数定义,但它却具有原型*/
    int olddef(d, i)
    float d;
    char i; {
        printf("olddef: float = %f, char = %x\n", d, i);

    /*新风格的定义,但它却没有原型*/
    int newdef(float d, char i) {
        printf("newdef:float = %f, char = %x\n", d, i);

    /*文件2
    旧风格的定义,但它具有原型*/
    int olddef(float d, char i);

    int main() {
        float d = 10.0;
        char j = 3;
        olddef(d, j);
        /*新风格的定义,但它没有原型*/
        newdef(d, j); 

    注意,如果把函数的定义放在它们被调用的同一个文件内,程序的行为就会不一样。编译器将会检测到olddef()的不匹配,因为它现在看不到原型和K&R C的函数定义。如果把newdef()的定义放在它被调用之前,编译器就会平静地执行正确的操作,因此此时函数的定义就相当于原型,它保证了声明和定义的一致性。如果把函数的定义放在它被调用以后,编译器就会发出“类型不匹配”的错误信息。由于C++要求所有函数必须具有原型,你可能会想用C++编译器去编译那些旧式的K&R C代码,在编译器发出错误信息的地方逐个为函数添加原型。

    早些时候我曾提到原型允许编译器检查函数使用和声明之间的一致性。在实际编程中,我们通过把函数原型放置在头文件中,而把函数定义放置在另一个包含了该头文件的源文件中来放置这种情况的发生。编译器可以同时发现它们,如有不匹配就能检测到。

    不要在函数的声明和定义中混用新旧两种风格
    如果函数在头文件里的声明时K&R C风格的,那么该函数的定义也应该使用K&R C风格的语法。
    int foo(); int foo(a, b) int a; int b; {/*...*/} 
    如果函数在头文件里的声明时ANSI C风格的,那么该函数的定义也应该使用ANSI C风格的语法。
    int foo(int a, int b); int foo(int a, int b) {/*...*/}

    可以建立一种可靠的机制来检查跨越多个文件的函数调用。在printf这种参数不定的函数中需要使用特别的技巧(当前就是如此)。它甚至可以应用于现存的语法。它所需要的就是在标准中规定每次调用函数时必须在参数名字、数量、类型以及函数的返回地址上与函数的定义保持一致。这种“预防艺术”确实存在,Ada语言就是这么做的。C语言也可以使用这种方法,不过需要在链接器之前进行一个额外的传递(重要提示:使用lint程序)

    或许ANSI C委员会在这方面也应该做一番努力,规定一个完整的解析过程,即使它在链接器之前需要进行一次传递。应该摒弃C++那种烦琐的部分解析过程,并且规定自己的约定、语法、语义和限制。 

    /*
    **编程挑战。
    */ 
    在一个独立的文件里创建下列函数:
    void banana_peel( char a, short b, float c ){
        printf( "char = %c, short = %d, float = %f\n", a, b, c );

    在另一个独立的文件里,建立调用banana_peel()的主程序。 
    1.试试在使用原型和不使用原型这两种情况下调用它,再试试在原型和定义不匹配的情况下调用它。 
    /*file.cpp内容如下:*/
    #include
    void banana_peel( char a, short b, float c ){
        printf( "char = %c, short = %d, float = %f\n", a, b, c );

    /*file2.cpp
    *调用banana_peel的程序。*/
    #include
    #include

    int main( void ){
        banana_peel( 'b', 2, 6.0 );
        
        return EXIT_SUCCESS;
    }

    /*
    **file3.cpp
    **调用banana_peel的程序。 
    */
    #include
    #include

    extern void banana_peel( char a, short b, float c );

    int main( void ){
        banana_peel( 'b', 2, 6.0 );
        
        return EXIT_SUCCESS;
    }

    /*
    **file4.cpp
    **调用banana_peel的程序。 
    */
    #include
    #include

    extern void banana_peel( int a, short b, char c );

    int main( void ){
        banana_peel( 'b', 2, 6.0 );
        
        return EXIT_SUCCESS;
    }

    /*没有使用原型的情况下*/
    /*输出:

     */ 
    /*使用原型的情况下*/
    /*输出:

     */

    /*原型和定义不匹配的情况下*/

    /*输出:

    */

    2.在每种情况下,在运行代码之前预测结果。编写一个union,你可以向它存储一个值却取回另一个值(两个值的长度不同),检测你的预测是否正确。 

    与原型有关的类型提升 
    #include

    int main() {
        union {
            double d;
            float f;
        } u;
        u.d = 10.0;
        printf("put in a double, pull out a float f = %f\n", u.f);
        u.f = 10.0;
        printf("put in a float, pull out a double d = %f\n", u.d);
        return 0;
    }

    /* 输出:

    */ 

    3.参数次序的改变(在函数的声明和定义中)是否会影响被调用函数接收参数的方式?解析其中的原因。你的编译器捕捉到多少种错误情况?
    解析:
    K&R C会影响被调用函数接收参数的方式,ANSI C不会影响被调用函数接收参数的方式。在ANSI C中的函数原型如果跟定义中的函数不一致,就会导致编译错误。在K&R C中,因为声明时只需要给出函数的名字就行,定义时才会进行裁剪,若果参数次序发生改变就会导致裁剪错误。 

  • 相关阅读:
    ping&icmp
    Windows 10 启用 Hyper-V
    MAA接枝聚苯乙烯(PSt-g-PMAA)共聚微球/聚醋酸乙烯酯接枝聚苯乙烯复合微球应用
    支持语音与视频即时通讯项目杂记(二)
    python+vue+elementui基于用户兴趣的电影视频推荐系统java springboot
    小学妹刚毕业没地方住想来借宿?于是我连夜用Python给她找了个好房子,我真是太机智了
    Docker自定义镜像
    GO编程实践:如何高效使用变量
    干货 | 做外贸必须掌握的小知识
    C语言 软件设计的七大原则,及其应用案例
  • 原文地址:https://blog.csdn.net/weixin_40186813/article/details/126083246