免费注册 查看新帖 |

Chinaunix

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

[C++] C++的cout就是个杯具 [复制链接]

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
71 [报告]
发表于 2010-03-14 23:44 |只看该作者
本帖最后由 chenzhanyiczy 于 2010-03-14 23:45 编辑
回复  chenzhanyiczy

注意, 我提出的都是假设。
是为了举出一个可能的例子, 将C标准为什么会这么规定 ...
OwnWaterloo 发表于 2010-03-14 22:51



你要理解我说的这句话意思:

假如某平台需要4字节对齐,那么不是所有的char指针都能转换为Int指针,必须是4字节对齐的char指针才能转换,否则就SIGBUS了

那么转换为int指针时就无所谓信息丢失了,因为本身char指针的后2 bit本身就是无用的


我的意思是,在某平台下,如果char -> int ,分为两种情况:
1.char指针没有4字节对齐,那么转换成int时就出现SIGBUS
2.char指针有4字节对齐,那么转换成int时,不会出现信息丢失。本身char指针的后2 bit本身就是无用的(即4字节对齐)

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
72 [报告]
发表于 2010-03-14 23:47 |只看该作者
三次函数调用比一个switch走三次要效率高吗?这个我真没测过,现代CPU上函数调用要不要保存寄存器状态?咱不是计算机专业的,不是很清楚...还有一个疑问就是三次cout导致陷入内核的次数会不会多于printf,也就是三次cout会不会导致缓存上的低效?求牛人给解释下
reiase 发表于 2010-03-13 19:43


我说的"大switch" 个某一个operator <<(T const&) 指的是目标代码的大小。
因为你提到了空间效率。

cout的每次调用, 还有printf的每次调用都不一定会进入内核, 还有缓冲呢。

时间上, 确实没见过有cout体系实现得比printf体系要快。
那是因为cout体系有更多的功能。

如果仅仅是格式化功能:
1. 使用重载,编译时分派
2. 使用格式化字符串,运行时分派

后者肯定比前者慢。

如果是一次仅输出一个域相比对比一次输出多个域, 请看46楼的例子。


scanf的返回值是成功读取数据的个数,但是在cin链上,你用状态检查函数能够检测出第几个读取出错吗?每次调用完cin,要不要都调用状态检查函数得瑟下?或者借用某位老兄的例子,多线程环境下,你用状态检查函数,能检查到啥?要不要先上个锁再调用状态检查函数?生产环境只能用异常吧,不然cin不声不响少读个数据reiase 发表于 2010-03-13 19:43


首先, 多线程根本不是问题。
cin只是会麻烦一些, 需要使用线程局部存储来保存最近一次的状态。
而scanf的返回值是栈上的, 本来就是线程私有的。
可以这么搞:

  1. stream_with_local_status tmp(cin);
  2. tmp<< ... << ... << ...
  3. tmp.status;
复制代码
错误处理, 嘿嘿。 来吧, 我在和你讨论错误处理。

既然你提到scanf, 给你个需求: 如何读入一个行? 行大小未知。

  1. // delimit为"行"结束符
  2. char* getline(FILE* f, int delimit);
复制代码
既然提到scanf, 就不得不再提一下sscanf。 再给你一个需求, C89中的。
返回的不是成功读取的个数吗?  我怎么知道读取的字符数?

  1. char const* s = "12abc12";
  2. int i1, i2;
  3. int r = sscanf(s, "%d%d", &i1, &i2);
复制代码
i2肯定读取不到了, 那我如何知道丢弃s中的哪个字符, 并从那开始重新读取i2?

C99我不太了解, 加入了一个%n。 我猜想可能应该是这么使用:
(如果用错, 请指出)

  1. char const* input = ...;
  2. char const* input_end = input + strlen(input);

  3. int i1, i2, n;
  4. char const* s = input;
  5. int r = 0;
  6. while ( r= sscanf(s, "%d%n%d%n", &i1, &n, &i2), r==0 ) {
  7.       if ( s == input_end ) {
  8.             // 输入错误
  9.       }
  10.       ++s; // 忽略一个字符
  11. }

  12. if ( r == 1 ) {
  13.       s += n1;
  14.       while ( r= sscanf(s, "%d", &i2), r == 0 ) {
  15.             if ( s == input_end ) {
  16.                 // 输入错误
  17.             }
  18.             ++s; 忽略一个字符
  19.       }
  20. }

  21. 如果顺利, 读取完毕。
复制代码
考虑错误处理, 如果需要一次性读取3个? 读取4个? 读取5个? 这代码应该怎么写?
你可以写写看, 看会不会变成读取一个, 检查一个; 还是说,依然是一次性读取完毕。

综上, 你总喜欢拿printf/scanf体系的长处去和cout/cin体系的短板相比。
公平吗? printf/scanf的短板你看出来了吗?

还有, 不要想当然。
比如不要想当然的认为每次cout调用就会陷入内核, 比如scanf的错误处理会比cin简单。

—————— python那个例子

对, 这确实很爽~_~
但是, 你用python作例子,去证明C中的printf? 不合适吧?

python确实会很爽, template字符串错了也不会咋样。
printf的template, 错了就等着悲剧吧。

另外, python的print也是可以不使用格式化字符串的

  1. print 'a=',a, 'b=', b
复制代码
OO当然是C++中最不起眼的特性。 你看, ACE不是把事情搞复杂了?

论坛徽章:
0
73 [报告]
发表于 2010-03-14 23:50 |只看该作者
本帖最后由 zx_wing 于 2010-03-14 23:58 编辑
回复  zx_wing

