免费注册 查看新帖 |

Chinaunix

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

月经结贴 -- 《Segmentation Fault in Linux》 [复制链接]

论坛徽章:
0
11 [报告]
发表于 2009-12-21 18:53 |只看该作者
原帖由 OwnWaterloo 于 2009-12-21 18:18 发表
char a[] = "hello";
char* p;

for ( p = a+sizeof(a)-2; p>=a; p-- )
      printf("%c\n", *p );

与:

for ( p = a+sizeof(a)-2; p!=a; p-- )
      printf("%c\n", *p );


效果是一样的: 如 ...

嘿嘿,我理解你的意思,觉得标准都规定了好了,为什么就不好好按标准写呢。
这里面一是有历史原因,一是不方便。
比如你这里这个例子
for ( p = a+sizeof(a)-1; p!=a /* or p>=a */; ) {
      --p;
      printf("%c\n", *p );
}
先--p就把空字符去掉了,很可能别人原意就要打印这个空字符。p!=a,又少打一个h,所以我在写这个例子时都是跳出循环后再打一次。
标准规定的是完美情况,但现实中要想写出完美的代码时很难的,所以我说有一些既成事实的标准。比如说按标准写:
int a = 70000;
严格来说这样写是不对的,因为不知道这个int的长度,如果是2字节,它就溢出了。怎么办呢,写成
int32_t a = 70000;
是保险的。这意味着我们就不随便使用int、short、long之类的变量的,一定要#include <stdint.h>。但那么多的教材、那么多的书籍都在这样用,
从一学C语言就开始这样用,突然就告诉说这样不对,不严格,在某些情况下会出错。但实际上99%的时间我们写不是跨平台程序,要把所有细节都严格按照标准,
基本上就寸步难行了。所以对于这种情况,人们大都follow的那些即成事实的标准。也正是因为有这些既成事实的标准了,所以几乎也不会出现你说那种特殊的编译器,出现了也不会被市场接受。

历史原因也有很多,比如大家都知道宏不好,定义常量会污染名字空间,应该用enum。写函数没有类型检查,应该用inline函数。但它就用了这么久了,那么多知名项目都在用,都这样用,所以也有很多人follow。

OwnWaterloo你可能是个追求完美的人,但现实中大部分时候都不是完美的。我倒不是鼓励大家不遵守标准,我只是从我的观点陈述一种事实,即它可能不符合标准,但它99%的时间不会出错,至于如何抉择,就看个人了。

>>算了, 别人写的代码是否可移植关我鸟事 ……   大家爱怎么写就怎么写好了……
至于这个嘛,你也别急,现实中和别人意见相左的情况很多,其实我们只要了解了别人的观点,理解他的出发点,然后在心中坚持自己的理念即可。至于别人怎么做怎么想,那真是管我们鸟事

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
12 [报告]
发表于 2009-12-21 19:15 |只看该作者

回复 #11 zx_wing 的帖子

我是故意把空字符去掉的……   上面2份代码是-2 ……
要输出空字符的话:
for ( p = a+sizeof(a)/*-1 把这个-1去掉*/; p!=a /* or p>=a */; ) {
      --p;
      printf("%c\n", *p );
}

那么, 在逆向遍历这个问题上, 遵守标准的写法, 还会造成什么不方便么?
如果还有, 请指出, 再讨论有没有可以遵守标准也能写出的方法。

其实, 多出的那一行也是可以去掉的……  只是……   我写了你就明白只是什么了……
for (T* p = a + n; p!=a; )
      --p, process( *p );


事实标准确实重要。 现实生活中其实依赖的是事实标准。 我的观点是: 不应该没有任何理由地、 无故地违反标准
所以遇见这种问题, 我一般都先问case。 而不是说"一定不能那样做"。
如果标准能解决这个case, 那还有什么理由去依赖未定义行为呢?
如果标准不能, 或者不够高效(也算是不能), 这种情况我自己都会去违反标准……



关于那个帖里22楼的那种yin 荡的、会主动crash程序的C实现, 我又想了想, 应该只会出现在想象中, 而不会实际出现。
因为这不符合C的逻辑 —— C语言是不会做多余的事情以提供保姆功能的。
但underflow确实是有可能的。 这依然是因为C语言的逻辑 —— 不会做多余的事情以提供保姆功能 —— 检查offset的溢出并相应的修改segment就是一种多余的保姆功能。

所以, 逆向遍历的case, 这么写也应该没问题 —— 在正常的C编译器上:
for (T* p = a + n; p-- != a; )
      process( *p );

有可能溢出, 但正常的C编译器不会提供检测溢出并且crash程序的功能。
熟悉msvc的同学说话前先仔细看清楚了: 这里的溢出仅仅是算术运算的溢出, 并没有到溢出的单元。/RTCs检查的不是这种情况。
如果真有检查算术溢出的C编译器 ……  我相信没人会去用的。

论坛徽章:
0
13 [报告]
发表于 2009-12-21 19:25 |只看该作者
原帖由 OwnWaterloo 于 2009-12-21 19:15 发表
我是故意把空字符去掉的……   上面2份代码是-2 ……
要输出空字符的话:
for ( p = a+sizeof(a)/*-1 把这个-1去掉*/; p!=a /* or p>=a */; ) {
      --p;
      printf("%c\n", *p );
}

那么, 在逆 ...

是我看错了,你把 --p提出来了。

这样是很好,但一般人不会相到这样写。就像你后来说了,人们不会接受指针算术溢出会导致错误。

[ 本帖最后由 zx_wing 于 2009-12-21 19:29 编辑 ]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
14 [报告]
发表于 2009-12-21 19:29 |只看该作者

回复 #13 zx_wing 的帖子

当真?

论坛徽章:
0
15 [报告]
发表于 2009-12-21 19:30 |只看该作者
原帖由 OwnWaterloo 于 2009-12-21 19:29 发表
当真?

你回的真快,我刚改你就回了。见上

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
16 [报告]
发表于 2009-12-21 19:35 |只看该作者

回复 #13 zx_wing 的帖子

原帖由 zx_wing 于 2009-12-21 19:25 发表
就像你后来说了,人们不会接受指针算术溢出会导致错误。

人们不会接受的是编译器主动检查溢出而导致错误。

因为编译器没有检测溢出而导致的语意错误, 是程序员的责任。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
17 [报告]
发表于 2009-12-21 19:42 |只看该作者

回复 #13 zx_wing 的帖子

原帖由 zx_wing 于 2009-12-21 19:25 发表
但一般人不会相到这样写


用idx逆向遍历 —— 自从某次错误之后 —— 我都是这么写的
for (size_t idx = size; idx-- ; )
      process( a[idex] );


用prt逆向遍历……  也是在那个帖里才头一次考虑这个问题, 以后我会选择:
for (T* ptr = a + size; ptr != a; ) {
      --ptr;
      process( *ptr );
}

for (T* ptr = a + size; ptr-- != a; )
      process( *ptr );

for (T* ptr = a + size; ptr != a; )
      --ptr, process( *ptr );


之一

论坛徽章:
0
18 [报告]
发表于 2009-12-21 22:54 |只看该作者
原帖由 zx_wing 于 2009-12-21 18:53 发表

嘿嘿,我理解你的意思,觉得标准都规定了好了,为什么就不好好按标准写呢。
这里面一是有历史原因,一是不方便。
比如你这里这个例子
for ( p = a+sizeof(a)-1; p!=a /* or p>=a */; ) {
      --p;
    ...


我做嵌入式开发比较多,为了能够在16位机和32位机之间更好的移植,代码中的 int 都会写成 int32_t 这样子的。

论坛徽章:
0
19 [报告]
发表于 2009-12-21 22:57 |只看该作者

回复 #1 zx_wing 的帖子

最近我也出了一系列段错误,其中一个比较深刻,大意如下:???标示不用关注。
...
struct ??? * x = malloc( ??? );
char * p = x->data;
x = realloc( x , ??? );
??? = *p;

[ 本帖最后由 happyzlz 于 2009-12-21 23:08 编辑 ]

论坛徽章:
0
20 [报告]
发表于 2009-12-22 10:58 |只看该作者
好文章,收藏,传阅
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP