• 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
     */ 
    /*实参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 

    int main() 
    {
        const int limit = 10;
        printf( "limit = %d\n", limit );
        const int *limitp = &limit;
        printf( "*limitp = %d\n", *limitp );
        int i = 27;
        limitp = &i;
        printf( "limit = %d\n", limit );
        printf( "*limitp = %d\n", *limitp ); 
        printf( "i = %d\n", i ); 
        
        return 0;
    }

    /* 输出:

    */ 

  • 相关阅读:
    医疗实施-MDM主数据管理基本介绍
    VOIT Automotive EDI项目案例
    TCP 的 Keepalive 和 HTTP 的 Keep-Alive 是一个东西吗?
    Flutter 3.0升级内容,该如何与小程序结合
    VirtualApp系统升级适配方法论(1)——一切从源码来
    数据结构-二叉搜索树
    day05vue学习
    如何基于 GORM 实现 CreateOrUpdate 方法
    关于#c++#的问题,请各位专家解答!
    2023年10月2日
  • 原文地址:https://blog.csdn.net/weixin_40186813/article/details/126069373