看吧, 楼上就提出了一种编译器。
如果他指的确实是转换是就会出错, 而不是访问时, 那 ...
OwnWaterloo 发表于 2010-03-14 22:54



    chenzhanyiczy可能是没把自己的观点讲清楚,或者是他理解错了SIGBUS。

首先对编译器来说没有signal这个概念,所以无法在编译阶段引发SIGBUS的。
其次即使有编译器将一个char指针转换int指针进行对齐而导致char的最低2位丢失,也只有在读写这个地址时才会引发SIGBUS(实际也不会,因为既然编译器都把char对齐到Int了,那这个访问最多得到的是错误的内容,或者引发一个segfault)。
SIGBUS有多种情况,chenzhanyiczy这里指的是在RISC架构CPU上引发的为对齐错误,但必须访问内存才能产生。所以这个例子和我们讲的那个没有关系。

论坛徽章:
0
74 [报告]
发表于 2010-03-14 23:57 |只看该作者
你要理解我说的这句话意思:

假如某平台需要4字节对齐,那么不是所有的char指针都能转换为Int指针 ...
chenzhanyiczy 发表于 2010-03-14 23:44



你理解错OwnWaterloo所举得C标准所描述的意思了。

C标准指的是char指针在转换非void指针时,不保证指针本身不被改变,也就是所谓的信息丢失。举个例子:
char* s = "hello";
int* i = (int*)s;

假设s指向的地址是0x80484b5,那么按照C标准,就有可能有一种编译器,在编译时将s对齐到4字节,这时i的值就变成0x80484b0了。

这种情况是在编译阶段发生的。

而不是你所指的在运行阶段,i指向0x80484b5,访问i指向的内容时,发生的未对齐错误。

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

我觉得是你要理解我说的话的意思。

我所说的是一种可能的实现方式
这种实现方式是符合标准的: 保证对齐严格的指针转换到对齐宽松的指针不会丢失信息, 而且可以再转换回去。
而且这种实现方式下, 将对齐宽松指针转化为对齐严格指针就会有问题。
提出这种假设, 是为了便于理解标准中关于指针的描述

你要说它错, 需要证明这种实现是不可能, 在所有平台下都不可能
企图以一个平台上的行为去证明一种可能性是不符合逻辑的。

要说明一种可能性是存在的, 只需要举出一个实际例子。
要说明一种可能性是不存在的, 你需要证明所有平台下都不存在这样的可能性。
理解了?


对69楼的代码, i386下无论哪一行都不会产生总线错误,cpu自己就会处理未对齐访问。
你又怎么说呢?

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
76 [报告]
发表于 2010-03-15 00:25 |只看该作者
要说明一种可能性是存在的, 只需要举出一个实际例子。
要说明一种可能性是不存在的, 你需要证明所有平台下都不存在这样的可能性。
理解了?

-->请看黑体的
我的意思是,在某平台下,如果char -> int ,分为两种情况:
1.char指针没有4字节对齐,那么转换成int时就出现SIGBUS
2.char指针有4字节对齐,那么转换成int时,不会出现信息丢失。本身char指针的后2 bit本身就是无用的(即4字节对齐)

我没有说没有这个可能


对69楼的代码, i386下无论哪一行都不会产生总线错误,cpu自己就会处理未对齐访问。
你又怎么说呢?

--> 确实,不是所有的cpu 会出现错误,这时对于特定平台来说的

论坛徽章:
2
青铜圣斗士
日期:2015-11-26 06:15:59数据库技术版块每日发帖之星
日期:2016-07-24 06:20:00
77 [报告]
发表于 2010-03-15 00:48 |只看该作者
-->请看黑体的
我的意思是,在某平台下,如果char -> int ,分为两种情况:
1.char指针没有4字节对齐,那么转换成int时就出现SIGBUS
2.char指针有4字节对齐,那么转换成int时,不会出现信息丢失。本身char指针的后2 bit本身就是无用的(即4字节对齐)
chenzhanyiczy 发表于 2010-03-15 00:25


嗯, 你这句话是对的。

说"某平台下是这样", 只要找出一个平台是这样, 就算证明了那个命题。
相反, 证明那个命题是假命题, 需要证明的是"所有平台都不是这样"。

如果我要说你这个说法是错误的, 那就必须证明所有的平台下, 都不会出现问题。
我就不能拿"i386上不会出现总线错误作为论据, 来证明你所说的是错误的" —— 这是不符合逻辑的。

而且你确实说了这么一个平台是这样处理的。
那就算证明了这个命题了。

btw: 具体是哪个平台? 什么编译器? 会在转换时检查? 而不是解引用时?



同样, 我说的也是一种假设, 一种可能性, 某个平台上怎么怎么。
所以, 用一种平台上的行为去证明一种可能性是不符合逻辑的。
只是我也没能找出这么一个平台, 来证明我说的那个命题罢了。

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
78 [报告]
发表于 2010-03-15 00:53 |只看该作者
具体的平台?忘了,老早之前好像遇到过,不知mips会不会

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

那是我理解错了……

成天只玩i386, 而且还多半是在Windows上……
感觉这些问题很抽象……
要是有各种古怪的机器给我玩就好了……

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:50:28
80 [报告]
发表于 2010-03-15 08:53 |只看该作者
此外我觉得无论cout如何不好用,但在C++里,你没办法Printf一个string类啊
zx_wing 发表于 2010-03-13 12:54


可以啊,有c_str()。
  printf("%s", a_string.c_str());




抛砖引玉很成功,各位大牛继续。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP