V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xiqingongzi
V2EX  ›  C

你们会向新人推荐 C++么?

  •  
  •   xiqingongzi · 2016-08-18 11:07:45 +08:00 · 11029 次点击
    这是一个创建于 3024 天前的主题,其中的信息可能已经有所发展或是发生改变。
    /t/300012 提问 C++ 的路线图,很多人都在劝我放弃
    但我是起意学 C++ 一方面是个人需要,另一方面是我的一个堂叔推荐我学 C++的。

    什么样的情况下你会推荐别人学 C++ 。什么情况下不推荐 C++?

    我觉得我堂叔不至于坑我吧....
    174 条回复    2016-08-26 13:03:57 +08:00
    1  2  
    lizon
        101
    lizon  
       2016-08-19 09:23:13 +08:00   ❤️ 3
    @FrankHB 你和我对学习这件事本身有不同的理解。

    你认为一开始就应该给初学者提供比较完善的语言和类型系统,让初学者知道什么是对的,什么是先进的,以最快速度学习享受到现在最先进的理论成果,更多的关注语言本身的描述能力。

    我认为一开始应该提供给初学者最大的自由,暴露合适的硬件细节,让初学者明白计算机到底在做什么。

    我说的奢俭,是指初学者一旦高级语言用爽了,屏蔽了本来应该了解的细节,很可能就呆在舒适区不想出来了,称他还没养成惰性,照脸糊 C 。

    我不明白学 C 的低效在哪,风险在哪。面向初学者的教材几乎全是 C ,算法教材也大部分是 C 代码或者类 C 伪码,各大高校开设的计算机课程必定有 C ,已经为初学者尽可能降低了学习曲线。

    初学者需要“学习 C ”,而不是“精通 C ”,不要去研究 C 语言本身的细枝末节,最主要是理解指针概念。很多初学者学 C ,从来没搞清楚过指针运作原理,就转投其他高级语言,我认为是有害的。不尝试从底层去理解语言特性,学习新语言就真的是换一种语言,重新学习新语言的语法特性,以往的经验没法融会贯通。为了逃避指针而去学高级语言的趁早转行,因为对语言的理解也就止步于语义了,隔两年,潮流变了,语言换了,才是一脸懵逼。

    有底层知识的支持,很容易就能理解函数指针,回调,委托的关系;从来就没有所谓的引用传递,都是值复制;缓存一致性问题不单单出现在底层,数据库,分布式系统同样出现,在底层同样能接触“速度不够就要加缓存,有缓存就要解决缓存一致性问题”这个朴素道理;类型系统都是纸老虎,是数据就都得放到内存里算。

    为什么 C 语言最合适,往上看,高级语言写法风格大都类 C ,要学习其他语言并无太大的不适应。类型系统一个语言一套,但是指针是每个计算机都有的;往下看,完全可以通过逆向 C 程序来往更底层的方向走。如果这个初学者的毕生梦想是写更好更快更稳定的嵌入式系统内核以及周边驱动开发,那起手让他学其他高级语言,了解各种类型系统有什么意义。

    如果是做语言研究,连用 C 入个门都困难,或者跌入个 C 设计上的坑都要大呼小叫,我觉得可能他的能力不适合做语言研究。语言设计也是填旧坑,挖新坑,不知旧坑,怎挖新坑?设计问题是权衡问题, C 语言是个不算好但是经典的范本。

    C 语言肯定不是做工程或者做语言研究最佳的入门语言。我说的是:

    在不清楚这个初学者以后到底要干什么的情况下,在初学者连自己都不知道自己到底要干什么的情况下, C 是性价比最高的语言。
    frozenshadow
        102
    frozenshadow  
       2016-08-19 09:41:18 +08:00
    @lizon 赞同。基础扎实了,其实学什么都很快
    kaneyuki
        103
    kaneyuki  
       2016-08-19 09:56:14 +08:00
    现在科班连 C/C++都学不动了么。。。时代变化快啊
    kaneyuki
        104
    kaneyuki  
       2016-08-19 09:57:31 +08:00
    从俭入奢易,由奢返俭难啊,同学
    shyling
        105
    shyling  
       2016-08-19 09:59:26 +08:00 via Android
    私以为问这种问题的话还是不要学 c 艹的好
    proudzhu
        106
    proudzhu  
       2016-08-19 10:03:17 +08:00 via Android
    @FrankHB 指针就是个地址,这么简单明了,哪来的什么抽象啊,当成 sum type 理解是什么鬼
    FrankHB
        107
    FrankHB  
       2016-08-19 10:16:38 +08:00
    @lizon 你还是没找到点。

    > 你认为一开始就应该给初学者提供比较完善的语言和类型系统,让初学者知道什么是对的,什么是先进的,以最快速度学习享受到现在最先进的理论成果,更多的关注语言本身的描述能力。

    如果我认为“一开始就应该给初学者提供比较完善的语言和类型系统”,那么压根就不用提 C 了。
    但是考虑实用,这种“比较完善”的东西并不存在,所以并不需要从这个角度考虑先从什么上手。
    (不管实用的话,可以考虑 Racket ,但有些知识复用性比较差。)

    > 我认为一开始应该提供给初学者最大的自由,暴露合适的硬件细节,让初学者明白计算机到底在做什么。

    用 C 显然不是最大的自由,而且很容易让初学者搞不清计算机到底在做什么。
    因为 C 暴露的硬件细节其实不多——至少没 C++多。而且经常暴露得很不地道。
    例如考虑不相关指针比较是 UB 这点就可以明白实际上 C 自身的设计(强调可移植性)完全是和单一地址空间的简化实现假设相悖的,和 C++11/D 形成鲜明对比。
    (其实理论上来讲这里 C 的设计更“正确”,只是实际上几乎并无卵用。)

    注意,我猜你想要的“暴露硬件”就是这类语言设计蕴含的抽象假设。
    如果是指操作硬件的接口,那么 C 无能为力。必须了解 C 以外的知识才能谈论是否能上手。这对初学者是不必要的负担。

    > 我不明白学 C 的低效在哪,风险在哪。

    低效有几方面的原因。
    首先 C 涵盖的新手急需的知识点太少,学其它语言上手容易收获更多。
    其次是教 C 的材料多数比较劣质,光是找到对路的参考资料就需要额外成本。
    再次,即便教对了路, C 本身的一些古董劣质设计很容易造成先入为主的错误观念形成误导,阻碍进一步学习——除非有意忘掉一些东西——这就是低效。
    核心风险是 C 没学好, C 以外的知识也没学好,另外还会教坏别的小朋友。
    因为上面几个原因,拿 C 混搭基础课造成的麻烦比其它语言大得多。

    > 面向初学者的教材几乎全是 C ,算法教材也大部分是 C 代码或者类 C 伪码,各大高校开设的计算机课程必定有 C ,已经为初学者尽可能降低了学习曲线。
    这是错觉。问题包含几个方面:
    不加前提地营造 C “够用”的假象,而不是在使用之前引导学生了解适用范围。
    算法实现如果只是伪码描述目的还好,但似是而非的、和现实使用不怎么着边的实现风格就大有问题:这是在误导这类实现是“正常”的或者“不重要”的。
    注意即便主题不是实现,作者仍然可以使它们接近实用的做法,而不是普遍地拿半成品搪塞。(当然并不是所有算法书都这么烂,但跟 C 沾边的主流如此。)

    使用不容易自然过渡到实用场合的代码教学,使学习者最后至少要学会两套不太相干的写法才能体现出所学知识的用途,这显然不是“降低了学习曲线”,而是人为抬线。

    > 初学者需要“学习 C ”,而不是“精通 C ”,不要去研究 C 语言本身的细枝末节,最主要是理解指针概念。

    我说过了指针作为实现技巧是个小聪明,而作为语言特性是个烂发明。
    如果你是指跟理解指针有助于和了解硬件,很遗憾,这个也是错觉。因为 C 的指针不是描述体系结构时使用的“指针”——有关联,但完全是两回事。
    (不信,让这些自以为学会 C 的去看 ISA 手册,看看真正地道的“指针”和 C 的这玩意儿有多大出入,需要浪费多少额外时间才能明白自己想错了。)
    另外,即便只是说 C ,我觉得不能理解为什么指针不靠谱的,不该视为理解了指针。具体地,真“搞清楚过指针运作原理”,除去程序语言理论专业知识,下面的一大半应该是能自己独自发现的:
    https://github.com/FrankHB/pl-docs/blob/master/zh-CN/why-is-pointer-awful.md

    > 有底层知识的支持,很容易就能理解函数指针,回调,委托的关系;从来就没有所谓的引用传递,都是值复制;缓存一致性问题不单单出现在底层,数据库,分布式系统同样出现,在底层同样能接触“速度不够就要加缓存,有缓存就要解决缓存一致性问题”这个朴素道理;类型系统都是纸老虎,是数据就都得放到内存里算。

    我很确信依赖实现支持的理解会造成一些典型的错误理解。实例很多。比如被 const folding 坑了的。

    你后面一些理解也是典型 yy ,但对大多数用户影响更大的是原则性方法论错误:模糊问题和解的边界。谁来替你保证实际的实现和你想象的一样?出问题谁负责?

    顺便,函数指针不管在 C 和 C++中都是大坑,因为甚至连对应的“地址”是什么都扯不清楚。这种 spec 基础问题表明这些语言不适合入门。

    > 为什么 C 语言最合适,往上看,高级语言写法风格大都类 C ,要学习其他语言并无太大的不适应。

    如果是“都”,那么稍微有点用。然而“大都”是最差的情况——似是而非,想要正确就基本不能合并学习路径复用历史知识,鸡肋。

    > 类型系统一个语言一套,但是指针是每个计算机都有的;往下看,完全可以通过逆向 C 程序来往更底层的方向走。

    你搞反了,“没有”类型系统是类型论应用的简化特例。这个特例对设计语言的人有点用——因为可以按需定制自己需要的类型系统而不是被渣语言设计恶心;但对多数用户纯属浪费——至少使在具体任务中以不够系统的方式重复造不知所谓的轮子代替缺少的静态契约检查变得有必要了。

    C 之所以在 B 上加上了类型系统,主要初衷也就是为了避免这里的不利影响。只不过由于设计者和实现技术的局限性,很不地道罢了。

    至于“一定有”指针那还是错觉,你对体系结构设计的见识太少。至少可以确定 ISA native 的 pointer 不保证说的是一回事且可以以一致的方式使用。如果地址操作数直接够用,完全不需要引入 CISC 风格的指针概念。

    逆向 C 程序是为了逆向本身的需求,如果说了解底层,比直接学习 ISA 慢不知哪去了……

    > 如果是做语言研究,连用 C 入个门都困难,或者跌入个 C 设计上的坑都要大呼小叫,我觉得可能他的能力不适合做语言研究。

    如果做语言研究,连 C 那么多明显的窟窿(以至于不适合入门)在哪都找不到,我觉得无论如何都是白费劲。

    C 作为样本研究是有价值的,所以可以一学。仅此而已。

    现在业界做语言和实现原型主要是 Scheme 这样的 Lisp 系方言。为了让之前学的 C 不浪费而故意复用 C 的知识也基本就是浪费时间,经验不够的还不如死了这条心。

    > 在不清楚这个初学者以后到底要干什么的情况下,在初学者连自己都不知道自己到底要干什么的情况下, C 是性价比最高的语言。

    我不清楚你有没有看到我指出的不管出于什么实用目的,基本上都有比直接学 C 更高效的路径这点。所以把 C 排在技能列表前面性价比不可能是最高的。
    FrankHB
        108
    FrankHB  
       2016-08-19 10:17:55 +08:00
    @proudzhu 看来又是个学傻的…… C 的指针加法跟地址加法一回事?
    嗯,我怀疑你根本就不懂 C 。
    eliteYang
        109
    eliteYang  
       2016-08-19 10:19:09 +08:00
    学什么跟语言无关,而更多的是解决问题的能力,不过学了 C++之后想转其他语言相对容易一些,但是 C++也是非常难的,包括科班都不怎么学了,更多的新型语言能更快更好的解决实际问题,并且学习成本低,作为企业考虑,自然愿意选择这些成本低的技术,而且人也比较好招。

    所以,学什么东西是看个人了,自己喜欢就去学,总归没害处的。
    bramblex
        110
    bramblex  
       2016-08-19 10:21:04 +08:00
    @proudzhu

    指针就是地址不抽象只是对我们这些有良好计算机基础的人来说不抽象,那地址你要不要跟初学者讲清楚是什么?地址怎么讲? CPU / 内存 这些组成原理基本的东西要讲吧,数据和代码都是内存上的块要讲吧?这样子杂七杂八讲起来,一个指针上面卡上十天半个月不奇怪吧?
    bramblex
        111
    bramblex  
       2016-08-19 10:24:55 +08:00
    @lizon

    你可能技术很牛逼,但是说实话,你对人性的把握真是差得一逼,找你教那就坑学生的。
    proudzhu
        112
    proudzhu  
       2016-08-19 10:35:56 +08:00 via Android   ❤️ 1
    @FrankHB 不是一回事,那个是编译器的优化,难道你喜欢每次都加个 sizeof ?
    一言不合就学傻,按你说的我需要先理解 sum type ,再理解编译器中 sum type 的具体实现,再来理解指针,绕一圈?一个本来相对底层的概念非得用个抽象的东西来理解?
    我没通读过 c 标准,没写过编译器,你说我不懂我也没什么说的。
    kaneyuki
        113
    kaneyuki  
       2016-08-19 10:38:29 +08:00   ❤️ 2
    事实上我觉得某人答的和题主问的完全不是一回事儿
    aoteman
        114
    aoteman  
       2016-08-19 10:39:31 +08:00 via Android
    C 找工作是更麻烦事,老死机告诉你
    proudzhu
        115
    proudzhu  
       2016-08-19 10:40:24 +08:00 via Android
    @bramblex 你要理解指针就必须要理解计算机体系结构,这是基础,想深入理解就不要想抄捷径。
    kaneyuki
        116
    kaneyuki  
       2016-08-19 10:40:44 +08:00
    @aoteman 用什么起手和用什么找工作也是两回事儿。。
    lizon
        117
    lizon  
       2016-08-19 10:49:00 +08:00
    @bramblex 有的人偏向于通过别人一步一步引导,以温和的方式来进行了解;有的人偏向于尽可能多的了解细节,以自由探索的方式来了解。我个人认为后一种品质更有利于自身发展,所以希望初学者一开始就培养自己这种品质。只是方式选择的问题,不分对错,我也只是发表了自己的见解。
    只谈技术,不谈人性。
    FrankHB
        118
    FrankHB  
       2016-08-19 10:52:34 +08:00
    @proudzhu ……看来你不仅没学明白 C ,也不懂什么叫“优化”。
    对 C 来讲,允许编译器优化而不依赖语言扩展的唯一依据是不违背 observable behavior 和 abstract machine 指定的等价性( C++倒是在 as-if rule 以外还有 copy elision 和 operator new merging 之类的开洞)。不管 sizeof 还是指针的类型都是在语义规则里直接钦定的被 abstract machine 都支持的东西,编译器必须得正确地生成不同的代码(还有可能报错),什么时候有脸叫“优化”了?

    > 一言不合就学傻,按你说的我需要先理解 sum type ,再理解编译器中 sum type 的具体实现,再来理解指针,绕一圈?一个本来相对底层的概念非得用个抽象的东西来理解?

    这还真是学傻了。
    1.sum type 在 C 的常见实现就是(untagged) union+表示 tag 的整数 /枚举值。这是很常用的惯用法,我不信真学会 C 的连这种做法都理解不了。也许只是不求甚解的时候不太理解计算机科学更通用的术语自己吓唬自己罢了。
    2.上面提 sum type 是指代替指针这种错误的偷懒设计应该怎么办。注意 tag 在静态语言中是能编码为静态类型确定的,所以可以实现成某些 C++库中的 compress_pair 。 C 的类型系统太弱没法自定义数据类型来描述,如果用 C++,忽略 tag 以后运行时内部在某些方言中的表示可以大致是这样:
    template<typename _Tp>
    using __pointer<_Tp> =
    union
    {
    __uintptr_t __address;
    __optional<_Tp> __nullable_ref;
    // ...
    // ...一堆 friend 当 std::is_object<_Tp>()的时候定义 pointer arithmetic ,略。
    } __attribute__((__may_be_aliased__));

    另外,这里的关键问题你理解错了。正常点的语言设计根本就不应该在实现扩展外出现这种投机取巧的类型,更应提供给用户的是等价于这里内部表示的__uintptr_t 和__optional 等等的(高阶)类型。所以你压根就不需要理解这样的实现。
    archxm
        119
    archxm  
       2016-08-19 10:53:55 +08:00
    一个个,都长篇大论的,你们真是在上班么?这样真是合格的程序员?
    cdffh
        120
    cdffh  
       2016-08-19 10:55:37 +08:00
    我在教小学生 c++. c++确实不简单 不过小学生都学的挺好的. 大家也不要过于夸大难度了.
    muziki
        121
    muziki  
       2016-08-19 10:57:47 +08:00 via iPhone
    @lizon is 我觉得他的意思可能是说,因为 C/C++自身的某些缺陷和学习资料的水平问题会导致初学者希望通过学习 C/C++的同时了解底层知识的时候受到误导
    与其学习 C/C++还不如学习“高级语言”,计算机底层知识没必要和特定语言绑定,想学就直接看底层的相关知识,否则初学者对底层的理解可能被带偏, C/C++本身学习成本和产出比较低,没那个必要
    bramblex
        122
    bramblex  
       2016-08-19 11:06:34 +08:00
    @lizon

    对不起,教育只谈人性不谈技术。
    kaneyuki
        123
    kaneyuki  
       2016-08-19 11:08:34 +08:00
    @bramblex 我去个孔子学院出来就能写程序了?
    kaneyuki
        124
    kaneyuki  
       2016-08-19 11:11:14 +08:00
    @proudzhu 看见某人的回复要吐血了吧,哈哈。
    所驳非所问这招到哪都是无敌的,你打不过的
    bramblex
        125
    bramblex  
       2016-08-19 11:13:56 +08:00
    @kaneyuki

    教育是我教你,我要懂人性,懂了吗?你手下带过几个程序员?
    FrankHB
        126
    FrankHB  
       2016-08-19 11:14:01 +08:00
    @kaneyuki 你先搞清楚答主的问题该答的上一页已经答完了再来水好不好。
    现在的焦点明显是给上一页的某些回复擦屁股避免不确定的影响。

    嘛,需要小尾巴广告的话——照例专业治疗各种自以为学会 C 的癔病。
    FrankHB
        127
    FrankHB  
       2016-08-19 11:17:40 +08:00
    另外补一句,我来义务诊疗并非因为我闲着没事干或者热衷慈善,而是因为太多被带沟里的厨余发酵着让业界发馊了碍着我了,基于利益考量,我有必要采取减少我潜在工作量的对策罢了。

    没搞清楚扯啥的搪塞的还是趁早闭嘴比较能节约双方时间。
    proudzhu
        128
    proudzhu  
       2016-08-19 11:18:55 +08:00
    @FrankHB 不是科班的,我表达的”优化“指的是“不需要你自己完成,编译器完成的",表达有误,见谅。
    我们讨论的问题不是理解指针吗? Sum Type 是在看 Haskell 时了解的,谢谢让我了解了 C 实现的 tagged union ,但是这个实现难道不需要理解指针?所以到底应该怎么理解指针?别说指针是语言设计的错误。
    lizon
        129
    lizon  
       2016-08-19 11:20:03 +08:00   ❤️ 1
    @muziki 嗯,了解。
    我的意思是:初学者只需要把 C 语言当成一个纯粹的工具,了解底层,做实验的工具,并没有上升到语言本身的问题上,我其实也不关心 C 语言语义上的东西。作为初学者了解底层的起手工具, C 语言最合适。
    带偏是难免的,任何资料都可能存在误导,遇到问题了,初学者自己要学会查问题,做实验,和别人交流,验证想法。
    我希望初学者通过学习 C 语言,通过遇到问题解决问题,学到其他更有用的东西,比如“底层封装得并不完美”,“编译器并不能保证程序的正确性”,永远保持向下探究的态度,顺带还有一大票的底层知识,而不单单只是学一门程序语言的语法语义。
    kaneyuki
        130
    kaneyuki  
       2016-08-19 11:21:07 +08:00
    @FrankHB 我只是看到一些连叙述者的意思都理解的所驳非所论而已。
    您专治各种癔病的郎中班继续开,不多打扰。
    proudzhu
        131
    proudzhu  
       2016-08-19 11:22:50 +08:00
    @kaneyuki 那没办法,非科班的表示还没了解到这么多的程序语言相关的概念,无奈脸
    kaneyuki
        132
    kaneyuki  
       2016-08-19 11:28:43 +08:00
    @bramblex 带了三届了,怎么了?
    FrankHB
        133
    FrankHB  
       2016-08-19 11:28:57 +08:00
    @proudzhu 你的误解应该综合来源于几个方面。
    须知:
    1.底层( ISA 设计提供的)的指针,一般就是有特别含义的地址。
    2.C 所谓的指针和上面所谓的指针根本不是一回事。
    3.这两者在实现上是有些关系,但不需要倒腾二进制互操作的用户(显然包括绝大多数新手),附会只是添乱。
    4.大部分用户没有机会也不必要同时接受把这些东西理解得面面俱到的系统训练。
    只有绝对少数领域(像实现 CPU 的、做编译器的、维护系统 ABI 的、在这个层次以下逆向的、因为目前 ISA 抽象混乱做 OS 不得不在这个层次上 hack 的……)的实现者和设计人员中的 architect 才有必要把这些都理解清楚。
    相对来讲,只学高级语言,忘记“指针就是地址”符合更一般语言用户的需求。
    先钦定指针=地址,根本就是搞错问题领域了。我当作误导,不算冤枉吧?
    lizon
        134
    lizon  
       2016-08-19 11:33:10 +08:00
    @bramblex 我不认为学习问题是教育问题,很多时候需要自学,交流,做实验,自己验证想法。不是每个初学者都有机会等到大牛根据人性的悉心指导,自力更生更重要。这个道理越早理解越好。
    bramblex
        135
    bramblex  
       2016-08-19 11:34:34 +08:00
    @kaneyuki

    那你还不懂得怎么培养人?怎么把不积极的程序员的兴趣调动起来?当然啦,反正如果只是当砖不培养的话当我没说过。
    bramblex
        136
    bramblex  
       2016-08-19 11:36:03 +08:00
    @bramblex

    自己学习没错,但是培养手下是另一码事了好吧。两个都要做的,光自己学习有个蛋用,一个人的力量多有限?
    bramblex
        137
    bramblex  
       2016-08-19 11:37:41 +08:00
    不撕了,干正事了……
    FrankHB
        138
    FrankHB  
       2016-08-19 11:43:43 +08:00
    @proudzhu 很遗憾,我还真找不出“不是错误”的借口。这是让实现细节倒置到接口之上的典型 leady abstraction ,怎么看都是设计上的经典反面教材,只是各种不明真相的群众以讹传讹说成了“精华”,也是无语。
    改正这个问题最简单的做法就是直接提供底层的指针代替现在的指针,可以实现为整数或者加上一些检查的地址类型(也可以考虑提供地址偏移量类型),于是“(对象)指针就是(可选的)地址”成了真命题,符合一些用户的预期。而现在 C 那种指针应该被废弃,非要兼容也应该弱化为库来提供而不是语言内建。这样语言规范里的废话也能转移出去一大坨,二进制兼容性维护起来也方便得多。
    然而很遗憾, C 在参数化类型上的开洞导致这种改动必须另加很基本的核心语言特性而不现实(不像 C++有模板加上一个扩展标识符占位就立刻能凑数)。所以估计接下来几十年将错就错还是主流了。
    proudzhu
        139
    proudzhu  
       2016-08-19 11:45:22 +08:00
    @FrankHB 如果我记得没错的话,程序都是访问的是虚拟地址空间,和真实硬件的地址是映射关系,我们说的 C 里的指针是指向这些虚拟地址空间的。
    我当然知道高级语言的用户不需要了解这些,但是我们现在讨论的不就是怎么理解指针吗?
    还是认为指针=地址,搞 DSP 的时候也和这个理解一致,求科班人士拍醒。
    FrankHB
        140
    FrankHB  
       2016-08-19 11:57:36 +08:00
    @proudzhu 你要知道 C 这种人为设计的东西,通过对“指针”这个术语的明确的定义和拒绝提及其它义项,就完美地把“指针”在其它领域的本义覆盖掉了。所以光是讨论 C ,你只有一个无歧义的“指针”的概念。如果你需要同时讨论更底层的某些 ISA 中定义的指针,那还不如直接说“地址”更清楚,不需要无谓增加同义词和混乱。(你也不方便随便发明一个新概念代替 C 所谓的“指针”了,加上“智能指针”这类派生,“指针”这个词在一般场合是保留给高级语言的。)

    而虚拟地址空间是另外一层抽象,通常比 C 实现的层次更低。不算 WG14 某些扩展提案, C 本身不对地址空间做任何抽象(其实根本就没提什么地址空间), ISA 和一些硬件 spec 倒是会提到支持,所以提虚拟地址空间实际上已经是 C 以下的底层话题了。排除高级语言这个意义上讨论“指针”的含义反倒比上面明确,虽然我仍然更愿意看到“地址”这样无歧义的表述。(嘛,严格来说上面所有的地址特指 memory byte address ,不过一般人也不会没事倒腾寄存器编址什么的……)
    initialdp
        141
    initialdp  
       2016-08-19 11:59:16 +08:00
    对初学者,我会推荐 Python 或者 java ,了解到一定程度后,会推荐 C 。一般不会推荐 C++,这要等新手成为老手后,自己有兴趣就去学呗。

    至于地址、指针等这些概念,如果以后主要做业务层面的开发,可能几乎不用理会这些概念,还不如多花时间去了解业务逻辑、行业知识等更实在些。当然,如果有兴趣去学习或者工作上有需要去学习,再了解也不迟,这些也不是什么了不得的概念,花点时间就能掌握,没有必要过度强调。
    pxlxh
        142
    pxlxh  
       2016-08-19 12:05:04 +08:00
    鼓吹底层的大妞们

    你们真的要这样坑人吗
    wizardforcel
        143
    wizardforcel  
       2016-08-19 12:35:20 +08:00
    @lizon

    [你认为一开始就应该给初学者提供比较完善的语言和类型系统,让初学者知道什么是对的,什么是先进的,以最快速度学习享受到现在最先进的理论成果,更多的关注语言本身的描述能力。]

    你觉得先有认识还是先有实践??

    如果一个人之前见识到了高级语言的完善,才可能探寻在 C 中怎么实现。如果一个人先接触了 C ,在接触其它语言之前不可能凭空发明出这些完善的设计。能凭空发明的人也不会在这里问问题。

    具体来讲,一个人之前如果没见识过 C++(或其它语言)的 Map ,自己还真不一定能想出来并实现这个 Map 。一个人如果没见识过 Golang 的 GC ,也不可能想出来我也在 C 里面实现这个 GC 。

    [我认为一开始应该提供给初学者最大的自由,暴露合适的硬件细节,让初学者明白计算机到底在做什么]

    光有自由是不够的,需要见多识广。

    小学生设计的汽车能上天入地,工程师设计的汽车就是现在的样子。

    [我说的奢俭,是指初学者一旦高级语言用爽了,屏蔽了本来应该了解的细节,很可能就呆在舒适区不想出来了,称他还没养成惰性,照脸糊 C ]

    如果一个人学了 Python ,并且认为解释器及下面都是黑盒,那它就不适合做程序员。不要妄想着学 C 给矫正过来。 C 有没有细节??一个人学了 C 之后,不想了解汇编、指令集、流水线、数字电路,你又能怎么办?

    [面向初学者的教材几乎全是 C ,算法教材也大部分是 C 代码或者类 C 伪码,各大高校开设的计算机课程必定有 C ,已经为初学者尽可能降低了学习曲线。 ]

    拿数据说话,你可以统计近几年的数据结构和算法书,从豆瓣上找。也可以统计国内外大学开的导论课。

    [初学者需要“学习 C ”,而不是“精通 C ”,不要去研究 C 语言本身的细枝末节,最主要是理解指针概念。 ]

    请把编程和计算机原理 /系统的学习分开。

    如果大部分语言都适用于没有指针(或者只有弱指针)的设计,那么就**编程**而言,没必要搞懂指针。

    指针可以放到 System 相关课程里去学。一开始接触指针会徒增入门的难度。

    [为什么 C 语言最合适,往上看,高级语言写法风格大都类 C ,要学习其他语言并无太大的不适应。 ]

    你这个论据也能说明“先学其它语言再学 C 也并无太大的不适应”。

    实际上先学 C 会不适应(或需要重新学习)其它语言的 FP ,或者 OO 。反过来倒是无大碍。

    [如果是做语言研究,连用 C 入个门都困难,或者跌入个 C 设计上的坑都要大呼小叫,我觉得可能他的能力不适合做语言研究。]

    请把“学习编程”或者入门跟学习 PLT 区分开。

    [在不清楚这个初学者以后到底要干什么的情况下,在初学者连自己都不知道自己到底要干什么的情况下, C 是性价比最高的语言。]

    在不清楚这个初学者以后到底要干什么的情况下,就不要假设初学者以后搞 CS 研究或者搞 IT 。这种情况下,应选择一种尽量“普适”的语言。如果学了 Java 或 Python ,假设以后不干这些了,还能编个程序跑数据,解决那个领域的问题。学了 C 能干嘛呢?
    wizardforcel
        144
    wizardforcel  
       2016-08-19 12:52:36 +08:00
    鼓吹底层 /system 的人总是说面向硬件编程比面向 OS 和互联网编程更重要,好像把它们派到阿里都能成为第二个马云似的。

    我对 binary 和逆向感兴趣,但我绝对不强迫别人研究这东西,尤其是不强迫新手一入门就研究这东西。

    OS 都知道把交互型进程排前头,把计算密集型进程排后头。至少比某些人聪明。
    lizon
        145
    lizon  
       2016-08-19 12:57:51 +08:00
    @wizardforcel 我之前的回答都是在强调:起手学 C ,并不是只学 C ,并不是要求精通 C 。

    就计算机知识体系来说, C 是最佳的线索。我对初学者的假设是“想了解计算机体系结构,但是没有人带领”的人。在学习 C 的过程中,会碰到很多问题,一方面是语言造成的,一方面是底层封装不完善造成的,在解决问题的过程中,一方面可以接触了理论知识,一方面可以接触硬件知识,对他自己寻找方向是有好处的。一旦找到了自己的方向,那还用不用继续学 C 就是他自己的兴趣问题了。不要以为跑数据写代码就是计算机的一切,你说的“普适”的语言对于想玩硬件,从事嵌入式系统内核开发的人有意义吗?

    如果你身边就有很好的学习资源,或者你已经找到了自己的方向,那随便怎么学都可以,反正方向明确有人带。
    kingddc314
        146
    kingddc314  
       2016-08-19 13:01:10 +08:00 via Android
    我也是服了你们这些长篇大论的
    wizardforcel
        147
    wizardforcel  
       2016-08-19 13:08:17 +08:00
    @lizon

    [你说的“普适”的语言对于想玩硬件,从事嵌入式系统内核开发的人有意义吗? ]

    你说的内核开发,或者嵌入式占市场的百分之多少?为了一颗树放弃整个森林??

    在如今嵌入式如此低迷,工作环境如此恶劣的情况下。圈内人都不想拉新手入坑,你可倒好。在不清楚这个初学者以后到底要干什么的情况下,你就把人往坑里带。

    你可以问问身边的人,互联网和嵌入式他们优先选哪个。
    lizon
        148
    lizon  
       2016-08-19 13:17:31 +08:00
    @wizardforcel 我往坑里带了吗?没有说学 C 就一定要用上 C 。
    我只是觉得应该给予初学者最大的自由。喜欢硬件就往硬件发展,喜欢软件就往软件发展。在学 C 的过程中寻找自己感兴趣的东西。说不定他就是下一个优秀的硬件工程师。
    对于上层开发,我很担心初学者过早用上高级语言会养成思维定势,形成舒适区,抵触底层细节,对发展有害。
    FrankHB
        149
    FrankHB  
       2016-08-19 13:53:01 +08:00
    @lizon

    > 就计算机知识体系来说, C 是最佳的线索。我对初学者的假设是“想了解计算机体系结构,但是没有人带领”的人。

    我之前说过了,就是需要学 C , C 也不适合放在最前面,因为基本上总是有更合适的路径。似乎你总是无视这个选择。

    > 在学习 C 的过程中,会碰到很多问题,一方面是语言造成的,一方面是底层封装不完善造成的,在解决问题的过程中,一方面可以接触了理论知识,一方面可以接触硬件知识,对他自己寻找方向是有好处的。一旦找到了自己的方向,那还用不用继续学 C 就是他自己的兴趣问题了。

    这仍然只是说明 C 是可选项,而不一定就是最合适的,也避免不了对于大多数需求事倍功半的事实。

    > 不要以为跑数据写代码就是计算机的一切,你说的“普适”的语言对于想玩硬件,从事嵌入式系统内核开发的人有意义吗?

    至少就 C 来讲在这里是不得不有意义的,因为 C 的设计自身极端强调这个层次上的“普适”。

    要从事嵌入式系统内核开发,也不可能一开始就学嵌入式系统内核开发专用的 C 。何况任何 C 的方言无法绕过 ISO C 这个基础 spec ,否则就不是 C 了。

    有些领域入行了提升并不是很困难,困难主要因为不是这个领域的公共基础的难度堆起来的。自担风险。

    > 我往坑里带了吗?没有说学 C 就一定要用上 C 。

    学了不用和为了不浪费之前没规划好学的东西而去用一样是坑。正确的姿势是为了用而学。

    你可能会说学 C 是基础积累,不直接用也可以发挥作用。遗憾的 C 在许多人眼里的“底层”是假象,而对大多数人的目的来说,发挥的作用经常有其它更合适的学习路径替代。
    FrankHB
        150
    FrankHB  
       2016-08-19 14:10:05 +08:00
    @ecloud
    K&R 当时的确是想发明“更好用的汇编”,但显然不止是汇编,不管是以 B 作为基础和有意无意保持可移植性。
    不过我基本同意“低级语言特性”主要是实现的锅。但是提交标准化以后,这些锅最终都尘埃落定了。
    在我的印象中伪码是历史上因为编译性能等因素才体现出有意义额外流程。现在并没有这个必要。
    与其说 Pascal 是背惯了实现的锅,倒不如说是后续长期疲软才是致命伤。
    互操作上的先天不足和其它一些不方便的特性(如 Why Pascal is not my favorite programming language 所说)使市场已经倒向了 C ,在之后没有靠标准化扳回一城于是满盘皆输。

    关于强弱类型的问题,实际上和 C 没有直接关系。
    按 C 的概念, if(a=5)不管和 typing 还是 type checking 都没关系,所以传统上跟强弱类型的论战也没交集。
    当然理论上来说还是可以有的,但按 C 声称的设计,死活不承认 lvalueness 是类型系统的一部分(倒也不像 B 一样直接作为文法元素的性质),那样怎么说都通。
    lytofb
        151
    lytofb  
       2016-08-19 14:18:52 +08:00
    第一反应就是——现在不是都用 go 了吗?结果发现没啥人推荐。
    用 GO !!!(望赐教)
    linuxchild
        152
    linuxchild  
       2016-08-19 14:25:30 +08:00 via iPhone
    想知道细节还是看一下比较好
    lizon
        153
    lizon  
       2016-08-19 14:34:11 +08:00
    @FrankHB 在细分领域,总有比 C 更好的选择,是的。基于目的去学习相应语言,造成的时间浪费最少,是的。
    如果找到方向了,大可以转投更有针对性的领域,在此之前学一学 C ,软硬都了解一下,没什么不好
    yuankui
        154
    yuankui  
       2016-08-19 15:04:24 +08:00
    堂叔。。。
    现在都什么年代了
    C++在你堂叔那个年代的确有他的地位,但是放到现在,哎。。
    xiqingongzi
        155
    xiqingongzi  
    OP
       2016-08-19 15:26:42 +08:00
    @yuankui 我堂叔今年 28.。。。在广联达搞 CPP 开发。
    yuankui
        156
    yuankui  
       2016-08-19 18:15:02 +08:00
    @xiqingongzi 哦,搞 CPP ,在互联网公司基本找不到工作。。
    而且你看 V2EX 里面讨论 CPP 得多呢,还是讨论 python , js , php , java 的多呢?
    GeekGao
        157
    GeekGao  
       2016-08-19 20:22:22 +08:00
    ”面向工资编程“
    FrankHB
        158
    FrankHB  
       2016-08-19 20:27:39 +08:00
    @lytofb 当初吹要取代 C ,还不是只能老实当 DSL ……
    @lizon 细分领域到最后是项目一有需要就人手撸个新语言实现而不用担心成本。靠 C 糊弄明显是初级阶段的初级阶段。 C 现在除了本来合适的领域,实际项目中主要也就继续靠实现其它语言(以及死皮赖脸装作能霸住互操作接口)刷存在感(虽然 Lisp 和搞所谓 FP 语言的那伙人多数早就对此没兴趣了)。
    毕竟现在条件好了能用的选择多了,不需要在此浪费时间。
    crayygy
        159
    crayygy  
       2016-08-19 20:29:47 +08:00 via iPhone
    分享葛平的单曲《猿泡沫》 http://music.163.com/song/31477115?userid=20205551 (@网易云音乐)
    miao1007
        160
    miao1007  
       2016-08-19 21:12:56 +08:00
    学 C 是兴趣提升,学 Java 是谋生手艺
    cchange
        161
    cchange  
       2016-08-19 21:13:34 +08:00 via iPhone
    这么多回复了 有时候为了操作硬件资源需要 c 或 c++

    但好时候硬件操作独立后 可以考虑转为 c#

    个人意见~
    introom
        162
    introom  
       2016-08-19 21:16:25 +08:00
    @FrankHB 没仔细看,但扫了一眼,发现你长篇大论很多,看上去很懂的样子。请教一下,你都是怎么学 C/C++的,你工作中是不是经常使用 C/C++? 没什么,就是学习一下,感觉你对 C/C++理解比我深刻很多,所以想取个经,我目前也就只是停留在有问题读 spec 的水准上。当然我平常也极少写 C/C++。
    FrankHB
        163
    FrankHB  
       2016-08-19 21:42:33 +08:00
    @introom 读 spec 能读到满腹槽点只能长篇大论就差不多了……
    oscarzhao
        164
    oscarzhao  
       2016-08-19 23:03:57 +08:00 via Android
    没太看懂上面争论的焦点是什么,这段时间看侯捷老师 c++11 的视频,完全使用新标准去写的话,之前兼容 c 的语法,操作裸指针等都很少使用了,不过最好懂一些。刚开始可以不用,后面随着能力长进,慢慢会主动去研究,也不错。 仅仅从使用的角度,理解指针的概念,学习类 c 的语言,比如 go 语言
    oscarzhao
        165
    oscarzhao  
       2016-08-19 23:06:06 +08:00 via Android
    很多概念理解起来容易太多。关于系统相关的东西,学习的时候都需要 c 去实践,才能更深刻地理解
    lxy
        166
    lxy  
       2016-08-19 23:34:53 +08:00
    我仿佛又听到耻球发出噗噗噗的声音 wwwwwwww
    yhyangjiabin
        167
    yhyangjiabin  
       2016-08-20 10:44:44 +08:00
    推荐 C 或者 Python 吧,一开始学习一些简单的,容易理解。有信心学下去,在慢慢深耕
    techmoe
        168
    techmoe  
       2016-08-20 11:56:45 +08:00
    借用一下某位前辈的话
    **你愿意一开始就整天面对一个黑漆漆的 console 玩吗?**
    xieyudi1990
        169
    xieyudi1990  
       2016-08-20 16:46:33 +08:00
    还有说实话每次看到这样鼓吹 C 的言论,感觉很 low 。老是说底层底层,不知道是不是自己脑补还是怎么啦。动不动来句 “底层”,要真说底层,估计一句话也答不上来。这种感觉让我想起了亲身经历的事。隔壁寝室有一同学( CS 毕业了找不到工作送中通),然而他大三时,我亲耳听到他向大一学弟吹嘘 C/C++ 如何如何好,如何接近底层(虽然我不反对他的说法,但我一脸鄙视)。

    而且我还想吐嘈,每次有人问如何学习计算机,就有人列一大堆课本。我怀疑发这贴的人,有多少人是认真看过的。

    题外话,你仍然想学习底层,那学习底层最好的方法,当然是直接学习底层。指令集架构,微架构,数电,模电,一层层看呗,有兴趣的话。一步步歪下去的话搞不好会转专业哦(和我一样, CS 转 EE 的奇葩)。这种情况下, C 搭着学一学,可以,比较大部分这方面的代码都用 C 。但如果只学 C 那点东西,指望能怎么 “底层”,那是不可能的。而且如果是考虑程序员这个职业,那自然更没必要。

    (虽然我平时要说也基本只用 C 。混着汇编和机器码吧。还有 bash 做胶水。描述语言不算。我是搞硬件的, CPU )。

    @bramblex
    地址,你就拿邮编做比方。只不过计算机是二进制,门牌是十进制;计算机以字节为单位,邮编以社区为单位。
    要精确到内存上... long story...

    就说 pc 的 dimm ,比如我前阵子在调的这个(普通笔记本用)内存条。双面各 8 个芯片(共 16 个, 64Mx8-bit );上面的 8 片的 cs 连在一起,和下面的 8 片的 cs 连在一起,组成两个 rank ; 8 片 8-bit dq (双向数据线)按位扩展到 64-bit ,一起和地址 /控制线接到内存控制器上。 dram 芯片上,有 4 个 bank ,每个 bank 有 16k row ,每个 row 1k column ,每次读写可选 4/8 长度的 burst 。要访问,需要先 active , read/write , precharge 三个阶段。可利用的地方比如,不同的 bank 可同时处于 open 状态(即不被 precharge ),而且如果处于 open 状态只要处在同一个 row 里可以快速访问(否则必须 precharge 关掉再 active )。另外至多每隔 64 ms 必须 refresh , refresh 后需要重新 active 。(说得有些不清楚,感兴趣的可以看 JEDEC 文档或内存芯片的文档)这样给内存控制器很多设计空间了。举例,比如是保持 open ( open-row policy )这样可减小同 row 的访问延迟,但是其他 row 的延迟会增大,而且 open 会更耗电,也有一些其他的限制;还有一种是 close-row policy ,延迟可能会大,但功耗小;当然有动态调节的,看情况。还有不同通道独享总线互不影响。(程序员应该都知道 locality )以上各种原因决定了物理地址到 channel/rank/bank/column/row 的映射。

    到 CPU 里面(现在应该都是集成了内存控制器)。内存控制器挂在 coherent interconnect 下面,上面是 cpu 最后一级缓存。哎感觉说了半天也没说清楚,不说了。反正 the rest is history , cache controller, line fill buffer,
    eviction buffer, snoop filter, tlb/itlb/dtlb, page walker (虚实地址转换就是前面几个货在弄), load/store queue, etc. etc.

    如果你知道你程序里变量的虚拟地址( C 里的 & 操作),页在内存里,能 dump 出页表,知道能 flush cache all the way to DDR ,知道内存控制器的设计和设置,知道你内存条的配置,理论上来说,你应该能精确到在哪颗 DDR 颗粒里(如果有内存条的 RTL 和 GDSII ,也许你能够知道具体在哪里)
    xieyudi1990
        170
    xieyudi1990  
       2016-08-20 16:50:13 +08:00
    @xieyudi1990 s/(如果有内存条 /(如果有内存颗粒 /g
    FrankHB
        171
    FrankHB  
       2016-08-21 01:58:18 +08:00
    @xieyudi1990 做 uncore 的?
    wizardforcel
        172
    wizardforcel  
       2016-08-21 16:31:02 +08:00
    @lizon

    [我往坑里带了吗?没有说学 C 就一定要用上 C 。 ]

    我承认,对于内核和嵌入式, C 具有良好的生态和工具链。(嵌入式不是主流、待遇差,但是与这个话题无关。)

    但是,你的观点就是,为什么学 C ,因为嵌入式要用到 C 。那我问为什么搞嵌入式,你又说学 C 不是为了搞嵌入式。那我就奇怪了,你的推荐原因是啥。

    [就计算机知识体系来说, C 是最佳的线索。]

    你知道啥叫“计算机知识体系”?只有 system ?图形、 ML 和 thoery 都被你吃了?

    [我对初学者的假设是“想了解计算机体系结构,但是没有人带领”的人。 ]

    这个假设就不对。

    还不会编程的人,应该学学一些编程的思想,比如说一些代码的抽象和组合方式。

    直接看汇编、流水线、缓存??呵呵。

    ---

    你给我的感觉就是,要么搞嵌入式搞傻了,要么基于个人原因推荐 C 。

    个人原因也没什么,实话实说就好了,搞什么“底层鼓吹论”只会让人觉得牵强附会。

    system 只是计算机的一个分支,也不是万能的,千万不要鼓吹或者是神秘化。

    就酱。
    lizon
        173
    lizon  
       2016-08-21 22:26:08 +08:00 via Android
    @wizardforcel 你完整的看过我们之前的讨论内容吗?
    我哪句话是在“鼓吹”底层?我基于自己的经历,建议让初学者首先接触接触 C ,对硬件实现形成基本的概念,有问题?我说过让初学者跳坑了吗?老是先上来批判一番。说实话,其他人先学什么关我屁事,有兴趣的人,自己都会去弄懂这些问题。本来就是建议向的东西,你觉得不对,你说你的方案就是了,一句一句反驳搞得我很恶心。
    laviris
        174
    laviris  
       2016-08-26 13:03:57 +08:00
    看你自己的定位,如果你只是想干份工作,拿份高薪,实在没必要开始就学 c/c++,在市场供需很明显的情况下,你学供应短缺的就行了。但是如果你稍微风险意识,希望自己足够全面,c/c++开始是没问题的。由奢入俭和由俭入奢,怎么选自己看着办。虽然我不做嵌入式,但是对于楼上说什么嵌入式非主流,待遇差这种,只能呵呵了。估计是互联网干多了加班加傻了。你去跟人嵌入式的比比时薪和压力看看,会比你差么。嵌入式不过是通用型太强,集成度太高,需求变少而已。最后,你我不过是社会生产资料中的一环,如果用价格高低来衡量,不过就是资本家在运作的时候发现生产资料短缺,暂时性的提高价码而已,感谢时代吧。
    1  2  
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3258 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 12:16 · PVG 20:16 · LAX 04:16 · JFK 07:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.