免费注册 查看新帖 |

Chinaunix

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

[C] 请教C语言牛人----关于int与unsigned int的奇怪问题 [复制链接]

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
81 [报告]
发表于 2010-06-14 00:47 |只看该作者
回复 78# guoruimin

完全遵守标准是不能写出优秀的东西的。 就连lua, 从5还是4开始也忍不住加入了模块。

标准的一个作用是指导
其实标准都太难, 是写给做编译器的人看的。
适合程序员看的, the c programming language 的附录就很不错。
还有一本叫"c reference"还是什么的。
下面还是把这些笼统的称为"标准"。


通过这些材料, 了解哪些操作是平台相关的, 例如:上面的int和char互转, 或者是位域。
绝对不使用这些不可移植特性并不是研究标准的目的

有些不可移植操作能带来显著的效率提升, 比如我上面举的例子, 那就用。
有些平台api要求使用这些操作, 而且这些api是没有等价替代的, 例如ls说的, 需要超出C语言类型的对齐
那当然不能因噎废食, memalign, posix_memalign, 或者valloc等, 那就用。

该用就用, 只要能获得好处。

而有些时候, 其实只要稍微花些功夫, 就可以避免违反标准,而且不会有任何坏处。我上面也有举例。
那不妨就花点精力改了, 就减少一个可移植障碍。


为了编写可移植程序, 需要尽可减少平台相关的特性, 并将它们压缩到较小的范围内。
而什么是平台相关特性? 这就需要标准来指导。

比如x86会自动处理未对齐整数。
如果没有其他平台上的体验, 就很有可能造成错觉: 上面char*到int*, 只要空间足够就是安全的。
标准可以纠正这种错觉, 使得即使没有其他平台上的体验, 也能意识到这操作有问题。
应该将对它们的使用限制到最小范围, 并且在新的平台上首先测试这些操作。
那么, 就可以通过一小段测试代码, 发现问题是因为arm需要严格对齐。
然后重写一小部分代码。

如果没有标准做这种指导, 这种不安全的操作就很有可能散布于所有代码中。
而且很难发现究竟是什么导致了问题(因为问题没有明显的主次之分)。


你看, 并不需要了解对齐的知识(并不是所有人都有必要去了解这个, x86上可能也只有用mmx的人才会有深刻教训
但依然可以先知先觉地将移植代价降低


对于其他的特性, 也是同样: 哪些特性是在移植时可以较少考虑, 甚至完全不考虑的; 哪些是必须考虑的?
标准可以将这些特性分出主次, 并给予指导。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
82 [报告]
发表于 2010-06-14 00:57 |只看该作者
回复 80# 没本

研究标准的目的在于:

1. 哪些差异性是可以不研究汇编代码就可以断言的

只要有一个符合标准的C编译器, 那无论什么平台, 行为一定是这样。

2. 对不符合标准的C编译器

可以选择更老的C标准(如基于c89而不是c99编程)。
甚至可以从c89中选出一个子集, 它们会被实现得很好。
而剩余部分, 可能就是通常所说的: 语言的阴暗层面。

一句话,  在移植(甚至是移植之前), 标准可以作为一种指导:
哪些特性被支持得很好, 哪些被支持得不够好。
通过这种指导, 在架构和实现, 然后移植到其他平台时出现各种问题和权衡时, 都能分出主次


平台确实是千差万别的
因为平台是千差万别的, 企图仅使用它们的交集编写程序是幼稚的。
因为平台是千差万别的, 将一种平台上的行为视为所有平台上应有的行为, 并能解决其他平台上的问题, 是自大的。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
83 [报告]
发表于 2010-06-14 01:03 |只看该作者
有的时候是不可能对齐的。
typedef struct packet_t {
    unsigned char  type;
    unsigned char  cmd;
    unsigned int   param;
    unsigned short len;
    unsigned char  buf[];
} packet_t;
只能针对不同的编译器加不同的对齐参数。

guoruimin 发表于 2010-06-14 00:08

  1. typedef struct {
  2.       unsigned char bytes[n];
  3. } packet_t;
  4. enum {
  5.       type = ...,
  6.       cmd  = ...,
  7.       param = ...,
  8.      ...
  9. };

  10. packet_t* p = ...
  11. &p[type],
  12. &p[cmd],
  13. &p[param],
复制代码
需要编译器的对齐参数?

论坛徽章:
0
84 [报告]
发表于 2010-06-14 01:43 |只看该作者
回复 82# OwnWaterloo

我没反对你谈的这些东西啊,而且你提到有些本身就是我陈述过的观点吧。

就这个帖子而言,通过16楼贴出来的汇编,我在20楼就做了回答,楼主的程序没出现ok,是因为last_jobid这个变量被编译器优化掉了,last_jobid+1没有被计算,直接被编译器硬编码为-1。
这个就是编译器优化实现的版本差异性造成的。事实上无论GCC 4.3.x还是GCC 4.5.0产生的优化代码,都因为对常量赋值做了优化,产生了与C源程序中的程序员原本意图不符的代码。对这个问题的研究讨论,我认为对于掌握GCC x86编译器某个版本的代码生成特点是有意义的。

你所以觉得没意义,是因为有符号数运算溢出结果不确定,结论在标准里没有,不能跨平台。

但是,这也不能构成反对我或者楼主探索这个问题在特定平台特点版本编译器的特征的理由吧。各人有各人的研究自由。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
85 [报告]
发表于 2010-06-14 03:23 |只看该作者
这个就是编译器优化实现的版本差异性造成的。事实上无论GCC 4.3.x还是GCC 4.5.0产生的优化代码,都因为对常量赋值做了优化,产生了与C源程序中的程序员原本意图不符的代码。对这个问题的研究讨论,我认为对于掌握GCC x86编译器某个版本的代码生成特点是有意义的。
没本 发表于 2010-06-14 01:43


你真的明白你在说什么吗?
平台*编译器*编译器版本*优化选项 —— 这是什么样的组合?

反正我是不敢写这种连不同的优化选项都会产生不同逻辑的代码。
我觉得更有意义的事是避免写出这种代码。


即使你老厉害, 真的能知晓这无数组合中的不同, 并且在论坛上显摆一下。
请你摸着良心说, 显摆的快感过后, 真的应该采取这样的方式?
也许你觉得这样会让你有继续显摆的机会, 正好可以再爽一次?

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
86 [报告]
发表于 2010-06-14 03:45 |只看该作者
总有人喜欢去分析结构的sizeof。
总有人喜欢去分析C++虚表的布局。
总有人喜欢去分析C代码产生出的汇编。
……

作为研究没错, 也有自由。 但这不是合理的解决实际问题的方式。
解决实际问题应该避免依赖于这些程序员不可控也不应该控制的方面。

---------------

通常都不需要依赖于结构大小是多少, 虚表在什么位置, 汇编代码会如何生成。
否则绝对会被不加节制、无限扩大的复杂性击败。

-------------------------

对于确实需要控制的地方, 往往又不应该是用结构或者C代码去解决的地方。

当确实需要一个精确的layout时, 直接定义unsigned char 数组是稍微笨拙;
但绝对可以减少无数麻烦的方式。
而不是定义一个结构, 去猜或用各种编译选项去控制。

当确实需要虚表的构造时, 直接使用函数指针的结构体也会减少无数麻烦。

当确实需要特定行为, 直接写汇编。


------------------------

我解决问题的办法:
1. 要么依赖高级抽象, 并且清楚的了解抽象提供的契约、协议不依赖协议之外的东西
2. 要么直接使用底层的设施

没有第3条。
任何行为都是精确控制的。


哪有写一段C代码, 并分析由它生成的汇编代码, 再根据汇编代码来调整C代码的(正确性的)事。

-----------------------

一句话总结你俩的问题: 太依赖于经验, 并只依赖于经验; 没想将经验总结为较好的方法论

论坛徽章:
0
87 [报告]
发表于 2010-06-14 03:47 |只看该作者
本帖最后由 没本 于 2010-06-14 03:49 编辑

回复 85# OwnWaterloo


    我也没鼓励任何人写出这样的代码,既然有人弄出这样的代码了,借机研究一下有何不可。
回避问题可不是解决问题之道。你担保你的代码运行时就不会发生标准未定义时的情况么?那你公司的QA人员真是省力了,都不用设计各种临界条件下的测试用例,因为你都替他们考虑到了。他们只要按软件的正确流程走一遍,验证功能正常就行了,绝不会出现意外。因为基于C语言标准的程序是净室软件工程,每万行代码不足一个bug。或者你们就不需要QA?

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
88 [报告]
发表于 2010-06-14 03:49 |只看该作者
回复 87# 没本

我从来没有将自己的代码交给QA的想法。 (虽然可能有这么个形式)
我都解决不了的问题, 他们也甭想解决。
所以我的代码都是自己测的……

你应该知道QA其实是什么样的人, 所以我并没有说大话。

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
89 [报告]
发表于 2010-06-14 03:58 |只看该作者
回复 87# 没本

总之: 应该使用较为明确的契约去编程。

我忘了, 你是总结过的。 我帮你回忆回忆:

回复  Kallawa
实际上对任何可移植的程序,基本上也是与我相同的观点。保持代码的简单比弄出一些语言的高深用法,对我更有意义。
没本 发表于 2010-05-26 20:16


也许是因为汇编在你看来并不高深, 所以其实也没有违反你总结的方法?

论坛徽章:
0
90 [报告]
发表于 2010-06-14 04:12 |只看该作者
本帖最后由 slackware12 于 2010-06-14 04:14 编辑

回复 60# guoruimin


nothing
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP