忘记密码   免费注册 查看新帖 | 论坛精华区

ChinaUnix.net

  平台论坛 博客 Club168 精华 文库 自测 访谈录| 频道操作系统 开发 数据库 存储 服务器 网络 IT新闻 Linux 下载 Power用户组
最近访问板块 发新帖
查看: 22856 | 回复: 196

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

Rank: 9Rank: 9Rank: 9

帖子
6459
主题
56
精华
0
可用积分
46818
专家积分
0
在线时间
3661 小时
注册时间
2009-12-09
最后登录
2012-05-23
论坛徽章:
0
发表于 2011-07-13 16:46:55 |显示全部楼层
本帖最后由 pmerofc 于 2012-05-18 19:35 编辑

本帖最后由 pmerofc 于 2011-12-09 11:49 编辑

0
打算把这个帖子(http://bbs.chinaunix.net/thread-1686753-1-1.html)里提到的那本书取名为《C解毒》
欢迎大家发表意见
本书最后定名为《品悟C——C程序设计中的谬误与恶习》

1
另外打算在陆续在这个帖子里发布部分写完的章节
欢迎大家指正

2
诚征C语言领域的各种误区、谬误、恶习及常见错误
先谢了!


C语言运算符优先级普遍存在的一个深层次误区
代码写得要"拽"(DRY)
“豆浆买两碗,喝一碗,倒一碗”
筛法“四不像”
混乱是怎样炼成的
怎样调戏程序
含糊之过、多做之过及乱做之过
关于函数原型的对话
新编《守株待兔》—C语言版—兼聊为什么不应该用%d格式转换输出指针
“函数声明”、“函数原型”与“函数定义”辨析
五花八门的main()
内裤外穿——错位及不伦不类
函数声明的位置问题
半身不遂和粗中有细
拙劣的外部变量
static的滥用与变态的阉割
边界测试——让BUG现形
flag标志什么?哦,它标志代码馊了——(一)
flag标志什么?哦,它标志代码馊了——(二)
flag标志什么?哦,它标志代码馊了——(三)
无知乱吃药
鸡窝里飞出伪凤凰
怎样整理房间
已知两边长求三角形面积
指针加减法运算的“定义域”
用驴子拖宝马——怎样滥用结构体
怎样建立链表并同时造成内存泄露
会错意表错情,搭错车上错床——“度日如年”的故事及“feof()”的故事
将main()进行到底
包含源文件 —— 是奇技淫巧还是饮鸩止渴?
亡羊补牢还是越错越远
糟蹋好题——魔方阵问题
free空指针
能否用痰盂盛饭——谈谈在头文件中定义外部变量
劣质代码评析——兼谈指针越界问题

Rank: 7Rank: 7Rank: 7

帖子
25889
主题
1467
精华
0
可用积分
10170
专家积分
302
在线时间
6446 小时
注册时间
2006-03-01
最后登录
2012-05-23
论坛徽章:
0
发表于 2011-07-13 16:56:58 |显示全部楼层
不支持,还是别趟浑水了
清茶流氓何其多,加起来还不及屁股发痒的十分之一。。。。。
财版富翁何其多,加起来还不及醉卧的十分之一。。。。。

Rank: 9Rank: 9Rank: 9

帖子
6459
主题
56
精华
0
可用积分
46818
专家积分
0
在线时间
3661 小时
注册时间
2009-12-09
最后登录
2012-05-23
论坛徽章:
0
发表于 2011-07-13 16:58:41 |显示全部楼层
本帖最后由 pmerofc 于 2011-07-13 21:08 编辑

C语言运算符优先级普遍存在的一个深层次误区

      国内许多C语言教科书,在介绍C语言运算符时,都把所谓的“单目运算符”归纳为优先级相同结合性从右向左的运算符。例如号称是“我国广大初学者学习C语言程序设计的主流用书”的《C程序设计》(谭浩强著,清华大学出版社,2010年6月(第四版))的378页“附录D 运算符和结合性”中就是这样:

                                                     附录D 运算符和结合性

优先级                  运算符                 含义                            要求运算对象的个数                结合方向
                                                                                       
1                           ( )                 圆括号                                                                     自左至右
                             [ ]                 下标运算符               
                             ->                 指向结构体成员运算符               
                             .                    结构体成员运算符       

       
2                          !                 逻辑非运算符                                1
                                                                                          (单目运算符)                    自右至左
                          ~                  按位取反运算符                 
                          ++                自增运算符               
                          --                  自减运算符               
                          -                   负号运算符               
                          (类型)             类型转换运算符               
                          *                  指针运算符               
                          &                  取地址运算符               
                          sizeof             长度运算符               

殊不知,这种归纳是完全错误的。而且恰恰由于《C程序设计》是所谓的“主流用书”,其错误带来的影响也是广泛普遍的和灾难性的。(google或百度一下“所有的单目运算符具有相同的优先级”,你就会知道我是不是在夸大其词危言耸听)。

    为了揭露“所有的单目运算符具有相同的优先级”的错误,下面首先按照这种错误的说法进行一个实验。
    我们都知道,对于
    int i;
来说,&i是求得一个指向i的指针(注意这里的“&”是一个“单目运算符”),&i的数据类型显然是“int *”。
    如果对“int *”类型的表达式“&i”做“(int *)”类型转换运算(可能显得有点无聊)
     (int *)&i
得到显然还是“&i”——值和类型都没有任何改变。
    按照“所有的单目运算符具有相同的优先级”这个错误的说法,由于“&” 和“(int *)”的结合性从右向左
    (int *)&i
这个表达式没有任何毛病,也不需要通过加“()”来明确运算对象。
    现在,再对
    (int *)&i
这个表达式做sizeof运算,由于sizeof也和(int *)同级(注意这是错误的),结合性从右向左,所以可以直接把sizeof写在(int *)&i 的左面,即
    sizeof (int *) & i
显然,这个表达式的运算结果和sizeof (int *)应该一模一样,因为(int *) & i的数据类型是(int *) 。
    然而,如果你在机器上跑一下下面的代码的话
  1. #include <stdio.h>

  2. int main( void )
  3. {
  4.   int i  ;
  5.   
  6.   printf(" %u \n" , sizeof (int *)     ) ;
  7.   printf(" %u \n" , sizeof (int *) & i ) ;
  8.    
  9.   return 0;
  10. }
复制代码
你很可能会惊讶地发现,两者并不相同。如果发现两者相同说明你人品可能太好了(这事情很难遇到),这时你可以给i一个初值比如2,再试一次,最终你一定会发现两个貌似“应该”相同的值却根本不相同。

    做为目睹了悖论产生过程的观众,我想你非常清楚,共同参与制造这个荒唐悖论的只有编译器、我和“主流用书”中的所谓“所有的单目运算符具有相同的优先级”的理论。所以如果你同意C语言本身应该是一个严密的逻辑体系的话,你应该能想到产生这个悖论的原因只能是三者之中至少有一个犯了错误。
    编译器BUG?你觉得可能吗?如此简单的表达式都算错,编译器厂家还怎么混?
    我的推理过程有错?可能吗?这比前一条更加没可能。
    所以,错误只可能出现在“所有的单目运算符具有相同的优先级”这句话上。

    这句话的究竟有什么错误呢?错误就在于,“(类型)”这种运算符的优先级其实低于sizeof 和 一元 & 运算符。由于类型转换运算符的优先级低于sizeof,所以
    sizeof (int *) & i
不可能表示sizeof ((int *) & i)这样的含义,因为C语言的优先级和结合性规定只容许运算符作用于高级表达式或同级表达式。
    且住,“高级表达式”和“同级表达式”是啥你可能看不懂,因为这是我为了叙述方便发明的新术语。不过咱不是那种发明术语而不做任何解释管杀不管埋之学风恶劣之人。我解释一下,高级表达式是指相对某运算符来说,只出现更高优先级运算符的表达式或基本表达式。例如,对于(二元)+运算符来说,3*5就是高级表达式。同级表达式是指相对某运算符来说,不出现更低级运算符的表达式。例如对于(二元)+运算符,2+3就是它的同级表达式,但a=b就不是,因为这里出现了=,=的优先级比+要低。
    举例来说,由于(二元)+的优先级低于(二元)*,那么可以对
    3*6 进行 + 运算:3*6+2
      再如由于+和+优先级相同,所以可以对3+6做+运算
    3+6+2
      但不可以对3+6做*运算
    3+6*2
      虽然合法,但绝对不可能是(3+6)*2的含义
    当把一个运算符添加在高级表达式或同级表达式上是还必须遵守结合性的规定,由于(二元)+运算的结合性是从左到右,所以只能加到高级表达式或同级表达式的右边。当然还得给它加的另一个操作数,这个操作数必须是高级表达式。
    由于 (int *) & i 不是 sizeof 的高级表达式或同级表达式,所以希望对它做sizeof运算必须加括号,写成sizeof ((int *) & i)。(注:((int *) & i)构成了一个基本表达式)
而写成 sizeof (int *) & i 的话,就如同前面在3+6加上*一样不是(3+6)*2的含义而是3+(6*2)的含义一样,表达的可能是另一种含义,这个含义是
    ( sizeof (int *) )  &  i
这里&其实是二元&运算。既然是&是二元&运算,前面代码中没有给 i 初值 显然不妥,正确的代码是:
  1. #include <stdio.h>

  2. int main( void )
  3. {
  4.   int i = 3 ; //whatever
  5.   
  6.   printf(" %u \n" , sizeof (int *)     ) ;
  7.   printf(" %u \n" , sizeof (int *) & i ) ;
  8.    
  9.   return 0;
  10. }
复制代码

Rank: 9Rank: 9Rank: 9

帖子
6459
主题
56
精华
0
可用积分
46818
专家积分
0
在线时间
3661 小时
注册时间
2009-12-09
最后登录
2012-05-23
论坛徽章:
0
发表于 2011-07-13 17:01:40 |显示全部楼层
不支持,还是别趟浑水了
hellioncu 发表于 2011-07-13 16:56



    WHY?
拾荒者

Rank: 5Rank: 5

帖子
1690
主题
42
精华
0
可用积分
6216
专家积分
15
在线时间
1709 小时
注册时间
2008-08-16
最后登录
2012-05-23
论坛徽章:
0
发表于 2011-07-13 17:06:03 |显示全部楼层
建议先参考一下C-Faq和C专家编程里面的一些内容先……其实现在优秀的C书已经很多了,问题在于因为某些体制的原因学生接触不到这些书= =所以嘛……

Rank: 9Rank: 9Rank: 9

帖子
6459
主题
56
精华
0
可用积分
46818
专家积分
0
在线时间
3661 小时
注册时间
2009-12-09
最后登录
2012-05-23
论坛徽章:
0
发表于 2011-07-13 17:13:22 |显示全部楼层
回复 5# starwing83


    非常感谢

Rank: 5Rank: 5

帖子
1441
主题
240
精华
0
可用积分
5242
专家积分
0
在线时间
3192 小时
注册时间
2008-10-18
最后登录
2012-03-05
论坛徽章:
0
发表于 2011-07-13 17:21:59 |显示全部楼层
, 对这个没啥热情. 错就错呗,谬就谬呗,  计算模型定下了, (正则, dfa),(上下文无关,下推自动机), 这些理论如果
都定型了,其他都不怎么重要.

这么极致的关注c, 小的方面, you got it.. 大的有方面, you miss it.
努力理解,努力热爱,努力追求,努力明白:为什么?这样?规律?规则?枷锁?突破?囚徒?人?社会?意识?黑天鹅?

Rank: 9Rank: 9Rank: 9

帖子
6459
主题
56
精华
0
可用积分
46818
专家积分
0
在线时间
3661 小时
注册时间
2009-12-09
最后登录
2012-05-23
论坛徽章:
0
发表于 2011-07-13 17:35:01 |显示全部楼层
,
小的方面, you got it.. 大的有方面, you miss it.
peidright 发表于 2011-07-13 17:21

我一点也没看出这两种情况存在必然的逻辑关系
在下愚昧,尚请详细说明一下

我也听过一句话
叫“细节决定成败”
敢问这句话应该怎样理解

Rank: 5Rank: 5

帖子
1441
主题
240
精华
0
可用积分
5242
专家积分
0
在线时间
3192 小时
注册时间
2008-10-18
最后登录
2012-03-05
论坛徽章:
0
发表于 2011-07-13 17:35:55 |显示全部楼层
从另一方面,我也有这样一个意见:
规则是怎样(策略),并不重要,到是为什么制定这样的規则(机制),这种似乎更为重要.

更恶烈的情况,不了解机制的情况下相信规则,更加容易恶杀创造.

就优先级这个例子,我会把所有不确定的加上括号.
但是, 了解  有些上下文无关文法固有的奇义性,了解如和把有些文法,转化为无奇义性
的文法,更好一点.
努力理解,努力热爱,努力追求,努力明白:为什么?这样?规律?规则?枷锁?突破?囚徒?人?社会?意识?黑天鹅?

Rank: 9Rank: 9Rank: 9

帖子
6459
主题
56
精华
0
可用积分
46818
专家积分
0
在线时间
3661 小时
注册时间
2009-12-09
最后登录
2012-05-23
论坛徽章:
0
发表于 2011-07-13 17:43:59 |显示全部楼层
从另一方面,我也有这样一个意见:
规则是怎样(策略),并不重要,到是为什么制定这样的規则(机制),这种似乎更为 ...
peidright 发表于 2011-07-13 17:35



    哦,那我非常欢迎您能谈谈为什么类型转换运算的优先级比sizeof和(一元)&运算的优先级低
    热门内容推荐
您需要登录后才可以回帖 登录 | 注册

北京皓辰网域网络信息技术有限公司. 版权所有 京ICP证:060528号 北京市公安局海淀分局网监中心备案编号:1101082001
广播电视节目制作经营许可证(京) 字第1234号 中国互联网协会会员  联系我们:
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP