zoukankan      html  css  js  c++  java
  • 新编《守株待兔》—C语言版—兼聊为什么不应该用%d格式转换输出指针

          有时候我感到和某些人讲道理比教猫唱歌还费劲。
          比如说,当你指出某些书上讲“鸡下鸭蛋”是胡说八道时,立刻就会有人跳出来说:鸡下不下鸭蛋并不重要,国内n多人都是看那本讲“鸡下鸭蛋”的书启蒙的,你掌握“下蛋”这一个知识点就够了,记住思想就好了。(参见http://www.cnblogs.com/pmer/archive/2011/08/08/2131075.html 评论部分)
          讨论和交流的前提是双方有共同的逻辑基础,如果您觉得“鸡下鸭蛋”并不荒谬而有思想的话,建议就不要再浪费时间继续看下去了,此文仅供那些懂得鸡不可能下鸭蛋的人参考。

          韩非老师讲过一个故事:
          宋人有耕田者。田中有株,兔走触株,折颈而死。因释其耒而守株,冀复得兔。兔不可复得,而身为宋国笑。
          每个人都会笑这个人很傻,包括幼儿园的小朋友都会。然而,假如这个人第二天又得一兔呢?还有多少人觉得他很傻?
          再假如这个人第三天依旧得一兔,有多少人依然坚信这不过是一个偶然事件?有多少人会跟着宋人一起去捡兔子呢?
          我知道一定会有人会跟着宋人去捡兔子。
          但假如此时有一个人,所有的人都知道他从不说假话,这个人说,那颗树下,从前并不是天天有兔子,以后也未必就天天会捡到兔子。尽管人人都知道这个人从不说假话并且永远不说假话,但是面对兔子的诱惑,这时还会有多少人还会相信他呢?
          这时这个人又说,稍微远一点的那颗树下一定会天天有兔子,而在近处那颗树下,尽管现在捡到了几只兔子,可能某天会遇到有害的虫子。
    假设人人都知道这个人说的一定是真话,相信这时会有人肯每天走得稍微远一点,以得到必然会获得的兔子并躲避有害的虫子。但是会不会有人依旧坚持到近处那颗树下去捡兔子呢?
          如果有人依旧坚持到近处那颗树下去捡兔子,这个人是否和韩非讲过的那个宋人一样可笑呢?
          结论留给大家自己去做,下面谈C语言里面的兔子。

    printf("%o",p);                                
    作用是以八进制形式输出指针变量p的值。
    ————谭浩强 ,《C程序设计》(第四版),清华大学出版社,2010年6月,p224

          这就是在近处那颗树下捡到的第一只兔子。因为在C标准和K&R的《C程序设计语言》(第二版)中,只说过%o用于转换输出int类型的值,从没说过%o可以用于转换输出指针。
          然而这确实是一只兔子,因为:编译通过了,运行也没捅漏子,居然有一个貌似正确的结果。
          于是开始在近处那颗树下捡第二只、第三只兔子……:

    #include <stdio.h>
    int main()
    {
    int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
    printf(
    "%d,%d\n",a,*a);
    printf(
    "%d,%d\n",a[0],*(a+0));
    printf(
    "%d,%d\n",&a[0],&a[0][0]);
    printf(
    "%d,%d\n",a[1],a+1);
    printf(
    "%d,%d\n",&a[1][0],*(a+1)+0);
    printf(
    "%d,%d\n",a[2],*(a+2));
    printf(
    "%d,%d\n",&a[2],a+2);
    printf(
    "%d,%d\n",a[1][0],*(*(a+1)+0));
    printf(
    "%d,%d\n",*a[2],*(*(a+2)+0));
    return0;
    }

    ————谭浩强 ,《C程序设计》(第四版),清华大学出版社,2010年6月,p248~249
          有了第一次成功的经验,这次的胆子更大了,居然用%d格式转换输出指针。好在这回没有窜出一条有毒的虫子(BUG),跑出来的还是一只兔子。这可能让在旁边捏着一把汗观看的人感到非常意外,侥幸捡到兔子简直是交上了狗屎运。要知道,%d可是有可能输出一个负的十进制整数的啊。
          虽然C标准及K&R只说过%d用于转换输出int类型的值,从没说过%d可以转换输出指针。然而这次还是捡到了兔子。

          然而历史有没有告诉过我们用%d或%o的方法捡不到兔子呢?有。但我不想和大家一道重温Intel8086的16位段地址和16位偏移地址组合成20位地址那噩梦一般的历史,只在这里陈述一下简单的历史事实:历史上有些C语言编译器中的各种不同类型的指针的大小并不相同,这时你绝对不可能把指针看得和int等同,更何况即使指针长度都和int长度相同也没有理由把指针看成int——它们毕竟不是相同的数据类型。
          这种噩梦般的历史一去不返了吗?NO!没有任何理由可以让我们作出这样的判断。

          那么,C标准有没有说过在哪颗树下一定可以捡到兔子呢?有!C标准和K&R都说过,指针应该用%p格式转换输出。
          那么为什么用%d或%o(也有人用%u)可以捡到兔子呢?相信一定会有心怀不甘或恼羞成怒的人这样反问。
          答案是,C标准没有说用%d或%o转换输出指针会产生什么样的结果(包括编译报错和警告),因此这是一个未定义行为(undefined behavior)。所谓未定义行为往往比你想象的还未定义,它可能在某些情况下假情假意地迎合你,但是假意迎合不表示遵从,它保留随时和你翻脸的权利。所以未定义行为是一种比立即发作的BUG更危险的BUG,不了解这一点就等于并不懂得C。
          现在是否还有宋人不愿意走得稍微远一点,不用%p转换输出指针而用%d、%o或%u转换输出指针呢?相信还会有。有的宋人是不到黄河心不死、不碰南墙不回头的,非得碰得头破血流不可。这也是没办法的事。我这里只能友情提醒一下,南墙不远:据网友ChiyuT报告,在他的机器上,指针是8个字节,不过int还是4个字节(http://bbs.chinaunix.net/thread-3582216-7-1.html)。

  • 相关阅读:
    poj 2763 Housewife Wind
    hdu 3966 Aragorn's Story
    poj 1655 Balancing Act 求树的重心
    有上下界的网络流问题
    URAL 1277 Cops and Thieves 最小割 无向图点带权点连通度
    ZOJ 2532 Internship 网络流求关键边
    ZOJ 2760 How Many Shortest Path 最大流+floyd求最短路
    SGU 438 The Glorious Karlutka River =) 拆点+动态流+最大流
    怎么样仿写已知网址的网页?
    5-10 公路村村通 (30分)
  • 原文地址:https://www.cnblogs.com/pmer/p/2149879.html
Copyright © 2011-2022 走看看