免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: pmerofc
打印 上一主题 下一主题

[C] 《C解毒》征询意见帖 [复制链接]

论坛徽章:
5
狮子座
日期:2013-08-20 10:12:24午马
日期:2013-11-23 18:04:102015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之德黑兰石油
日期:2015-06-29 18:11:1115-16赛季CBA联赛之新疆
日期:2024-02-21 10:00:53
151 [报告]
发表于 2012-02-08 15:17 |只看该作者
本帖最后由 starwing83 于 2012-02-08 15:17 编辑

亡羊补牢还是越错越远

    谭书其实和C语言有一个很相像的地方,就是都出了很多个版本。然而C语言出新的版
本是为了方面程序员、适应新的变化和开发风格。而一本教材出新的版本无非就是修正错
误和描述语言的新方向。然而,如果一本教材的第一版就是概念不清胡说八道,却又碍着
面子不肯承认自己的错误,那最终的结果就是越错越远了。

    就比如这里:

定义变量的位置:一般在函数开头的声明部分定义变量,也可以在函数外定义变量(即外部变量、全局变量,见第7章)。C99允许在函数中的复合语句(用一句花括号括起来)中定义变量。

————谭浩强 ,《C程序设计》(第四版),清华大学出版社,2010年6月,p41

    我相信谭老一定没有亲自去看过C99标准,不知道是英文不好还是自信满满觉得自己
比标准要牛。所以,虽然谭老的确知道有“标准化”这么一个说法,却只有错上加错的份
儿。事实上,我看不出这里的“一般”有什么凭据,难道谭老从没有看过正式地C语言项
目吗?一般情况下,只有八十年代到九十年代的C语言项目才会“一般”在函数开头定义
变量,新的项目一般定义变量的位置是复合语句的开头。将自己的臆测煞有介事地说成业
界惯例,不知道这是无耻还是做得太多已经麻木了。

    让我们来揭开谜底吧。实际上,这段话几乎每一句都是错误的。”一般在函数开头的
声明部分“,很遗憾地,C99根本就没有“声明部分”的说法,而C90中,声明部分根本就
不止限于函数开头!“也可以在函数外定义变量”这一句是对的,然而括号坏事了:“(
即外部变量,全局变量)”,事实上C语言根本没有全局变量的说法,只有外部变量,静
态变量的说法,因为事实上这里的全局是有两个含义的:文件域的全局,和整个程序范围
的全局。这两个含义是根据变量的链接性来定义的,我们之前就提到了链接性的概念,而
谭书对此只字不提。“C99运行在函数中的复合语句(用一对花括号括起来)中定义变量
”,首先这是C90的特性,而不是C99的,其次,括号内的部分明显代表谭老根本就不知道
什么是复合语句,花括号本身是复合语句的一部分,复合语句花括号内的部分在标准中是
被叫做“块项列表(block-item-list)”的,而列表中的一个块项既可以是声明,也可
以是语句。对基本概念都不清晰,也难怪错的这么离谱了。

    我们总结一下:
        - C99实际上是允许你在任何地方声明变量的。
        - C90声明部分实际上是可以在任何复合语句的开头的。
       
    也就是说,下面的代码在C90里面仍然是合法的:

  1.     void reverse(int array[], size_t size) {
  2.         int i = 0, j = size - 1;
  3.         for (; i < j; ++i, --j) {
  4.             int temp = array[i];
  5.             array[i] = array[j];
  6.             array[j] = temp;
  7.         }
  8.     }
复制代码
只有唯一一种情况是必须在函数开头申请变量的:即该变量在整个函数的执行过程中
都必须存在。而真正有这么一个需求是很罕见的。如同这里的 temp 变量,它只需要在交
换的时候才存在,因此就不该把它和 i, j 声明在一起。上面的代码是合法的 C90 代码
,可以在任何严格支持 C90 (而不支持 C99)的编译器下编译。

    就算你用的是C90的编译器,你也仍然可以获得“随处声明变量”的特权,很简单,
在需要使用局部变量的时候,直接用复合即可,这也是复合语句作为一种单独的语句类型
出现的另一个理由。(前一个理由是作为其他语句(如if for)中的语句部分存在)

    在真正使用的时候申请变量是个好习惯,这也是 C99 真正的改变是允许变量在任意
