C专家编程 第1章 C:穿越时空的迷雾 1.9 阅读ANSI C标准,寻找乐趣和裨益

    阅读ANSI C标准,寻找乐趣和裨益 
    int foo(const char **p) {
    }
    编译这段代码,编译器会发出一条警告信息: 
    int main(int argc, char **argv) {
        foo(argv);
    }
    /*line 5: warning: argument is incompatible with prototype
    *prototype: pointer to pointer to const char:
    *argument: pointer to pointer to char*/ 
    /*
    ** interest of ansi.
    */
    #include <stdio.h>
    #include <stdlib.h>

    int foo( const char **p );

    int main( int argc, char *argv[] ){
        /*
        ** foo( argv );
        ** can't pass compilation:
        ** because of [Error] invalid conversion from 'char **' to 'const char **'[-fpermissive]
        ** and [Note] initializing argument 1 of 'int foo(const char **)'
        */
    
        return EXIT_SUCCESS;
    }

    int foo( const char **p ){
        return 0;
    }
输出:

    实参char *s与形参const char *p应该是相容的,标准库中所有的字符串处理函数都是这样的。
    实参char **argv与形参const char **p实际上不能相容呢?答案是肯定的,它们并不相容。 
    每个实参都应该具有自己的类型,这样他的值就可以赋值给它所对应的形参类型的对象(该对象的类型不能含有限定符)。
    这就是说参数传递过程类似于赋值。所以,除非一个类型为char**的值可以赋值给一个const char**类型的对象,否则肯定会产生一条诊断信息。要想知道这个赋值是否合法,就请回顾标准中有关简单赋值的部分。 
    标准中关于简单赋值的部分 
    *要使上述的赋值形式合法,必须满足下列条件之一:
    *两个操作数都是指向有限定符或无限定符的相容类型的指针,左边指针所指向的类型必须
    *具有右边指针所指向类型的全部限定符。
    //合法: 
    char *cp;
    const char *ccp;
    ccp = cp;
    左操作数是一个指向有const限定符的char的指针,右操作数是一个指向没有限定符的char的指针。char类型与char类型是相容的,左操作数所指向的类型具有右操作数所指向类型的限定符(无),再加上自身的限定符(const)。
    cp = ccp; /*结果产生编译警告*/

    const float *类型并不是一个有限定符的类型---它的类型是“指向一个具有const限定符的float类型的指针”,也就是说const限定符是修饰指针所指向的类型,而不是指针本身。
    const char **也是一个没有限定符的指针类型,它的类型是“指向有const限定符的char类型的指针的指针”
    char**和const char **都是没有限定符的指针类型,但它们所指的类型不一样(前者指向char*, 后者指向const char *),所以它们是不相容的。因此,类型为char**的实参与const char **的形参是不相容的。
    可以用下面这个方法进行理解:
    左操作数的类型是FOO2,它是一个指向FOO的指针,而FOO是一个没有限定符的指针,它指向一个带有const限定符的char类型。
    右操作数的类型为BAZ2,它是一个指向BAZ的指针,而BAZ是一个没有限定符的指针,它指向一个没有限定符的char类型。 
    FOO和BAZ所指的类型是相容的,而且他们本身都没有限定符,所以符合标准的约束条件,两者之间赋值是合法的。
    但FOO2和BAZ2之间的关系又有不同,由于相容性是不能传递的,FOO和BAZ所指向的类型相容并不代表FOO2和BAZ2所指向的内容也相容,所以虽然FOO2和BAZ2都没有限定符,但它们之间不能进行赋值。也就是说,它们都是不带限定符的指针但它们所指的对象是不同的,所以它们不能进行赋值,也就不能分别作为函数的形参和实参。 

    启发 
    关键字const并不能把变量变成常量,const 限定符只是表示这个符号不能被赋值,也就是它的值对于这个符号来说是只读的,但它并不能防止通过程序的内部(甚至是外部)的方法来修改这个值。 
    const最有用之处就是它来限定函数的形参,这样该函数将不会修改实参指针所指的数据,但其他的函数却可能会修改它。这也许就是C和C++中const最一般的用法。 
    const可以用在数据上:
    const int limit = 10;
    limitp 是一个指向常量整数的指针,这个指针不能用于修改这个整数值。但是在任何时候,这个指针本身的值却可以改变。这样,它就指向了不同的的地址,对它进行解除引用(dereference)操作会得到一个不同的值。
    const和*的组合通常只用于在数组形式的参数中模拟传值调用。它声称“我给你一个指向它的指针,但你不能修改它”。
    这个约定类似于从极为常见的void*的用法,尽管在理论上它可以用于任何情形,但通常被限制于把指针从一种类型转换为另一种类型。 
    const int *limitp = &limit;
    int i = 27;
    limitp = &i;  
    类似地,你可以取一个const变量的地址,并且可以......。正如Ken Thompson所指出的那样,“const关键字可能引发一些罕见的错误,只会混淆函数库的接口”。回首往事,const关键字原先如果命名为readonly就好多了。

    #include<stdio.h>
    
    int main()
    {
        const int limit = 10;
        printf( "limit = %d\n", limit );
        const int *limitp = &limit;
        printf( "*limitp = %d\n", *limitp );
        /*
        ** *limitp = 12;
        ** can't pass compilation:
        ** because of [Error] assignment of read-only location '*limitp'
        */
        int i = 27;
        printf( "i = %d\n", i );
        void *p = &i;
        *(int *)p = 12;
        printf( "*p = %d, i = %d\n", *(int *)p, i );
        limitp = &i;
        printf( "limit = %d\n", limit );
        printf( "*limitp = %d\n", *limitp );
        printf( "i = %d\n", i );
        
        return 0;
    }

输出:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_40186813

你的能量无可限量。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值