如何提高com接口操作导出 excel word 效率的效率 c

> 问题详情
为Word文档设置保护口令时,最多可以输入的字符数是A.8个B.11个C.15个D.18个
悬赏:0&答案豆
提问人:匿名网友
发布时间:
为Word文档设置保护口令时,最多可以输入的字符数是A.8个B.11个C.15个D.18个请帮忙给出正确答案和分析,谢谢!
为您推荐的考试题库
您可能感兴趣的试题
1在Word中,对段落进行“分散对齐”操作,可以选择“格式”工具栏中的A.按钮B.按钮C.按钮D.按钮2下列关于Word分栏排版功能的叙述中,正确的是A.最多可以设三栏B.各栏的宽度可以不同C.只能应用于整篇文档D.各栏之间的间距是固定的
我有更好的答案
相关考试课程
请先输入下方的验证码查看最佳答案
图形验证:
验证码提交中……
找答案会员
享三项特权
找答案会员
享三项特权
找答案会员
享三项特权
选择支付方式:
支付宝付款
郑重提醒:支付后,系统自动为您完成注册
请使用微信扫码支付(元)
支付后,系统自动为您完成注册
遇到问题请联系在线客服QQ:
请您不要关闭此页面,支付完成后点击支付完成按钮
遇到问题请联系在线客服QQ:
恭喜您!升级VIP会员成功
常用邮箱:
用于找回密码
确认密码:Word教程:熟练掌握常用操作,提高工作效率
原作者:长空|
来自:电脑爱好者
&查看 : ( 10229 )
&评论 : ( 0 )
摘要 : 本例主要介绍了如何设置Word常用操作选项,快速提高工作效率,作者通过多年的工作经验总结了这篇文章,相信会给朋友们带来一定的帮助~~
这些年来,此类介绍文章比比皆是,高手对此早以不屑一顾,但想起当年的我,还是忍不住要写一下,以解众多新手之急切心情。我想要是用一些实际的例子来说明一些事情,肯定比平平板板的文字更容易理解,如果大家能结合实际操作更能加深印象起到举一反三的效果。
1.自定义快捷键:
例1:工具栏快捷键
在每个文档编辑过程中,最频繁改动的是&字体、段落、页面设置&等,每次改动都得从菜单中选择(当然字体、段落也可以单击右键来实现,页面设置可以双击&标尺&来实现),但在表格中字体、段落的右键可就不好使了(如图1)
偏偏这两样在表格中又是经常使用的,难道每使用一次都要多点N次鼠标?得想个办法:单击&格式&选择&自定义&出现对话框&&命令&在&类别&中(白框)选&格式&,然后在&命令&中(灰框)选择&字体&或&段落&,(如图2)
按住左键,把它拖到工具栏中合适的位置,这样就可以在工具栏中建一个快捷按钮。照上面的方法,找其它几项试一下,会发现许多意想不到的惊喜:表格中的&中部居中& 、&中部居中左& 等这些按键效果都是&杠杠地&。什么,你看一下我的?好吧,好人作到底,送佛送到西,我把我的工具条给你看一下,就看一下啊。(图3)(点击下图看大图)
例2:符号栏快捷键 同样的道理,想一下命令可以有快捷键,符号可不可以有?太多太多的同学们抱怨WORD里的&符号栏&品种单一、门类不全,我就不在此一一列举了啊(一副很是自得的样子,哈哈哈&&)。下面我们就自己制作一个符号工具栏:单击&工具&&&自定义&出现对话框,点&新建&,(如图4)
在&工具栏名称&中键入&自定义符号&,拖动&自定义符号&栏到窗口中的合适位置,再次单击&工具&&&自定义&,(如图5)
选择&类别&框中&所有命令&,&命令&框中选择&symbol&拖至&自定义符号&栏中,此时会出现WORD中的&符号&窗口,选择您常用的符号点确定,&快捷键&就此建成了,如果它的名称不如意,可以单击右键,出现菜单,然后自己命名一个名字,选择它的显示图标样式:&默认样式&更改按钮图标&编辑按钮图标&自己画一个图标,以后可以随时欣赏您的涂鸦之作了(如图6)
用同样的方法就可以把您常用的符号添加到工具栏中,以备日后之用。顺便说一下&图5&中&保存于&选项记着把你所建立的快捷键什么的都存在&Normal&这个模板中它的位置是C:\Documents and Settings\Administrator\Application Data\Microsoft\Templates建议把这个模板备份一下,万一日后格式化硬盘了什么的,就不用从头再来了。
说了这么多不知你是否理解了,下面还有一个方法可以练习一下。另一种&自定义符号&方法,先从视图中调出&自动图文集&(如果调出了&自动图文集&就可直接进行②操作):①视图-工具栏-点选&自动图文集&-②在文档中输入符号-创建&自动图文集&-工具-自定义-命令-自动图文集(如图5中画圈的)。
&2.宏的录制和应用:
1.&录制宏&简单的说就是把你的每一步操作都录制下来,每次有同样操作步骤的时候就可以一键搞定了。
例1:经常需要把&字体间距&设定成&加宽5磅&的。
工具-宏-点录制新宏-输入宏名-点工具栏(如图7)
拖动宏的图标到工具栏上适合位置-(关闭自定义对话框后就可以像平常一样操作让系统录制操作过程了,录制完后点一下&停止录制&。不要告诉我你不会设定字符间距,什么?我恨你!)格式-字体-字符间距-加宽5磅(如图8)
注意事项:
1、不要有多余的操作,例如撤消等。不行就多操作几遍等自己练熟了操作步骤再录制吗。 2、关于自己录制宏的名称和图标,可以参照第1节例2中的按钮图标制作方法。
WORD已经是一个非常成熟的软件了,在这里面几乎只有你想不到的,没有她做不到的,只要你深入的挖掘,她还会有许多奇妙的功能等待着你去发现。
3.新文档的默认值:
在使用WORD的时候经常会用到一些诸如:直线,图片等之类的东西,有时想要调整很小一点距离时很麻烦,按住CTRL键同时按上下左右箭头调整这样治标不治本。有方法如下:&页面设置&-&文档网格&-&绘制网格&然后如&图9&
进行设置基本就可以达到使用方便的要求了,当然可以自己根据需要设定数值。要想在以后的每个&新建文档&中应用这一设置,就必须按一下&默认&。同样,在&页面设置&中把文档的&页边距&、&纸型&文档中的&字体&等设定后点一下&默认&就可以在以后所有新文档中使用自己设定的数值了。
造字程序的用法。 在日常工作中,您肯定要碰到一些字库中没有的字,比如 &字,要想找到这个字其实也容易,到网上搞一个图片不就行了?可是要想让他像正常的字体一样,改变大小,间距等就会很麻烦,有时缩小后会看不清,那么就自己造一个矢量的字体吧。&
例如:字的制作。单击&开始&-&程序&-&附件&-&造字程序&。选择一个空白的&代码&(如图10)
点&确定&后点&窗口&-&参照&,输入&喜&点&字体&,选择一种合适的字体后点&确定&(如图11)
单击&矩形选择工具&选择&引用&窗口中的喜字拖到&编辑&窗口中并调整其大小,选择&编辑&&复制&,复制一份调整好大小的喜字,调整两个字符的位置(如图12)
(这里需要注意的是:在调整字体大小的时候,一定要一直按着鼠标不放,直到字体定型之后方可放开,如果你分两次或多次调整,字体的比例会发生变化影响效果)。然后用&橡皮檫&和&铅笔&工具修改最终效果如图13
单击&编辑&-&保存字符&-&文件&-&字体链接&-&与选定字体链接&选择一种字体-&确定&。字体制作完毕。想要用的时候,打开&字符映射表&选择字体类型-单击要使用的专用字符、&选定&和&复制&-在应用程序中点&粘贴&。
学习,从教程网开始!
部分带宽赞助
Copyright &
备案号:&&&&p&你能想到的,C语言都能搞,可以说是无所不能,把C学好,上手其他语言也会事半功倍。题主只是还没有入门,只看教程不动手永远学不会,推荐5个免费的C语言入门小项目,由易到难,开始动手做一些常见的小东西吧。&/p&&p&1.&a class=& wrap external& href=&///?target=https%3A///courses/75& target=&_blank& rel=&nofollow noreferrer&&C/C++ - C语言制作简单计算器&i class=&icon-external&&&/i&&/a&&/p&&p&用C语言做一个简单的计算器,进行加、减、乘、除操作。项目涉及的所有数学知识都很简单,但输入过程会增加复杂性。&/p&&p&&img data-rawheight=&345& data-rawwidth=&678& src=&/daa1a832d45da6cadb62fd168d8532f9_b.jpg& class=&origin_image zh-lightbox-thumb& width=&678& data-original=&/daa1a832d45da6cadb62fd168d8532f9_r.jpg&&2.&a class=& wrap external& href=&///?target=https%3A///courses/155& target=&_blank& rel=&nofollow noreferrer&&C/C++ - C语言制作2048&i class=&icon-external&&&/i&&/a&&/p&&p&2048是之前十分火爆的一款益智游戏。项目将使用 C 语言完成一个2048游戏。&/p&&img data-rawheight=&416& data-rawwidth=&715& src=&/d6cbd086d9a5ec5ee7de6_b.png& class=&origin_image zh-lightbox-thumb& width=&715& data-original=&/d6cbd086d9a5ec5ee7de6_r.png&&&p&3.&a class=& wrap external& href=&///?target=https%3A///courses/116& target=&_blank& rel=&nofollow noreferrer&&C/C++ - C语言版扫雷游戏&i class=&icon-external&&&/i&&/a&&/p&&p&扫雷是Window系统中自带的经典游戏。项目将使用 C 语言完成一个简单的扫雷游戏。&/p&&p&&img data-rawheight=&386& data-rawwidth=&690& src=&/048680efc0b5a20a0c3a_b.png& class=&origin_image zh-lightbox-thumb& width=&690& data-original=&/048680efc0b5a20a0c3a_r.png&&4.&a class=& wrap external& href=&///?target=https%3A///courses/126& target=&_blank& rel=&nofollow noreferrer&&C/C++ - C语言编写万年历&i class=&icon-external&&&/i&&/a&&br&&/p&本次课程将使用 C 语言完成一个简单的日历功能。输入相应的年/月即可看到当月的日历。&br&&img data-rawheight=&350& data-rawwidth=&797& src=&/496ab6c9ffebd991b24fc_b.png& class=&origin_image zh-lightbox-thumb& width=&797& data-original=&/496ab6c9ffebd991b24fc_r.png&&5.&a class=& wrap external& href=&///?target=https%3A///courses/313& target=&_blank& rel=&nofollow noreferrer&&C/C++ - C语言快速实现五子棋&i class=&icon-external&&&/i&&/a&&p&用最最简单的代码来实现五子棋游戏,帮助大家复习基础知识,了解一个项目的开发流程。&/p&&img src=&/v2-8cf4aa2be6a_b.png& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&/v2-8cf4aa2be6a_r.png&&&br&&p&收藏的童鞋们顺便点个赞吧:)&/p&
你能想到的,C语言都能搞,可以说是无所不能,把C学好,上手其他语言也会事半功倍。题主只是还没有入门,只看教程不动手永远学不会,推荐5个免费的C语言入门小项目,由易到难,开始动手做一些常见的小东西吧。1.用C语言做一个简…
推荐Pelles C,德国人开发,Freeware, C2011, Windows-only。配上 Programming Windows 5th Edition是撸Win32 API神器。
推荐Pelles C,德国人开发,Freeware, C2011, Windows-only。配上 Programming Windows 5th Edition是撸Win32 API神器。
可以看一下我们团队在编写的开源书籍,里面介绍了nginx的实现,可以参考一下:&br&&a href=&///?target=http%3A//tengine.taobao.org/book/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&tengine.taobao.org/book&/span&&span class=&invisible&&/&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&&br&另外,有问题也可以到我们的邮件列表上问:&br&&a href=&///?target=http%3A//code.taobao.org/mailman/listinfo/tengine-cn& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&code.taobao.org/mailman&/span&&span class=&invisible&&/listinfo/tengine-cn&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&&br&另外我几年前还写过一个介绍的ppt:&br&&a href=&///?target=http%3A//www.slideshare.net/joshzhu/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&slideshare.net/joshzhu/&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a&nginx-internals
可以看一下我们团队在编写的开源书籍,里面介绍了nginx的实现,可以参考一下:
另外,有问题也可以到我们的邮件列表上问:
另外我几年前还写过一个介绍的ppt: nginx-internals
首先你需要学会lua(不仅仅是C语言水平的问题),这里的学会我指的是能用lua写个几千上万行业务代码,对lua有了一定的理解,再根据你自己理解找找对lua哪方面感兴趣,专门针对那方面去看lua的代码,比如函数调用是怎么实现的(以及与C语言怎么交互的)、lua的debug库是怎么提供hook指令执行的等等。你看云风那么多lua分析的文章都是这段时间关注GC就看GC的实现,那段时间关注string的实现就看string的相关代码。找到你关注的感兴趣的部分去看,比你在14588行代码(lua 5.2.3的代码,排除注释和空行)乱无头绪的看要好多了。&br&&br&如果你想通过看lua代码学习编译原理的知识,那自然就看词法分析、语法分析、代码生成及VM代码,这方面我曾写过三篇博客(&a href=&///?target=http%3A//airtrack.me/posts//lua%25E6%25BA%%25A0%%E6%259E%2590%25EF%25BC%%25B8%2580%25EF%25BC%2589& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&lua源码剖析(一)&i class=&icon-external&&&/i&&/a& 、&a href=&///?target=http%3A//airtrack.me/posts//lua%25E6%25BA%%25A0%%E6%259E%2590%25EF%25BC%%25BA%258C%25EF%25BC%2589& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&lua源码剖析(二)&i class=&icon-external&&&/i&&/a&、&a href=&///?target=http%3A//airtrack.me/posts//lua%25E6%25BA%%25A0%%E6%259E%2590%25EF%25BC%%25B8%2589%25EF%25BC%2589& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&lua源码剖析(三)&i class=&icon-external&&&/i&&/a&)。不过我不推荐通过lua源码来学习编译原理,因为很难在lua这种工业级的解释器里理清交杂在一起的语法分析、语义分析以及代码生成。lua本身是一个一遍式的编译器,我觉得对于初学者来说这是不好理解的,在这个一遍式的编译器里还交杂着GC和运行时报错的准备工作,另外一方面lua的代码变量太短,经常是一个字母,不好读(至少我是这么认为的),各个模块之间耦合也很大程度的影响理解。我觉得学习编译原理最好的方式是,先通看一遍编译原理,然后硬着头皮写一个渣编译器(解释器),这时候你再来看lua这块的代码会好很多。我在看lua代码之前,就是自己实现了一个lua的子集,我目前正在写第二版的实现(luna第二版:&a href=&///?target=https%3A///airtrack/luna& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&airtrack/luna · GitHub&i class=&icon-external&&&/i&&/a& 只是子集,没有metatable userdata coroutine等东西),luna的第一版我实现了一个渣一般的栈虚拟机,在看了lua的代码之后,我想实现一个寄存器虚拟机,于是写了第二版。在写第二版的时候有时候遇到某个问题,觉得我自己的想法实现成本太高时(运行时的时空代价),我就会看看lua是怎么实现的,比如运行时报错(f()函数调用,f本身不是函数的报错),而这时候我已经有过自己的思考,再去看lua的这块实现,看代码3-5分钟就看到了重点,醍醐灌顶,然后迅速的实现出来。其实到目前为止我都没有完整的看过lua的代码。&br&&br&另外lua的是一个工业级的解释器,它的很多实现方式是有效率考虑的(比如一遍式的编译),而且很多实现方面都是在它这个语言之下是很优的(也许是最优的),如果换做另外一门语言,是不能完全套用它的实现方式,当然原理是通的,所以我觉得关键还是理解实现后面的原理,不单单是看怎么实现的。
首先你需要学会lua(不仅仅是C语言水平的问题),这里的学会我指的是能用lua写个几千上万行业务代码,对lua有了一定的理解,再根据你自己理解找找对lua哪方面感兴趣,专门针对那方面去看lua的代码,比如函数调用是怎么实现的(以及与C语言怎么交互的)、lua…
从题主的提问来看,C应该也不是很好,不然不会提及 最近有兴趣,所以我觉得直接让你看那种比如Redis/Nginx的代码看起来有压力,所以我就推荐那种入门项目:&br&&ul&&li&&a href=&///?target=http%3A//tinyhttpd.sourceforge.net/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&tinyhttpd&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&///?target=http%3A//sourceforge.net/projects/cjson/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&cJSON&i class=&icon-external&&&/i&&/a&&/li&&/ul&最近网上有文章提到了他们,你可以参考:&br&&a href=&///?target=http%3A///1070.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&程序员最值得关注的10个C开源项目&i class=&icon-external&&&/i&&/a&
从题主的提问来看,C应该也不是很好,不然不会提及 最近有兴趣,所以我觉得直接让你看那种比如Redis/Nginx的代码看起来有压力,所以我就推荐那种入门项目: 最近网上有文章提到了他们,你可以参考:
&b&各种OJ刷题。&/b&&br&&ul&&li&POJ(&a href=&///?target=http%3A//poj.org/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Welcome To PKU JudgeOnline&i class=&icon-external&&&/i&&/a&)&br&&/li&&li&九度(&a href=&///?target=http%3A///& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&九度Online Judge,用代码记录你的成长之路!&i class=&icon-external&&&/i&&/a&)&br&&/li&&li&ZOJ(&a href=&///?target=http%3A//acm./changsha/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ZOJ :: Home&i class=&icon-external&&&/i&&/a&)&br&&/li&&/ul&其它:&i&(from quora)&/i&&br&&ul&&li&&a href=&///?target=http%3A///& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Programming Competition,Programming Contest,Online Computer Programming&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&///?target=http%3A///p/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Sphere Online Judge (SPOJ)&i class=&icon-external&&&/i&&/a&&br&&/li&&li&&a href=&///?target=http%3A///& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Programming Praxis&i class=&icon-external&&&/i&&/a&&br&&/li&&li&&a href=&///?target=http%3A//projecteuler.net/about& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Project Euler&i class=&icon-external&&&/i&&/a&&br&&/li&&li&&a href=&///?target=http%3A///& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&TopCoder, Inc. | Home of the world's largest development communityTopCoder, Inc. | Home of the world's largest development community&i class=&icon-external&&&/i&&/a&&br&&/li&&li&&a href=&///?target=http%3A///& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Codeforces&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&///?target=http%3A///& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&HackerEarth Beta&i class=&icon-external&&&/i&&/a&&br&&/li&&li&&a href=&///?target=http%3A///& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&The Python Challenge&i class=&icon-external&&&/i&&/a&&br&&/li&&li&&a href=&///?target=https%3A///& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&HackerRank&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&///?target=http%3A///& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&LeetCode&i class=&icon-external&&&/i&&/a&&/li&&/ul&&br&&br&&b&Computational Geometry (计算几何) &/b&&br&计算几何真是个计算机世界中的一朵奇葩,是我上的众多计算机课程中最优雅地将算法理论和应用结合起来的(邓sir也是我遇到最好的老师,cg project list:&a href=&///?target=http%3A//dsa.cs./%7Edeng/cg/project/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Project&i class=&icon-external&&&/i&&/a&)&br&一些CG的Demo:&br&&ul&&li&3D Convex Hull &a href=&///?target=http%3A//www.openprocessing.org/sketch/94632& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&openprocessing.org/sket&/span&&span class=&invisible&&ch/94632&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&&/li&&li&Triangulation &a href=&///?target=http%3A//www.eecs.tufts.edu/%7Emgolds07/triangulate/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Triangulate Star-Shaped Polygon&i class=&icon-external&&&/i&&/a&&/li&&li&Voronoi Diagram & Delaunay Triangulation &a href=&///?target=http%3A//www.cs.cornell.edu/home/chew/Delaunay.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Voronoi/Delaunay Applet&i class=&icon-external&&&/i&&/a&&br&&/li&&li&Trapezoidal Map &a href=&///?target=http%3A//cgm.cs.mcgill.ca/%7Eathens/cs507/Projects/2002/JukkaKaartinen/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Compunational Geometry&i class=&icon-external&&&/i&&/a&&/li&&/ul&例如,我们前几天做的一个CG的课程项目(Qt+opengl用于显示和交互核心是用C++写的):&br&&img src=&/e4de3e86577e5ffb1d70_b.jpg& data-rawwidth=&1434& data-rawheight=&715& class=&origin_image zh-lightbox-thumb& width=&1434& data-original=&/e4de3e86577e5ffb1d70_r.jpg&&&br&&br&------------------------------------------------------------------------------&br&即陶冶了情操又为以后找工作奠定了强大的基础。&br&------------------------------------------------------------------------------&br&做日常的项目会把自己陷入到一个苦逼程序员的定义中不可自拔,做oj会觉得自己很伟岸,嗯,是这样的。
各种OJ刷题。 POJ() 九度() ZOJ() 其它:(from quora)
更新完成。&br&&a href=&///people/1e2cccc3ce33& data-hash=&1e2cccc3ce33& class=&member_mention& data-editable=&true& data-title=&@Milo Yip& data-hovercard=&p$b$1e2cccc3ce33&&@Milo Yip&/a&
milo老师说了整个优化的大框架,那我来补充一点实践方面的知识好了,聊一下天涯明月刀OL的优化,下文把这个游戏简称天刀。这是一个大型mmorpg,pc平台,客户端程序员数量在25人以上,其中引擎程序员大约在10人不到。&br&天刀是我从业以来优化最久,投入最大的项目,没有之一。以前的AAA游戏,我们通常会有一个两个senior的程序员,进行数个月的优化,而天刀的优化,断断续续做了接近3年,长期来看平均有两个以上的senior程序员投入,整个引擎和游戏方方面面都做了好几轮优化。&br&优化的流程始于profiling,我们用过各种各样的工具,cpu性能方面包括比较大路一点的vtune,自制profiling工具,已经数个小众一点的基于sampler的cpu监测工具。为了监测各种卡顿,windows performance toolkit是最常用的利器,虽然相对难学点,但这是最好的查找卡顿的工具了,是windows平台上性能优化必须要掌握的工具。gpu性能方面gpa,perfhud用的比较多,中后期gpuview也很常用。至于为什么要用这么多不同的工具,主要是每个工具各有擅长,往往能看见其他工具不容易发现的盲区。&br&&br&来几个有趣的优化例子,看看天刀这里的优化幅度:&br&1,milo老师的tag math+visibility组件,理念在2015年已经不算先进,但令人惊讶的是组件的效率。参考的dice公司同样的技术,运行在ps3的spu,这样的计算密集型特性,经过milo的优化,运行在普通cpu上,毫无压力,在i3的入门级cpu上,依然只消耗低于2ms的cpu时间。这个技术甚至颠覆了传统场景管理技术。天刀这个大场景远视距的游戏,玩过的朋友可能知道,场景复杂度和可视距离,都是国内少见的,即使和国外游戏相比,也只有逊色于just cause,farcry等不多的游戏,但是天刀里面的场景管理,没有用4叉树或者8叉树,直接扔进底层visibility组件。。。当然visibility组件里面还是有一些简单的类似管理,把这一层管理放到底层之后,场景管理和移动物体变得无比方便,对引擎层完全透明了。visibilty组件如此高效,以致阴影、树木、反射,全部可以由它来裁剪,简洁优雅。&br&在天刀早期做完大地形后,粗粗用visibility裁剪一下,帧数直接翻倍。后期主城场景密密麻麻,用到了其中的遮挡裁剪,看不见的就不画,又没有gpu的oclussion culling的延迟。&br&&br&2,植被系统的优化。严格来说这不算优化,是一个特性。天刀植被用了speedtree,相当出色的中间件,基本一个美术就能把整个游戏需要的树全部建模出来了。于是我们就在考虑是不是可以在场景里面种满树,因为这个中间件也有类似的demo。但是结果并不令人满意,原生的技术在效率和质量上都不 够好。&br&开发同事在speedtree的基础上做了很多尝试和优化,效果被制作人几次拍死,最后终于达到了满意的质量,也就有了大家看见的漫山遍野得植被。远处树木本质上使用speedtree的billboard,但是在normal生成、树木根部和地形的融合等多方面做了很多尝试,对于树木建模,是多一些polygon,好降低fillrate(因为pre z可以裁剪掉后面的像素),还是用大一点的面,可以减少polygon,也做了细致的美术微调,找到了平衡。前后整个特性应该做了超过半年,初始效果做出来以后,在场景序列化、裁剪等方面又要做深度整合,而不能简单充用原先speedtree的整合方式。在远处使用billboard的树木,同事很创新的想出密度倍增的技巧,一下子就出现了震撼的全景植被效果。&br&天刀的植被目前来说,效果和效率应该是是顶尖的。我们在2014年给unreal引擎创始人tim sweeney展示的时候,他也表示这是他见过的最好的植被表现,能得到偶像君的肯定,团队也非常受鼓舞。更多细节我们今年下半年会有一个gdcc session,同事应该会介绍更多。&br&这个工作有一点值得注意,真正好的优化,是程序、美术等多团队共同努力的结果。在效果和效率上很多团队说起优化,就是程序定个指标,扔给美术去做,程序就不管了。这样做下去,很容易出现美术用力缩贴图减模型,效果一塌糊涂,帧数倒是没提高多少。真正好的优化,必须是多方一起坐下来,共同分析问题,一起解决,即使是纯美术的改动,也需要程序帮助定位问题,这样才更有针对性,才能把优化带来的质量损失降到最低。&br&&br&3,卡顿优化,shader cache收集系统&br&天刀一测二测得到了较好的性能方面反馈,一方面的确优化的还可以,另一方面由于我们花了非常多的精力在防卡顿上面,导致游戏里面的卡顿相对较少,有玩家反映帧数只有20左右,但也能顺利玩下来。由此可见,片面追求高帧数意义不大,去掉性能上的spike,会给玩家更好的体验。&br&卡顿原因多种多样,单独就可以是一个很大的话题。我分几个单独案例来说。&br&一个情况是shader cache,天刀使用了uber shader的机制,根据场景和人物材质不同,可以组合出多种多样的shader,开发早期会在构建版本的时候穷举所有参数组合把shader全部编译出来,存在版本里面。很快这个方式就没法用了,shader参数组合爆炸了,于是就用动态生成机制,根据参数组合去取shader,如果之前没有编译过就同步编译,然后把编译后的shader保存到cache文件,以后要用就可以直接load。之所以这里没有在后台用别的线程编译,主要原因还是不希望编译的过程中模型不显示造成显示上的瑕疵。但是这样做的话,如果遇到缺失shader,就会有几百ms的卡顿了。&br&开发过程中这个同步编译当然无妨,但是见玩家的时候可不能这样,事实上三测一开始就因为bug,cache没处理好导致卡顿乱七八糟,被玩家喷死了。我们需要做的就是给玩家的版本里面需要把所有的shader组合都编译出来。&br&07年做xbox360游戏的时候也遇到过一样的问题,当时的团队有足够的测试资源,我们的方案是把所有用到过的shader参数存在文本文件,每天测试人员会把所有的参数发给我,我运行一个脚本去掉重复,整合所有的shader参数,然后第二天构建版本的时候就可以用收集的参数来预先生成所有的shader了。&br&但这次天刀项目组规模比较大,用类似的方法收集比较累。&br&我写了个简单的小server,测试版本都会上传所有的shader参数组合到这个小server,这个server会定期合并参数,输出后就可以上传到版本里面,下一个版本就可以构建这些shader了。&br&通过这个方法,我们在整个团队不受到干扰的情况下,收集了所有的shader参数组合。同时如果一个shader太久没有被用掉,也会被server去掉,这样如果因为更新程序导致shader改变,那些废旧的shader会在一段时间以后被慢慢淘汰,避免了shader的无止境增加。&br&&br&4,卡顿优化,跨进程卡顿&br&有一阵子上线以后玩家表示卡得很,但只要删除cross组件(腾讯内部的一个通用组件),就会流畅很多。听到这个迷信的说法,大家都不以为然,自己测试一下,发现也没有重现。&br&可是过了一阵子,发现坊间这个传说越传越广,进一步测试,发现在主程或者群战的时候,的确有可能会有很多没发现的卡顿,这些都是我们开发版里面不能重现的。&br&开发同学用Windows performance toolkit查了很久,结论非常令人崩溃。&br&起源是Cross组件使用了内部的另一个登录组件,这个组件也被很多其他腾讯产品使用。每一帧cross更新的时候,这个登录组件都会去读一个系统的锁。如果在游戏内存占用量非常高的时候,这个系统锁的变量有可能被page out,于是引起了一个page fault,所以系统就会卡顿一下。我们内部的电脑都是SSD,所以page in也一般不是很慢,理论上也不应该卡啊。继续追查,发现出问题的机器上往往装了微云,微云经常读写硬盘,在多台电脑件同步数据。如果正好page in发生在读写数据的时候,就会卡了。换句话说,我们内部观察到的现象,是腾讯的微云读写一个文件,正好和游戏中那个系统级锁的page in过程重叠了,所以会卡。外部玩家如果用了其他腾讯服务,或者硬盘比较慢,也可能引起一样的问题。&br&解决方案就比较简单,把这块东西的update全扔到另一个线程就好了。&br&&br&就先讲四个案例吧。可以看见在这几个案例里面,查找问题、解决思路都各不相同,但共同特点都是在程序端做了非常多细致的工作,也有一些非常有创意的解决方法。在我看来,优化绝不仅仅是设一个budget,对美术资源的大小、polygon数量等等设好限制,然后push他们去减贴图简化模型。程序作为性能的主导者,有非常大的主动性,如果能有很多更有创意的实现方式,可以大大简化美术的工作,也把性能和效果推到更极限。
更新完成。
milo老师说了整个优化的大框架,那我来补充一点实践方面的知识好了,聊一下天涯明月刀OL的优化,下文把这个游戏简称天刀。这是一个大型mmorpg,pc平台,客户端程序员数量在25人以上,其中引擎程序员大约在10人不到。 天刀是我从业以来…
你开始欣赏到纯 C代码所带来的 “美感” 了,即简单性和可拆分性。代码是自底向上构造,一个模块只做好一个模块的事情,任意拆分组合。对于有参考的 OOP系统建模,自顶向下的构造代码抽象方法是有效率的,是方便的,对于新领域,没有任何参考时,刻意抽象会带来额外负担,并进一步增加系统耦合性,设计调整,往往需要大面积修改代码。&br&&br&有兴趣你可以读读《Unix编程艺术》,OOP的思维模式,是大一统的;C的思维模式,是分离的。前者方便但容易造成高耦合,后者灵活但开发开发太累。用 C开发,应该刻意强调 “简单” 和 “可拆分”。一个个象搭积木一样的把基础系统搭建出来,哪个模块出问题,局部替换即可。&br&&br&自底向上的开发模式,并不是从不站在大局考虑问题,而是从某个子系统具体实现开始,从局部迭代,逐步反思全局设计,刻意保持低偶合,一个模块一个模块的来,再逐步尝试组合。&br&&br&自底向上强调先有实践,再总结理论,理论反过来指导实践,又从实践中迭代修正理论。这和人类认识世界的顺序是一样的,先捕猎筑巢,反思自然是怎么回事,又发现可以生火,又思考自然到底怎么回事情。&br&&br&它的反面,是指大一统设计,你一开始用 UML画出整套系统的类结构,然后再开工设计。这种思维习惯,如果是参考已有系统做一个类似的设计,问题不大,全新设计的话,他总有一个前提,就是 “你能完整认识整个大自然”,就像人类一开始就要认识捕猎和筑巢还有取火一样。否则每次对世界有了新认识,OOP的自顶向下设计方法都能给你带来巨大的负担。&br&&br&所以有些人才会说:OOP设计习惯会依赖一系列设计灵巧的 BaseObject,然而过段时间后再来看你的项目,当其中某个基础抽象类出现问题是,往往面临大范围的代码调整。这其实就是他们使用自顶向下思维方法,在逐步进入新世界时候,所带来的困惑。&br&&br&当然也有人批判这种强调简单性和可拆分性的 Unix思维。认为世界不是总能保持简单和可拆分的,他们之间是有各种千丝万缕联系的,你一味的保持简单性和可拆分性,你会让别人很累。这里给你个药方,底层系统,基础组建,尽量用 C的方法,很好的设计成模块,随着你编程的积累,这些模块象积木一样越来越多,而彼此都无太大关系,甚至不少 .c文件都能独立运行,并没有一个一统天下的 common.h让大家去 include,接口其他语言也方便。&br&&br&然后在你做到具体应用时根据不同的需求,用C++或者其他语言,将他们象胶水一样粘合起来。这时候,再把你的 common.h,写到你的 C++或者其他语言里面去。当然,作为胶水的语言不一定非要是 C++了,也可以是其他语言。&br&-------------&br&PS: 这里主要在探讨 OOP存在的问题,并没有讨论嵌入式这种资源限制的情况,以及操作系统和底层等需要精确控制硬件和内存的情况,更没有讨论 C++在语言设计层面的事情。&br&&br&---
你开始欣赏到纯 C代码所带来的 “美感” 了,即简单性和可拆分性。代码是自底向上构造,一个模块只做好一个模块的事情,任意拆分组合。对于有参考的 OOP系统建模,自顶向下的构造代码抽象方法是有效率的,是方便的,对于新领域,没有任何参考时,刻意抽象会…
要不要黑一下 C++呢?呵呵呵。&br&------------------&br&咱们要有点娱乐精神,关于 C++的笑话数都数不清:&br&&br&笑话:C++是一门不吉祥的语言,据说波音公司之前用ADA为飞机硬件编程,一直用的好好的,后来招聘了一伙大学生,学生们说我靠还在用这么落后的语言,然后换成C++重构后飞机就坠毁了。&br&&br&笑话:什么是C++程序员呢?就是本来10行写得完的程序,他非要用30行来完成,并自称“封装”,但每每到第二个项目的时候却将80%打破重写,并美其名曰 “重构”。&br&&br&笑话:C容易擦枪走火打到自己的脚,用C++虽然不容易,但一旦走火,就会把你整条腿给炸飞了。&br&&br&笑话:同时学习两年 Java的程序员在一起讨论的是面向对象和设计模式,而同时学习两年 C++的程序员,在一起讨论的是 template和各种语言规范到底怎么回事情。&br&&br&笑话:教别人学 C++的人都挣大钱了,而很多真正用 C++的人,都死的很惨。&br&&br&笑话:C++有太多地方可以让一个人表现自己“很聪明”,所以使用C++越久的人,约觉得自己“很聪明”结果步入陷阱都不知道,掉坑里了还觉得估计是自己没学好 C++。&br&&br&笑话:好多写了十多年 C++程序的人,至今说不清楚 C++到底有多少规范,至今仍然时不时的落入某些坑中。&br&&br&笑话:很多认为 C++方便跨平台的人,实际编写跨平台代码时,都会发现自己难找到两个支持相同标准的 C++编译器。&br&---------------&br&&br&Q:那 C++为什么还能看到那么多粉丝呢?&br&A:其实是因为 Windows,因为 Windows的兴起带动了 C++,C++本来就是一门只适合开发 GUI的语言。&br&&br&Q:为何 C++只适合开发 GUI呢?&br&A:你看 Unix下没有 GUI,为啥清一色的 C呀?所有的系统级问题都能在 C里找到成熟的解决方案,应用级问题都能用其他高级语言很好地解决,哪里有 C++什么事情呀?&br&&br&Q:你强词夺理,Unix下也有 C++的项目呀。&br&A:有,没错,你任然可以用任何语言编写任何糟糕的代码。&br&&br&Q:别瞎扯了,你都在说些什么?连C++和 Windows 都扯到一起去了。&br&A:回想下当年的情景,一个大牛在教一群初学者如何编程。一边开发一边指着屏幕上说,你看,这是一个 Button,我们可以用一个对象来描述它,那是一个 panel我们也可以用一个对象来描述它,并且你们有没有发现,其实 Button和 Panel是有血缘关系的,你们看。。。这样就出来了。。。。下面的学生以前都是学着学校落后的教材,有些甚至还在用 turboc的 bgi库来画一些点和圆。哪里见过这么这么华丽的 Windows 界面呀。大牛说的话,象金科玉律一样的铭刻在自己幼小的心理。一边学着 Windows,一边发现,果然,他们都需要一个基类,果然,他们是兄弟关系,共同包含一些基本属性,可以放到基类去。他们越用越爽,潜意识里觉得因为 C++这么顺利的帮他们解决那么多界面问题,那看来 C++可以帮他们解决一切问题了。于是开发完界面以后,他们继续开发,当他们碰到各种设计问题时,反而认为肯定自己没有用好 C++。于是强迫自己用下去,然后就完蛋了。&br&&br&---------------&br&关于 C++的笑话我有一箩筐,各位 C++粉用不着对号入座。言归正传,为什么要黑 C++呢?谈不上黑不黑,我从94年开始使用 C++(先前是 C 和 Pascal),一路看着 C++成长壮大,用 C++写过的代码,加起来应该超过 10MB了吧,C++的各种宝典我也都读过,一直到 2004年开始切回 C,主要原因是发现很多没法用 C++思路继续解决下去的问题,或者说用
C++思路解决下去会很糟糕的问题。&br&&br&那时候()正是 C++满天飞的时候,言必称 C++,用必用模版,我跳出来说你们醒醒吧,别过火了,这个世界并不是都是抽象数据结构和算法就可以描述清楚的。于是很多人激动的跳出来说:“你没领会到 C++精髓,你根本都不会用 C++”。我问他们:“语言是用来解决问题的,如果一个语言学了三四年都会经常掉沟里,算好语言么?如果编写十多年 C++的程序员都很难掌握得了,这算好语言么”。他们又说:“语言是死的,人是活的”。&br&&br&我记得当时一位国内 C++大牛,为了纠正我的 “错误观点”,给我看过他写的一套十分强大的库,我打开一看,倒吸了一口冷气,全部是 .h文件。我只能回他三个字:“你牛逼”。当然这是一个极端的例子,那家伙后来终于也开始把 .h里面的东西逐步挪到
.cpp里面了,这是好事。&br&&br&当时和云风在一家公司,2004年新人培训时,他给新人布置了一个实现内存分配器的作业,批改作业的时候,他经常边看边问人家,“不够C++呀,你能不能百分之百OOP?”,“1%的 C都不要留”。我当时在公司内部邮件列表里面发过关于 C++的问题,大部分人都表示:“你看没有C++我们怎么写3D引擎呢?”。我跟他们讲:“John Carmack直到 Quake3都还在用着 ANSI C,后来因为不得不支持 D3D,改用 C++了。为啥 C不能写 3D引擎了?”。他们告诉我:“你看,Point,就是个对象,Matrix也是个对象,那么多 Vector的代数计算,用 C++的算术重载是多么美妙的事情,三维世界就是对象的世界。”。&br&&br&确实当时客户端 GUI的话,只有 C++,图形引擎也只有 C++,这两个正是C++最强的地方,所以我也没和他们争辩,强迫他们承认 C也可以很漂亮的写图形,而且C写的可以写的很优雅。我又不是闲着没事情,何必去质疑人家的核心价值观呢,呵呵。当年我正在接手一个 C++项目,代码超过 800KB,每次崩溃都需要花费很长时间去定位,项目中大量的前后依赖,改一个地方,前后要看好几处,一处遗漏,整个系统就傻逼了。我开始重构后,画了两个星期,将性能敏感的核心部分剥离出来用 C实现(代码量仅 200KB),然后导出 Python接口,用Python来完成剩下的部分,整个脚本层代码量只有 150KB。整个世界清爽了,整个 C++项目原来的工期为 2个程序员四个月,我一个人重构的时间加起来就 1.5个月,而且代码量比远来少了两倍还多,各种奇特的 BUG也一扫而尽。我看看左边的 800KB一团乱麻的 C++代码,再看看右边整洁的 300多 KB 纯 C + Python,琢磨着,这个项目干嘛不一开始就这么做?&br&&br&&b&跨语言接口&/b&&br&&br&现代项目开发,不但需要更高的性能,而且需要更强大的语言描述能力。而 C++正处在一个尴尬的地方,比底层,它不如 C能够精确的控制内存和硬件,各种隐式构造让你防不胜防;比描述能力,比快速业务开发和错误定位,它又赶不上 Python, Ruby, Lua等动态语言,处于东线和西线同时遭受挤压和蚕食的地步。&br&&br&很快,&a href=&tel:& class=&&&&/a&年左右,其他项目组各种滥用 C++的问题开始显现出来:当时脚本化已经在工程实践中获得极大的成功,然而某些项目一方面又要追求 100%的 C++,另一方面又需要对脚本导出接口,他们发现问题了,不知道该怎么把大量的 C++基础库和接口导给 Lua。&br&&br&C的接口有各种方便的方式导给脚本,然而整个项目由一群从来就不消于使用脚本的cpp大牛开发出来,当他们要吧cpp类导出接口给脚本时,他们设计了一套牛逼的系统,lua自动生成机器码,去调用c++的各种类,没错,就是c++版本的cffi或者ctypes。他为调用vc的类写了一套机器码生产,又为调用gcc的类写了一套代码生成。那位cpp大牛写完后四处炫耀他的成果,后来他离职了,项目上线一而再再而三的出现无可查证的问题,后来云风去支援那个项目组,这套盘根错节的c++项目,这套盘大的代码自生成系统深深的把他给恶心到了。后来众所周知云风开始反C++,倡导回归C了,不知道是否和这个项目有关系。&br&&br&于是发现个有趣的现象,但凡善于使用脚本来提高工程效率的人,基本都是C加动态语言解决大部分问题(除了gui和图形),但凡认为c++统治宇宙的人很多都是从来没使用过脚本或者用了还不知道该怎样去用的人。&br&&br&凭借这样的方法,我们的产品同竞争对手比拼时,同样一个功能,同样的人力配置,竞争对手用纯C++要开发三月,我们一个月就弄出来了,同样的时间,对手只能试错一次,我们可以试错三次。后来,据我们招聘过来的同事说,竞争对手也开始逐步降低 C++的比例,增加 java的比例了,这是好事,大家都在进步嘛。&br&&br&&b&ABI的尴尬&/b&&br&&br&ABI级别的 C++接口从来没有标准化过,以类为接口会引入很多隐藏问题,比如内存问题,一个类在一个库里面实例化的,如果再另外一个库里面释放它们就有很多问题,因为两个动态库可能内存管理系统是不一样的。你用这里的 allocator分配一块内存,又用那里的
allocator去释放,不出问题才怪。很多解决方法是加一个
Release方法(比如 DX),告诉外面的人,用完的时候不要去 delete,而是要调用 Release。项目写大了各个模块隔离成动态库是很正常的,而各种第三方库和自己写的库为追求高性能引入特定的内存管理机制也是很正常的。很多人不注意该调用release的地方错写成delete就掉沟里去了。更有胜者跨 ABI定义了很多inline方法的类,结果各种隐式构造和析构其实在这个库里生成,那个库里被析构,乱成一团乱麻。C就清晰很多,构造你就调用fopen,析构你就fclose,没有任何歧义。其实C++的矛盾在于&b&一方面承认作为系统级语言内存管理应该交给用户决定&/b&,&b&一方面自己却又定义很多不受用户控制的内存操作行为&/b&。所以跨 ABI层的c++标准迟迟无法被定义出来,不是因为多态 abi复杂,而是因为&b&语言逻辑出现了相互矛盾&/b&。为了弥补这个矛盾,C++引入了operator new,delete,这new/delete重载是一个补丁并没从逻辑上让语言变得完备,它的出现,进一步将使用者拖入bug的深渊。&br&&br&其实今天我们回过头去看这个问题,能发现两个基本原则:跨abi的级别上引入不可控的内存机制从语言上是有问题的,只能要靠开发者约定各种灵巧的基类和约定开发规范来解决,这个问题在语言层是解决不了的;其次你既然定义了各种隐式构造和析构,就该像java活着动态语言一样彻底接管内存,不允许用户再自定义任何内存管理方法,而不是一方面作为系统极语言要给用户控制的自由,一方面自己又要抢着和用户一起控制。&br&&br&因此对象层 ABI接口迟迟无法标准化。而纯 C的 ABI不但可以轻松的跨动态库还能轻松的和汇编及各类语言融合,不是因为C设计多好,而是C作为系统层语言没有去管它不该管的东西。当年讨论到这个话题时 C++大牛们又开始重复那几句金科玉律来反驳我:“语言只是招式,你把内功练好,就能做到无招胜有招,拿起草来都可以当剑使,C++虽然有很多坑,你把设计做好不那么用不就行了”。我说:本来应该在语言层解决好的事情,由于语言逻辑不完备,将大量问题抛给开发者去解决极大的增加了开发者的思维负担,就像破屋上表浆糊一样。你金庸看多了吧,武术再高,当你拿到一把枪发现子弹不一定往前射,偶尔还会往后射时,请问你是该专心打敌人呢?还是时刻要提防自己的子弹射向自己?&br&&br&&b&系统层的挫败&/b&&br&&br&C++遭受挫败是进军嵌入式和操作系统这样靠近硬件层的东西。大家觉得宇宙级别的编程语言,自然能够胜任一切任务,很快发现几个问题:&br&&ul&&li&无法分配内存:原来用 C可以完全不依赖内存分配,代码写几千行一个 malloc没有都行。嵌入式下处理器加电后,跳到特定地址(比如起始地址0),第一条指令一般用汇编来写,固定在0地址,就是简单初始化一下栈,然后跳转到 C语言的 start函数去,试想此时内存分配机制都还没有建立,你定义了两个类,怎么构造呀?资源有限的微处理器上大部分时候就是使用一块静态内存进行操作。C++写起来写爽了,各种隐式构造一出现,就傻了。&br&&/li&&li&标准库依赖:在语言层面,&b&C语言的所有特性都可以不用依赖任何库就运行&/b&,这为编写系统层和跨平台跨语言代码带来了很方便的特性。而C++就不行,我要构造呀,我要异常呀,你能不给我强大的运行时呢?什么你还想用 stl?不看看那套库有多臃肿呀(内存和代码尺寸)。&br&&/li&&li&异常处理问题:底层开发需要严格的处理所有错误返回,这一行调用,下一行就判断错误。而异常是一种松散的错误处理方式,应用层这么写没问题,系统层这么写就很狼狈了。每行调用都try一下和 C的调用后if判断结果有什么区别?C++的构造函数是没有返回值的,如果构造内部出错,就必须逼迫你catch构造函数的异常,即便你catch住了,此时&b&这个实例是一个半初始化实例,你该怎么处理它呢?&/b&于是有人把初始化代码移除构造函数,构造时只初始化一下变量,新增加一个带返回的init函数,这样的代码写的比C冗余很多。何况硬件中断发生时,在你不知道的情况下,同事调到一些第三方的库,你最外层没有把新的exception给 catch住,这个exception该往哪里抛呀?内存不够的时候你想抛出一个 OutOfMemoryException,可是内存已经不够了,此时完全无能力构造这个异常又该怎么办呢?&br&&/li&&li&处理器兼容:C++的类依赖基地址+偏移地址的寻址方式,很多微处理器只有简单的给定地址寻址,不支持这样一条语句实现BASE+OFFSET的寻址,很多C++代码编译出来需要更多的指令来运算地址,导致性能下降很多,得不偿失。&br&&/li&&li&隐式操作问题:C的特点是简单直接,每行语句你都能清楚的知道会被翻译成什么样子,系统会严格按照你的代码去执行。而用C++,比如 str1 = str2 + &Hello& + str3; 这样的语句,没几个人真的说得清楚究竟有多少次构造和拷贝,这样的写法编写底层代码是很不负责任的,&b&底层需要更为精细和严格的控制,用C语言控制力更强&/b&。&/li&&/ul&当然,说道这里很多人又说,“C++本来就是 C的超集,特定的地方你完全可以按照C的写法来做呀。没人强迫你构造类或者使用异常呀”,没错,按 Linus的说法:“&b&想要用 C++写出系统级的优秀的可移植和高效的代码,最终还是会限于使用 C本身提供的功能,而这些功能 C都已经完美提供了,所以系统层使用 C的意义就在于在语言层排除 C++的其他特性的干扰&/b&”。&br&&br&很多人都记得 Linus在 2007年因为有人问 Git为什么不用 C++开发炮轰过一次C++。事实上2004年 C++如日中天的时候,有人问 Linux内核为何不用 C++开发,他就炮轰过一次了:&br&&blockquote&实际上,我们在1992年就尝试过在Linux使用 C++了。很恶心,相信我,用C++写内核是一个 “BLOODY STUPID IDEA”。事实上,C++编译器不值得信任,1992年时它们更糟糕,而一些基本的事实从没改变过:&br&&br&- 整套 C++异常处理系统是 “fundamentally broken”。特别对于编写内核而言。&br&- 任何语言或编译器喜欢在你背后隐藏行为(如内存分配)对于开发内核并不是一个好选择。&br&- 任然可以用 C来编写面向对象代码(比如文件系统),而不需要用 C++写出一坨屎来。&br&&br&总得来说,对任何希望用 C++来开发内核的人而言,他们都是在引入更多问题,无法象 C一样清晰的看到自己到底在写什么。&/blockquote&&br&C++粉丝们在C++最火热的时候试图将 C++引入系统层开发,但是从来没有成功过。所以不管是嵌入式,还是操作系统,在靠近硬件底层的开发中,都是清一色的 C代码,完全没有 C++的立足之地。&br&&br&&b&应用层的反思&/b&&br&&br&STL出来后,给人一种 C++可以方便开发应用层逻辑的错觉。由于很多语言层不严密的事情,让STL来以补丁的方式完成,于是很多以为可以象写 java一样写 C++的初学者落入了一个个的坑中。比如 list.size(),在 Windows下vc的 stl是保存了 list的长度的,size()直接 O(1)返回该变量,而在gcc的 stl中,没有保存 list长度,size()将搜索所有节点,O(n)的速度返回。&br&&br&由于语言层不支持字符串,导致 std::string实现十分不统一,你拷贝构造一个字符串,有的实现是引用,才用 copy-on-write的方法引用。有的地方又是 new,有的实现又是用的内存池,有的实现线程安全,有的实现线程不安全,你完全没法说出同一个语句后面到底做了些什么(见孟岩的《&a href=&///?target=http%3A//blog.csdn.net/myan/article/details/1777230& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Linux之父话糙理不糙&i class=&icon-external&&&/i&&/a&》)。&br&&br&再比如说我想使用 hash_map,为了跨平台(当你真正编写跨平台代码时,你很难决定目标编译器和他们的版本,想用也用不了 unordered_map),我很难指出一种唯一声明 hash_map的方法,为了保证在不同的编译器下正常的使用 hash_map,你不得不写成这样:&br&&div class=&highlight&&&pre&&code class=&language-c&&&span class=&cp&&#ifdef __GNUC__&/span&
&span class=&cp&&#ifdef __DEPRECATED&/span&
&span class=&cp&&#undef __DEPRECATED&/span&
&span class=&cp&&#endif&/span&
&span class=&cp&&#include &ext/hash_map&&/span&
&span class=&n&&namespace&/span& &span class=&n&&stdext&/span& &span class=&p&&{&/span& &span class=&n&&using&/span& &span class=&n&&namespace&/span& &span class=&n&&__gnu_cxx&/span&&span class=&p&&;&/span& &span class=&p&&}&/span&
&span class=&n&&namespace&/span& &span class=&n&&__gnu_cxx&/span& &span class=&p&&{&/span&
&span class=&n&&template&/span&&span class=&o&&&&&/span& &span class=&k&&struct&/span& &span class=&n&&hash&/span&&span class=&o&&&&/span& &span class=&n&&std&/span&&span class=&o&&::&/span&&span class=&n&&string&/span& &span class=&o&&&&/span& &span class=&p&&{&/span&
&span class=&kt&&size_t&/span& &span class=&n&&operator&/span&&span class=&p&&()(&/span& &span class=&k&&const&/span& &span class=&n&&std&/span&&span class=&o&&::&/span&&span class=&n&&string&/span&&span class=&o&&&&/span& &span class=&n&&x&/span& &span class=&p&&)&/span& &span class=&k&&const&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&n&&hash&/span&&span class=&o&&&&/span& &span class=&k&&const&/span& &span class=&kt&&char&/span&&span class=&o&&*&/span& &span class=&o&&&&/span&&span class=&p&&()(&/span& &span class=&n&&x&/span&&span class=&p&&.&/span&&span class=&n&&c_str&/span&&span class=&p&&()&/span& &span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&p&&};&/span&
&span class=&p&&}&/span&
&span class=&cp&&#else&/span&
&span class=&cp&&#ifndef _MSC_VER&/span&
&span class=&cp&&#include &hash_map&&/span&
&span class=&cp&&#elif (_MSC_VER & 1300)&/span&
&span class=&cp&&#include &map&&/span&
&span class=&cp&&#define IHAVE_NOT_HASH_MAP&/span&
&span class=&cp&&#else&/span&
&span class=&cp&&#include &hash_map&&/span&
&span class=&cp&&#endif&/span&
&span class=&cp&&#endif&/span&
&span class=&cp&&#ifdef __GNUC__&/span&
&span class=&n&&using&/span& &span class=&n&&namespace&/span& &span class=&n&&__gnu_cxx&/span&&span class=&p&&;&/span&
&span class=&k&&typedef&/span& &span class=&n&&hash_map&/span&&span class=&o&&&&/span&&span class=&kt&&uint32_t&/span&&span class=&p&&,&/span& &span class=&n&&XXXX&/span&&span class=&o&&*&&/span& &span class=&n&&HashXXXX&/span&&span class=&p&&;&/span&
&span class=&cp&&#else&/span&
&span class=&n&&using&/span& &span class=&n&&namespace&/span& &span class=&n&&stdext&/span&&span class=&p&&;&/span&
&span class=&k&&typedef&/span& &span class=&n&&hash_map&/span&&span class=&o&&&&/span&&span class=&kt&&uint32_t&/span&&span class=&p&&,&/span& &span class=&n&&XXXX&/span&&span class=&o&&*&&/span& &span class=&n&&HashXXXX&/span&&span class=&p&&;&/span&
&span class=&cp&&#endif&/span&
&/code&&/pre&&/div&如果有更好的跨平台写法,麻烦告诉我一下,实在是看不下去了。一个基础容器都让人用的那么辛苦,使得很多 C++程序员成天都在思考各种规范,没时间真正思考下程序设计。&br&&br&由于语言层要兼容 C,又不肯象 C一样只做好系统层的工作,导致当 C++涉足应用层时,没法接管内存管理,没法支持语言层字符串,没法实现语言层基础容器。所以需要借助一些 stl之类的东西来提供便利,但 stl本身又是充满各种坑的。且不说内存占用大,程序体积大等问题,当编译速度就够呛了。所以为什么 C++下面大家乐意重复造轮子,实现各种基本容器和字符串,导致几乎每个不同的 C++项目,都有自己特定的字符串实现。就是因为大家踩了坑了,才开始觉得需要自己来控制这些细节。stl的出发点是好的,但是只能简单小程序里面随便用一下,真是大项目用,stl就容易把人带沟里了,所以很多大点的 C++项目都是自己实现一套类似 STL的东西,这难道不是违背了 stl设计的初衷了么?&br&&br&语言层的缺失,让大家为了满足业务开发的快速迭代的需求,创造了很多很基础的设计灵巧的基类,来提供类似垃圾回收,引用计数,copy-on-write,delegate,等数不胜数的功能。每个项目都有一系列 BaseObject 之类的基础类,这样就引入一个误区,两年后你再来看你的代码,发现某个 BaseObject不满足需求了,或者你和另外一个项目 merge代码时,需要合并一些根本属性。图形和GUI这些万年不变的模型还好,应用类开发千变万化,一旦这些设计灵巧的基类不再适应项目发展时,往往面临着全面调整的代价。&br&&br&打开一个个 C++大牛们 blog,很多地方在教你 std::string的原理,需要注意的事项。map的限制,vector的原理,教你如何实现一个 string。这就叫 “心智负担”,分散你的注意力,这是其他语言里从来见不到的现象。战士不研究怎么上前线杀敌,天天在琢磨抢和炮的原理,成天在思考怎么用枪不会走火,用炮不会炸到自己,这战还怎么打?&br&&br&所以此后几年,越来越多的人开始反思前两年C++过热所带来的问题,比如高性能网络库 ZeroMQ作者 Martin Sustrik 的:《&a href=&///?target=http%3A///n/143021/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&为什么我希望用C而不是C++来实现ZeroMQ&i class=&icon-external&&&/i&&/a&》,比如云风的《&a href=&///?target=http%3A///2007/09/c_vs_cplusplus.html%23more& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&云风的 BLOG: C 的回归&i class=&icon-external&&&/i&&/a&》,比如引起热议的《&a href=&///?target=http%3A////why-c-is-not-back/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Why C++ Is Not &Back&&i class=&icon-external&&&/i&&/a&》。&br&&br&&b&全面被代替&/b&&br&&br&2008年以后,行业竞争越来越激烈,正当大家一边苦恼如何提高开发效率,一边掉到C++的各种坑里的时候,越来越多的应用开发方案涌现出来,他们都能很好的代替 C++。各行各业的开发者逐步相见恨晚的发现了各种更加优秀的方案:需要底层控制追求性能的设计,大家退回到 C;而需要快速迭代的东西大家找到各种动态语言;介于性能和开发速度之间的,有java,知乎上好像很多黑java的,语言是有不足,但是比起C++好很多,没那么多坑,真正考虑面向对象,真正让人把心思放在设计上。所以再黑也不能挡住 java在 tiobe上和 C语言不是第一就是第二的事实,再黑也挡不住 java在云计算,分布式领域的卓越贡献。&br&&img src=&/089e8cd5adfb2c98af4e396d_b.jpg& data-rawwidth=&708& data-rawheight=&447& class=&origin_image zh-lightbox-thumb& width=&708& data-original=&/089e8cd5adfb2c98af4e396d_r.jpg&&所以2005年以后,C++处在一个全面被代替的过程中:&br&&ul&&li&底层系统:进一步回归 C语言,更强的控制力,更精确的操作。&br&&/li&&li&网页开发:2006年左右,C++和 fastcgi就被一起赶出 web世界了。&br&&/li&&li&高性能服务:varnish, nginx, redis 等新的高性能网络服务器都是纯C开发的。&br&&/li&&li&分布式应用:2007年左右, C++被java和其他动态语言彻底赶跑。&br&&/li&&li&游戏服务端:2008年后进一步进化为 C 和 脚本,完全看不到胖C++服务端了。&br&&/li&&li&并行计算:2010年后,go, scala, erlang;而能方便同go接口的,是 C不是C++。&br&&/li&&li&游戏引擎:没错 C++和脚本,但是这年头越来越多的开源引擎下,引擎类需求越来越少。&br&&/li&&li&游戏逻辑:脚本&br&&/li&&li&多媒体:SDL纯C,ffmpeg是纯 C,webrtc的核心部分(DSP, codec)是纯C的。&br&&/li&&li&移动开发:早年C++还可以开发下塞班,现在基本被 java + objc + swift 赶跑了。&br&&/li&&li&桌面开发:Qt+Script, C#等都能做出漂亮的跨平台界面。且界面脚本化趋势,不需要C++了。&/li&&li&网页前端:JavaScript, Html5, Flash&/li&&li&操作系统:FreeBSD, Open Solaris, Linux, RTOS, Darwin(OS X 底层),都是纯 C&/li&&li&虚拟技术:qemu / kvm (云计算的基石)纯 C,Xen 纯 C&/li&&li&数据库:MySQL (核心纯C,外围工具 C++),SQLite 纯 C, PostgreSQL / BDB / unqlite 纯C&/li&&li&编译器:C/C++并存,不过编译器用脚本写都没关系,我还在某平台用 java写的 C/C++编译器&/li&&li&大数据:kafka, hadoop, storm, spark 都使用 Java&/li&&li&云存储:openstack swift python, hdfs java, 还有好多方案用 go&/li&&/ul&可以看出,即便 C++的老本行,GUI和图形(确实也还存在一些短期内 C++无法替代的领域,就像交易统里还有 COBOL一样),这年头也面临的越来越多的挑战,比如新发布的 Rust (&a href=&/question//answer/& class=&internal&&如何看待 Rust 的应用前景? - 知乎用户的回答&/a&)。可以发现,开发技术多元化,用最适合的技术开发最适合的应用是未来的趋势。而为这些不同的技术编写高性能的可控的公共组件,并轻松的和其他语言接口,正是 C语言的强项。所以不管应用层语言千变万化,对系统级开发语言C的需求还是那么的稳定,而这个过程中,哪里还有 C++的影子呢?&br&&br&&b&话题总结&/b&&br&&br&所以说未来的趋势是:C x 各种语言混搭 的趋势,从TIOBE上 C++的指数十年间下跌了三倍可以看出,未来还会涌现出更多技术来代替各个角落残存的C++方案,C++的使用情况还会进一步下降。所以题主问学习纯C是否有前途,我觉得如果题主能够左手熟练的掌握 C语言,培养系统化的思维习惯和精确控制内存和硬件的技巧;右手继续学习各种新兴的开发技术,能够应对各个细分领域的快速开发,碰到新问题时能左右开弓,那么未来工作上肯定是能上一个大台阶的。至于C++ 嘛,有时间看看就行,逼不得已要维护别人代码的情况下写两行即可。&br&&br&&b&故事分享&/b&&br&&br&古代用弓箭进行远距离攻击时,对射手要求较高,瞄准难度大,需要一直使劲保持准心。战斗中一个弓箭手开弓二十次就需要比较长的休息时间。弩的威力远胜于弓,秦弩的制造就如现代的自动步枪一般精密无二,它既可以延长射击,又可以精确瞄准。弩箭的发射速度更是弓箭的数倍,威力惊人。因为弩的操作非常简单,不需要射击技巧,平民很容易掌握它的使用方法。秦国靠着弩兵,在战争中取得了不少优势,被人称为 “虎狼之师”。&br&&br&日本投降时,天皇下罪己诏。很多士兵不愿意相信这时真的,找种种理由拒绝相信。有的士兵甚至以为天皇的广播是敌人诱降的把戏,于是躲到丛林里继续三五成群的收集情报,袭击可以攻击的目标,等待上司来给他们下达新命令。直到好几年后看到周围的人都穿着日常的便装了,而来巡山的 “敌人” 也从士兵变为了巡逻队,他们都还觉得这是敌人的伪装。而同时,德国战败时,最后的党卫军一直战斗到 1957年才肯投降。&br&&br&-----------------------------------------&br&很多人觉得 java慢,C++快java 10倍以上已经是上世纪的事情了,现代的 java 只比 C/C++慢 70%,C++连1倍都快不了 java。也不要觉得动态语言慢,javascript只比C/C++慢 2.7倍。luajit只比 C++慢 5.8倍。在 jit技术发展的今天,C++在性能上离动态语言/java的差距越来越小,可易用性和生产效率上的差距,却和动态语言/java 比起来越来越大。&br&&img src=&/ac9ac0a33fba9b5c00b7_b.jpg& data-rawwidth=&289& data-rawheight=&339& class=&content_image& width=&289&&&br&---------------------------&br&最后,补充一张图:&br&&img src=&/04c89a6e62ea65ae0b30e856e655a281_b.jpg& data-rawwidth=&745& data-rawheight=&396& class=&origin_image zh-lightbox-thumb& width=&745& data-original=&/04c89a6e62ea65ae0b30e856e655a281_r.jpg&&----
要不要黑一下 C++呢?呵呵呵。 ------------------ 咱们要有点娱乐精神,关于 C++的笑话数都数不清: 笑话:C++是一门不吉祥的语言,据说波音公司之前用ADA为飞机硬件编程,一直用的好好的,后来招聘了一伙大学生,学生们说我靠还在用这么落后的语言,然后…
推荐神器,我已经帮助不下5个文科生转行CS学数据结构了,绝对的深入浅出,谁用谁知道:&br&&br&&a class=& wrap external& href=&///?target=http%3A//p.nus.edu.sg/%7Estevenha/visualization/index.html& target=&_blank& rel=&nofollow noreferrer&&VisuAlgo - visualising data structures and algorithms through animation&i class=&icon-external&&&/i&&/a&
推荐神器,我已经帮助不下5个文科生转行CS学数据结构了,绝对的深入浅出,谁用谁知道:
已有帐号?
无法登录?
社交帐号登录
4371 人关注
855 条内容
2061 人关注
460 条内容
11983 人关注
515 条内容
2708 人关注
311 条内容
294 人关注
3282 条内容

我要回帖

更多关于 主板com接口 的文章

 

随机推荐