位置定义,而不仅限复合语句开头的缘故。这可以防止变量的名字冲突,简化逻辑——新
申请的变量哪怕名字和之前申请的一致,也不会对旧的变量有任何影响,一旦新变量超过
作用域,旧的变量仍然有效。这是C语言的一个重大特性,也被认为是C语言最优秀的一个
特性,这个特性就是大名鼎鼎的“词法作用域”。它被广泛地用在了大量的语言上,是编
程语言的一个约定俗成的基本特性。如果不允许在复合语句内申请变量,无异于让C语言
自废武功。

    并且,我们知道,C语言的局部变量是分配在栈上的。那么局部变量的及时释放也帮
助节省栈空间:对于两个平行的复合语句块,其内部的局部变量事实上是共享一块区域的
,这就是词法作用域的另一个实际好处。

    为什么谭老即使是愿意让C语言自废武功,也不愿意介绍真正的C99的变量声明特性呢
?原因是谭书的前一个版本言之凿凿地说明“变量只允许声明在函数开头”,记得我最开
始看谭书的时候,就一直是这么申请变量的,直到自行翻阅C90标准才走出这个误区。08
年的时候我帮助一个上海交大的生物系研究生修改其 DNA 检测代码,就发现一堆的 i,
j, k, l, m, n 被申请在函数开头,整个程序十分难维护,后来花了很大功夫才将代码整
理完成,由此可见谭书危害之深。

    程序员一个重要的素质就是肯承认错误,肯承认失误。程序本就是思维的结晶,是智
慧最集中的产品。不肯承认错误,就一定会被更先进者替代。而谭书却死死抓住“权威”
两字不放,宁愿错上加错也不肯承认自己不是完人。这样的心态怎么符合一个程序员的自
我修养呢?又怎么培育合格的程序员呢?书的销量越好,事实上是流毒越多而已。

    下面我们介绍一下C99真正的新特性,看看标准委员会为C语言的进步做出了什么样的
努力。

    C99从C++中引进了可以“随处申请变量”的特性,并修改了 for 语句的语法,添加
了一个新的 for 语句形式。对C99来说,符合语句内已经不区分“声明部分”和“语句部
分”,在任何地方都可以书写声明或者语句,而新加入的 for 语句的语法是允许 for 的
第一个部分是声明,后跟可选的表达式(注意声明本身会带上一个分号),后跟必须的分
号,再跟可选的表达式。也就是说,上面的反转函数实际上可以这么写:

  1.     void reverse(int array[], size_t size) {
  2.         for (int i = 0, j = size - 1; i < j; ++i, --j) {
  3.             int temp = array[i];
  4.             array[i] = array[j];
  5.             array[j] = temp;
  6.         }
  7.     }
复制代码
这时,i, j, temp 就同属一个作用域了,即 for 语句的语句体。在 for 语句之外
使用 i, j, temp 会造成编译错误。

    注意和C++不同,对C99来说只有 for 才有在第一部分申请变量的殊荣, if、while
等等语句都是不允许的。而在C++里面这些语句的条件判断部分都是可以申请新变量的。

    从C99的新特性可以看出,C语言显然易见地是支持并鼓励“使用处声明”的编程方法
的。而谭书却对此只字不提,挂着着C99的羊头,卖着C89的狗肉,不愿大大方方地承认自
己的错误,甚至连一点点改过的意向都没有,只是一门心思的一错再错,一条路走到黑。
这种态度不止是一本教科书编撰者,就算只是一个普通的程序员,恐怕也逃不过被开除的
命运。

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
152 [报告]
发表于 2012-02-08 15:36 |只看该作者
pmerofc 发表于 2012-02-08 15:02
回复 150# flw

新来的吧?

flw 三个字母就是理由。这就是一个鉴定专用章。

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
153 [报告]
发表于 2012-02-08 15:46 |只看该作者
pmerofc 发表于 2011-07-16 14:08
代码写得要"拽"(DRY)
  
      DRY : Don’t repeat yourself,是编写出优质代码的一个重要原则。其含义就 ...

   while( printf("please input the value of n: ") ,

                        scanf("%d",&n) ,

                        n<=0 )

      printf("error!");

让人呕吐的代码

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
154 [报告]
发表于 2012-02-08 16:03 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
2
技术图书徽章
日期:2013-09-04 15:21:51酉鸡
日期:2013-11-01 21:20:20
155 [报告]
发表于 2012-02-08 22:48 |只看该作者
flw 发表于 2012-02-08 14:25
这个写法太二逼了。

居然有这神奇的写法?

论坛徽章:
0
156 [报告]
发表于 2012-02-09 11:15 |只看该作者
flw 发表于 2012-02-08 14:25
这个写法太二逼了。


放驴娃真是含蓄,
不但2B,还有bug,输入一个十六进制数 0x2B
程序就不响应用户,自己死循环去了.

(测试环境:mingw gcc)

屏幕输出如下 ---

error!please input the value of n: error!please input the value of n: error!plea
se input the value of n: error!please input the value of n: error!please input t
he value of n: error!please input the value of n: error!please input the value o
f n: error!please input the value of n: error!please input the value of n: error
!please input the value of n: error!please input the value of n: error!please in
put the value of n: error!please input the value of n: error!please input the va
lue of n: error!please input the value of n: error!please input the value of n:
error!please input the value of n: error!please input the value of n: error!plea
se input the value of n: error!please input the value of n: error!please input t
he value of n: error!please input the value of n: error!please input the value o
f n: error!please input the value of n: error!please input the value of n: error
!please input the value of n: error!please input the value of n: error!please in
put the value of n: error!please input the value of n: error!please input the va
lue of n: error!please input the value of n: error!please input the value of n:
error!please input the value of n: error!please input the value of n: error!plea
se input the value of n: error!please input the value of n: error!please input t
he value of n: error!please input the value of n: error!please input the value o
f n: error!please input the value of n: error!please input the value of n: error
!please input the value of n: error!please input the value of n: error!please in
put the value of n: error!please input the value of n: error!please input the va
lue of n: error!please input the value of n: error!please input the value of n:

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
157 [报告]
发表于 2012-02-09 11:41 |只看该作者
starwing83 发表于 2012-02-07 13:11
包含源文件 —— 是奇技淫巧还是饮鸩止渴?

    C语言如此流行,有一个很重要的原因是C语言志向于“抽象 ...


来插一杠子。。。

/* Get an address range which is currently unmapped.
* For mmap() without MAP_FIXED and shmat() with addr=0.
* Return value 0 means ENOMEM.
*/
#ifndef HAVE_ARCH_UNMAPPED_AREA
unsigned long get_unmapped_area(unsigned long addr, unsigned long len)
{
        struct vm_area_struct * vmm;

        if (len > TASK_SIZE)
                return 0;
        if (!addr)
                addr = TASK_UNMAPPED_BASE;
        addr = PAGE_ALIGN(addr);

        for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
                /* At this point:  (!vmm || addr < vmm->vm_end). */
                if (TASK_SIZE - len < addr)
                        return 0;
                if (!vmm || addr + len <= vmm->vm_start)
                        return addr;
                addr = vmm->vm_end;
        }
}
#endif

#define vm_avl_empty        (struct vm_area_struct *) NULL

#include "mmap_avl.c"

/* Look up the first VMA which satisfies  addr < vm_end,  NULL if none. */
struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)
{
        struct vm_area_struct *vma = NULL;

        if (mm) {
                /* Check the cache first. */
                /* (Cache hit rate is typically around 35%.) */
                vma = mm->mmap_cache;
                if (!(vma && vma->vm_end > addr && vma->vm_start <= addr)) {
                        if (!mm->mmap_avl) {
                                /* Go through the linear list. */
                                vma = mm->mmap;
                                while (vma && vma->vm_end <= addr)
                                        vma = vma->vm_next;
                        } else {
                                /* Then go through the AVL tree quickly. */
                                struct vm_area_struct * tree = mm->mmap_avl;
                                vma = NULL;
                                for (; {
                                        if (tree == vm_avl_empty)
                                                break;
                                        if (tree->vm_end > addr) {
                                                vma = tree;
                                                if (tree->vm_start <= addr)
                                                        break;
                                                tree = tree->vm_avl_left;
                                        } else
                                                tree = tree->vm_avl_right;
                                }
                        }
                        if (vma)
                                mm->mmap_cache = vma;
                }
        }
        return vma;
}

论坛徽章:
2
技术图书徽章
日期:2013-09-04 15:21:51酉鸡
日期:2013-11-01 21:20:20
158 [报告]
发表于 2012-02-09 12:00 |只看该作者
回复 158# zylthinking
你这个还好,做了if定义,看这个:
  1. /*-
  2. * Fowler / Noll / Vo Hash (FNV Hash)
  3. * http://www.isthe.com/chongo/tech/comp/fnv/
  4. *
  5. * This is an implementation of the algorithms posted above.
  6. * This file is placed in the public domain by Peter Wemm.
  7. *
  8. * $FreeBSD: src/sys/sys/fnv_hash.h,v 1.3.22.1 2009/08/03 08:13:06 kensmith Exp $
  9. */

  10. typedef u_int32_t Fnv32_t;
  11. typedef u_int64_t Fnv64_t;

  12. #define FNV1_32_INIT ((Fnv32_t) 33554467UL)
  13. #define FNV1_64_INIT ((Fnv64_t) 0xcbf29ce484222325ULL)

  14. #define FNV_32_PRIME ((Fnv32_t) 0x01000193UL)
  15. #define FNV_64_PRIME ((Fnv64_t) 0x100000001b3ULL)

  16. static __inline Fnv32_t
  17. fnv_32_buf(const void *buf, size_t len, Fnv32_t hval)
  18. {
  19.         const u_int8_t *s = (const u_int8_t *)buf;

  20.         while (len-- != 0) {
  21.                 hval *= FNV_32_PRIME;
  22.                 hval ^= *s++;
  23.         }
  24.         return hval;
  25. }

  26. static __inline Fnv32_t
  27. fnv_32_str(const char *str, Fnv32_t hval)
  28. {
  29.         const u_int8_t *s = (const u_int8_t *)str;
  30.         Fnv32_t c;

  31.         while ((c = *s++) != 0) {
  32.                 hval *= FNV_32_PRIME;
  33.                 hval ^= c;
  34.         }
  35.         return hval;
  36. }

  37. static __inline Fnv64_t
  38. fnv_64_buf(const void *buf, size_t len, Fnv64_t hval)
  39. {
  40.         const u_int8_t *s = (const u_int8_t *)buf;

  41.         while (len-- != 0) {
  42.                 hval *= FNV_64_PRIME;
  43.                 hval ^= *s++;
  44.         }
  45.         return hval;
  46. }

  47. static __inline Fnv64_t
  48. fnv_64_str(const char *str, Fnv64_t hval)
  49. {
  50.         const u_int8_t *s = (const u_int8_t *)str;
  51.         u_register_t c;                 /* 32 bit on i386, 64 bit on alpha,ia64 */

  52.         while ((c = *s++) != 0) {
  53.                 hval *= FNV_64_PRIME;
  54.                 hval ^= c;
  55.         }
  56.         return hval;
  57. }
复制代码

论坛徽章:
3
2015年迎新春徽章
日期:2015-03-04 09:56:11数据库技术版块每日发帖之星
日期:2016-08-03 06:20:00数据库技术版块每日发帖之星
日期:2016-08-04 06:20:00
159 [报告]
发表于 2012-02-09 13:08 |只看该作者
AD8018 发表于 2012-02-09 11:15
放驴娃真是含蓄,
不但2B,还有bug,输入一个十六进制数 0x2B
程序就不响应用户,自己死循环去了.

我把它这个BUG干掉,hoho
   while( printf("please input the value of n: ") ,

                        scanf("%d",&n) &&

                        n<=0 )

      printf("error!");

论坛徽章:
2
程序设计版块每日发帖之星
日期:2015-06-17 22:20:00每日论坛发贴之星
日期:2015-06-17 22:20:00
160 [报告]
发表于 2012-02-09 13:28 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP