﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-我的编程乐园-随笔分类-大学公开课</title><link>http://www.cppblog.com/deercoder/category/19231.html</link><description>&lt;P&gt;&lt;FONT style="FONT-SIZE: 20px" color=#ff0000&gt;积累，坚持！&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT style="FONT-SIZE: 20px" color=#ff0000&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ---------我是一只IT小小鸟&lt;/FONT&gt;&lt;/P&gt;</description><language>zh-cn</language><lastBuildDate>Sun, 24 Jun 2012 14:30:22 GMT</lastBuildDate><pubDate>Sun, 24 Jun 2012 14:30:22 GMT</pubDate><ttl>60</ttl><item><title>斯坦福大学开放课程--编程范式（四）</title><link>http://www.cppblog.com/deercoder/archive/2012/06/24/180038.html</link><dc:creator>deercoder</dc:creator><author>deercoder</author><pubDate>Sun, 24 Jun 2012 08:57:00 GMT</pubDate><guid>http://www.cppblog.com/deercoder/archive/2012/06/24/180038.html</guid><wfw:comment>http://www.cppblog.com/deercoder/comments/180038.html</wfw:comment><comments>http://www.cppblog.com/deercoder/archive/2012/06/24/180038.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/deercoder/comments/commentRss/180038.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/deercoder/services/trackbacks/180038.html</trackback:ping><description><![CDATA[<p style="margin-top: 18px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; "><span style="font-size: x-large; font-weight: 600; "></span></p><p style="margin-top: 18px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; "><span style="font-size: x-large; font-weight: 600; ">综述</span></p> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">本节课的主要内容是关于泛型数据的拷贝，虽然是使用C语言实现，并且没有用到C++中的模板这种泛型编程技术，但是效果却非常好。本节内容紧接上节所将的字节位拷贝的知识，充分利用了字节拷贝技术。</p> <p style="margin-top: 16px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; "><span style=" font-size:x-large; font-weight:600;">笔记</span></p> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">由于内容和例子不断深入，实际核心内容则比较集中，因此这里只进行总结讨论。</p> <p style="margin-top: 16px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; "><span style=" font-size:x-large; font-weight:600;">引例</span></p> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">本节所有的例子都是针对于数据交换来进行的，从最简单的例子开始，不断深入。 开始是关于一个最简单的整数数据的交换实例：</p> <pre style="margin-top: 12px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">void swap(int a, int b){</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">        int tmp = a;</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">        a = b;</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">        b = tmp;</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">}</span></pre> <pre style="margin-top: 0px; margin-bottom: 12px; font-family: 'Courier New,courier'; "></pre> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">此例子非常简单，只需要构造一个简单的中间临时变量tmp用来存放a的值，并且交换赋值相关的数据，就可以达到交换的目的。</p> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">但是，此实例有一个缺陷，就是值传递，而不是引用传递，这样，传递的值虽然改变，但是只想原始变量的单元却没有改变，具体来说就是：</p> <pre style="margin-top: 12px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">a = 23;</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">b = 34</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">swap(a, b);</span></pre> <pre style="margin-top: 0px; margin-bottom: 12px; font-family: 'Courier New,courier'; "></pre> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">执行上面一段语句会发现，其实a，b的值并没有交换，原因和C/C++的参数的值传递以及指针传递有关系。函数调用的时候，只会拷贝a，b的值，因此调用swap的时候，交换的是形参，实际参数的值并没有改变。</p> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">要实现真正参数传递的效果，需要用指针的形式来实现：</p> <pre style="margin-top: 12px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">void swap(int *vp1, int *vp2) {</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">    int a = *vp1;</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">    *vp1 = *vp2;</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">    *vp2 = *vp1;</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">}</span></pre> <pre style="margin-top: 0px; margin-bottom: 12px; font-family: 'Courier New,courier'; "></pre> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">再次调用swap(&amp;a, &amp;b)的时候，就会修改掉原来的值，因为这里传递过去的就是指针，所以，对<span style=" font-style:italic;">vp1，</span>vp2的操作 就是对指向单元a，b的操作，所以能够修改对应的值。</p> <p style="margin-top: 16px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; "><span style=" font-size:x-large; font-weight:600;">泛型交换与拷贝</span></p> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">上面的例子，只是对某种特定的类型进行交换，比如int类型，如果想对double类型等进行交换，只需要修改其类型为double即可，其他类型类似。 但是考虑到需要对多种不同类型进行交换，是否存在一种通用的方法呢？ 在C++中，可以用模板template技术，然而这里，回想起上节课中讲到的字节操作，能否利用字节的拷贝来实现呢？答案是肯定的。</p> <pre style="margin-top: 12px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">void swap(void *vp1, void *vp2, int size){</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">    char buffer[size];</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">    memcpy(buffer, vp1, size);</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">    memcpy(vp1, vp2, size);</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">    memcpy(vp2, buffer, size);</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">}</span></pre> <pre style="margin-top: 0px; margin-bottom: 12px; font-family: 'Courier New,courier'; "></pre> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">调用的时候，字号需要给定某个类型，即可实现。比如，通过：</p> <pre style="margin-top: 12px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">double a = 23.0, b = 34.0;</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">swap(&amp;a, &amp;b, sizeof(double));</span></pre> <pre style="margin-top: 0px; margin-bottom: 12px; font-family: 'Courier New,courier'; "></pre> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">当然，对于结构体也可以通过这种形式来进行拷贝。</p> <p style="margin-top: 14px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; "><span style=" font-size:large; font-weight:600;">关于上面例子的几点说明：</span></p> <ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style="margin-top: 12px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; ">这里声明数组的方式，使用的大小size是可变的，这只在某些编译器中支持，这里只是为了说明字符拷贝的方式，例子的重点在于交换。当然可以使用malloc或者new来动态分配大小可变的空间。</li> <li style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; ">这里使用memcpy(dest, src, size)这个函数来进行内存单元的拷贝，注意此函数并不关心你的数据类型，单纯的进行单元的拷贝而已，所以虽然编译可能通过，但是还需要自己进行判断和控制。</li> <li style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; ">这个例子的亮点就在于void*的使用，通过它能够实现泛型，即针对于int，short，char，struct等类型都能够保证能够拷贝交换成功。</li> <li style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; ">template和这里的区别和优缺点。注意到使用模板的话，编译后，会为每种类型都生成一种代码，比如int对应的，float对应的，这样如果调用次数很多的话，代码体积会增大，冗余过多。而这里编译出来就一套代码，更加简洁。</li> <li style="margin-top: 0px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">这里传递一个参数大小size是因为，由于泛型指针void*的存在，所以编译器并不知道要拷贝多少个字节，所以，需要你手动控制并指定一个大小。</li></ol> <p style="margin-top: 14px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; "><span style=" font-size:large; font-weight:600;">存在的问题</span></p> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">由于编译器会很容易的放过void*带来的错误，所以如果两个类型不同的数据调用此函数，就会出现问题：</p> <pre style="margin-top: 12px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">    double a = 23.0;</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">    int b = 345;</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">    swap(&amp;a, &amp;b, sizeof(double));</span></pre> <pre style="margin-top: 0px; margin-bottom: 12px; font-family: 'Courier New,courier'; "></pre> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">这里，double和int类型占据的数据空间的大小是不同的，因此，如果单纯的直接调用这个函数，就会出错，简单的结果就是，截断拷贝或者多拷贝数据。 比如，int类型拷贝到double数据空间的时候，只有前面2个字节拷贝了，后面的原来double数据的两个字节仍然保留了；或者说double拷贝到int的时候，可能会多拷贝两个字节到int后面的数据，造成出错。具体的方式，与后面一个参数sizeof(double)或者sizeof(int)有关系。</p> <p style="margin-top: 14px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; "><span style=" font-size:large; font-weight:600;">初学者容易犯的错误</span></p> <ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">使用void * tmp = vp1，而不是前面锁讲到的char buffer[size]，这个错误的原因是由于不理解void不是一个类型，不像int，double等属于一个类型，所以错误。void <span style=" font-style:italic;">只能用作函数参数，返回值才可行。但是可以使用 void * tmp = (int </span>)&amp;a这类的用法，因为具体的类型即可以赋值给一般的类型，你只有给定了一个具体的类型，才能让编译器知道规则，才能编译通过。</li> <li style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">指针的拷贝，何时使用引用地址的问题。一个简单的例子出发，</li></ol> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">char * husband = strdup("Fred"); char * wife = strdup("Wilma");</p> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">如果想交换两人所指向的空间内容，正确的做法是：</p> <pre style="margin-top: 12px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">swap(&amp;hustband, &amp;wife, sizeof(char *))</span></pre> <pre style="margin-top: 0px; margin-bottom: 12px; font-family: 'Courier New,courier'; "></pre> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">也就是说，这里要交换的是指针的地址，交换之后，husband的内容发生了变化，内容变成了原来wife的内容，由于本身是地址，所以内容变了，实际上所只想的地址也变了，现在husband指向原来wife所指向的地址，而wife指向原来husband指向的地址。</p> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">一个错误的例子就是，swap(husband, wife, &amp;sizeof(char <span style=" font-family:'Courier New,courier';">*</span>))，这样，交换的实际上是他们锁指向的内容，即存放Fred和Wilama的单元中的内容会交换，而且，由于char <span style=" font-family:'Courier New,courier';">*</span>是四个字节，因此交换的就只有四个字节的内容。 为何会如此呢？因为上面的例子，比如要交换a，b单元的内容，传入的就是a，b的地址&amp;a, &amp;b，同样，这里我直接传入指针，当然交换的是他们指向的单元的内容，即两个字符串。 所以要交换两个指针的内容，就要交换他们的地址，即指针的地址，指针的指针。</p> <p style="margin-top: 16px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; "><span style=" font-size:x-large; font-weight:600;">另外一个例子</span></p> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">思考一个下面线性搜索的例子，</p> <pre style="margin-top: 12px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">int * lsearch(int key ,int* array, int size){</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">    for (int i = 0; i &lt; size; i++)  </span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">    {</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">        if(array[i] == key)</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">            return i;</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">    }</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">}</span></pre> <pre style="margin-top: 0px; margin-bottom: 12px; font-family: 'Courier New,courier'; "></pre> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">上面的这段代码，直接返回的就是找到索引的那个下标。</p> <p style="margin-top: 14px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; "><span style=" font-size:large; font-weight:600;">利用位比较的方式来实现</span></p> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">同样，为了应用上面我们学到的知识，这里想要泛型比较，搜索，如何实现？ 例如，对于这里的int，能否用一个struct，一个double或者其他类型。 答案仍然是肯定的，只不过，我们需要对其中编译器的工作，比较的大小进行控制而已。</p> <pre style="margin-top: 12px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">int *lsearch(void *key, void *base, int size, int elementSize){</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">    for (int i = 0; i &lt; size; i++) {</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">      void * elemeAddr = (char *)base + i * elementSize; </span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">      if (memcmp(key, elemeAddr, elementSize) == 0)</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">        return elemeAddr;</span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">    }       </span></pre> <pre style="margin-top: 0px; margin-bottom: 0px; "><span style=" font-family:'Courier New,courier';">}</span></pre> <pre style="margin-top: 0px; margin-bottom: 12px; font-family: 'Courier New,courier'; "></pre> <p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; ">这里的几个说明点就是，首先，传入参数的size就是要比较的数组的大小，类型我们不知道，就用void *类型，然后要传入每一个类型的大小，elementSize，这个标记了每一个数组成员的大小，正因为有这个我们才可以精准的定位到具体的单元，利用for循环来比较每一个单元和key的关系。而这里比较用的memcmp来进行，比较的字节数就是elementSize，传入两个指针即可，而比较的指针就是数组的每一个单元的地址，即elemeAddr而已。<br /><br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;---Written by markdown and HTML file is generated by markdown.</p><p style="margin-top: 12px; margin-bottom: 12px; margin-left: 0px; margin-right: 0px; "></p><img src ="http://www.cppblog.com/deercoder/aggbug/180038.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/deercoder/" target="_blank">deercoder</a> 2012-06-24 16:57 <a href="http://www.cppblog.com/deercoder/archive/2012/06/24/180038.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>斯坦福大学开放课程：编程范式学习笔记《二》</title><link>http://www.cppblog.com/deercoder/archive/2012/05/13/174774.html</link><dc:creator>deercoder</dc:creator><author>deercoder</author><pubDate>Sun, 13 May 2012 10:03:00 GMT</pubDate><guid>http://www.cppblog.com/deercoder/archive/2012/05/13/174774.html</guid><wfw:comment>http://www.cppblog.com/deercoder/comments/174774.html</wfw:comment><comments>http://www.cppblog.com/deercoder/archive/2012/05/13/174774.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/deercoder/comments/commentRss/174774.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/deercoder/services/trackbacks/174774.html</trackback:ping><description><![CDATA[本课讲述了C/C++关于int，float等数据的底层表示，以及赋值操作所进行的处理。本节内容比较简单，应该属于组成原理的基础知识，各种码的表示和底层实现，但是，讲述还不错，特别是为何要这样形成补码，比单纯记忆强多了，这样才理解了取反加1的原因，比当初上课的时候要理解深刻多了。<br /><br />bool &nbsp; &nbsp;1byte<br />char &nbsp; &nbsp;1 byte<br />short &nbsp; 2 bytes<br />int &nbsp; &nbsp; &nbsp; &nbsp;2-4 bytes<br />float &nbsp; &nbsp; 4bytes<br />double &nbsp;8bytes<br /><br />binary &nbsp;digit ==&gt; bit<br />1byte = 8种bit的组合，即共有2的8次方这么多种选择。<br />每一位都有权值，对应的，2的0次方依次往上递增。<br /><br />short：2 bytes表示，共有2的16次方表示<br />但是并不是完全表示正数，最开始的符号位，1为负数，0为正数（实际上就是反码的表示方法）<br />缺陷： +7 + （-7），最终得到的数值用反码来表示的话不是0。<br />因此，计算机处理起来很麻烦，以备淘汰<br /><br />更优的办法是：补码表示，取反加1.<br />为何？ 从计算机表示的角度出发，+7 加上什么为0呢？ 接近0的数是，全部为1的（-1），然后加上1就可以溢出符号位，从而表示为0.<br />因此顺理成章的，负数的表示就是，正数的基础上，取反， 然后加1.<br /><br />一个例子：<br />char ch = 'A';<br />short s = ch;（不需要类型转换）<br />cout &lt;&lt; s结果是，65.<br />如何做的呢？计算机，just copy&nbsp;<br />bit pattern copy的形式，不管你的类型如何，直接进行拷贝，由于short比char多一个字符，所以拷贝的前一个byte直接用全0来复制。<br /><br />现在，另外考虑一个例子，截断。<br />short s = 67;<br />char ch = s;<br />问题是，short比char 要多一个byte，那么赋值的话，是尽可能的接近吗？<br />NO，计算机不懂值得大小，只会单纯的copy，因此，截断后面的1byte赋值过去而已。<br /><br />同样的，讲short赋值给int的时候也是这样处理的，高位全部copy为0，地位直接copy。而int赋值给short的时候，就是单纯的截断处理而已。<br />现在的问题来了，如果是负数呢？<br />short s =-1;<br />int i = s;<br />这个时候，前面的高位字节直接赋值为0的话，事实上数值的大小是变化的。因此计算机的做法是，拷贝符号位复制到高位。这样正数，就是拷贝的0，所以高位全为0，而负数的话高位1，拷贝的话，高位全1.最终保证i的值仍然是-1.<br /><br />接下来学习float的表示。<br />我们可以自定义一种解释float的方法。权重依次降低，比如从2的31次方到2的0次方，变为2的29次方到2的-1次方，最开始的那一位表示为+/-符号位，这样就可以表示一定的浮点数，同样的，再次降低权重就可以表示更低的数据了。<br />但是，实际上计算机的表示不是这样的<br /><br />采用了一种很奇怪的表示方法，即符号位（1位） + exp位（8位） + 浮点部分（23位）。<br />符号位表示政府，exp为8位的正数表示，浮点数表示0.XXXXX（0到1之间的数据）<br />最终浮点的值是，2的（exp - 127）次方 乘以 1.XXXX表示。<br /><br /><br />最后两个例子表示值拷贝的过程。<br />int i = 5;<br />float f = i;<br />输出的结果是f仍然是5，why？ 因为不是bit copy，这里是直接进行赋值，而类型不同，因此会先计算出来值得带下，然后转换一种类型表示出来。<br />也就是把5的int类型表示为float的类型，bit pattern是完全发生了变化的。<br /><br />另外一个例子。<br />int i = 37;<br />float f = *(float *) &amp;i;<br />这种是把i的地址取出来，认为它表示的是float，因为（float *）的作用，然后解释为float类型输出它的值，注意的是，bit pattern并不会发生变化。<br /><br />float f = 7.0;<br />short s = *(short *) &amp;f;<br />由于是不同的类型，short只会截取自己那么大size的byte来进行翻译，所以float类型尽管4bytes，但是认为是short类型的话，仍然截取的是2bytes。<br />从而输出short的值应该是一个比较小的值。注意，bit pattern并不会改变，只是取出来地址而已。<br /><br />总结的关键是：just copy bit pattern!<img src ="http://www.cppblog.com/deercoder/aggbug/174774.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/deercoder/" target="_blank">deercoder</a> 2012-05-13 18:03 <a href="http://www.cppblog.com/deercoder/archive/2012/05/13/174774.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>斯坦福大学开放课程：编程范式学习笔记《一》</title><link>http://www.cppblog.com/deercoder/archive/2012/04/29/173163.html</link><dc:creator>deercoder</dc:creator><author>deercoder</author><pubDate>Sun, 29 Apr 2012 10:26:00 GMT</pubDate><guid>http://www.cppblog.com/deercoder/archive/2012/04/29/173163.html</guid><wfw:comment>http://www.cppblog.com/deercoder/comments/173163.html</wfw:comment><comments>http://www.cppblog.com/deercoder/archive/2012/04/29/173163.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/deercoder/comments/commentRss/173163.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/deercoder/services/trackbacks/173163.html</trackback:ping><description><![CDATA[<div>  <p><span style="font-family: 宋体;">编程范式（</span>Paradigm<span style="font-family:宋体;">） Lesson 1 读书笔记：<br /></span></p>    <p><span style="font-family:宋体;">列举几种常见的编程语言（范式）：</span></p>    <p>C</p>  <p>Assembly</p>  <p>C++</p>  <p>Concurrency programming(<span style="font-family:宋体;">并行编程</span>) （只是一种范式，而不是语言，可以使用C/C++实现并行编程）<br /></p>  <p>Scheme</p>  <p>Python</p>  <p>&nbsp;</p>  <p>C<span style="font-family:宋体;">是面向过程，</span>C++<span style="font-family:宋体;">面向对象。</span>C<span style="font-family:宋体;">语言是函数调用函数，因此就像一个多级标题一样，通过函数</span>A<span style="font-family:宋体;">调用</span>B<span style="font-family:宋体;">，</span> <span style="font-family:宋体;">而函数</span>B<span style="font-family:宋体;">调用函数</span>C<span style="font-family:宋体;">，因此是有过程来决定一个函数的功能，我们首先看到的也就是一个过程（函数），通过指针来调用的。</span></p>  <p>&nbsp;</p>  <p>C++<span style="font-family:宋体;">是面向对象的，因此是通过&#8220;</span>-&gt;<span style="font-family:宋体;">&#8221;或者&#8220;</span>.<span style="font-family: 宋体;">&#8221;来进行访问的，我们首先看到的就是指针或者引用，也就是一个完整的对象。</span></p><p><span style="font-family:宋体;"><br /></span></p>  <p>这系列课程会详细讲述底层是如何将C/C++编译为汇编语言的，会进行指针的详细讲解，让你使用到**&amp;p-&gt; i = 7 这些很复杂的用法，虽然过程可能有些头疼，但是对于了解底层很有帮助，让你知道崩溃的时候是为什么，而不是看着它崩溃。当然，这种用法还是不值得提倡的。通过这些课程，可以让你成为一个高级C/C++工程师。<br /></p><p><br /></p>  <p><span style="font-family:宋体;">汇编语言是很古老的，不会详细讲。有一个语言</span>MITS<span style="font-family:宋体;">，有点意思，可以研究下。会重点讲述</span>C<span style="font-family:宋体;">和</span>C++<span style="font-family:宋体;">如何编译为</span>obj<span style="font-family:宋体;">文件，然后生成可执行的二进制文件，会发现原来</span>C<span style="font-family:宋体;">和</span>C++<span style="font-family:宋体;">最终生成的二进制代码（</span>0<span style="font-family:宋体;">和</span>1<span style="font-family:宋体;">形式的），其实差不多。</span></p>  <p>C++<span style="font-family:宋体;">去掉了面向对象的部分就是</span>C<span style="font-family:宋体;">，很多牛逼的工程师都倾向于使用</span>C<span style="font-family:宋体;">，尽管有很多优秀的语言在不同方面要比</span>C<span style="font-family:宋体;">优秀。</span></p>  <p>&nbsp;</p>  <p><span style="font-family:宋体;">并行编程并不是真的并行。原来的语言，如</span>C/C++<span style="font-family:宋体;">，实际上都是执行完一条之后再执行，而并行编程则是并行执行（感觉上并行，实际上是交替执行，只是这个交替的频率很高，用户看不到这个交替的过程而已，从而认为是并行执行）。</span></p>  <p><span style="font-family:宋体;">并行编程很多地方使用不到，但是在网络编程上面很有用处。一个例子就是，两个用户同时从取款机上取一定的钱，比如余额为</span>100<span style="font-family:宋体;">，要保证他们不会同时取走，就是这样一个过程。将这一次操作成为事务</span>(transaction)<span style="font-family:宋体;">。</span></p>  <p>&nbsp;</p>  <p>Scheme<span style="font-family:宋体;">是一个函数式的语言，和</span>LISP<span style="font-family:宋体;">有很深的渊源。可能大家不大了解，函数式的语言就是执行依赖于函数的返回结果。传统的语言有缺陷，比如</span>C/C++<span style="font-family:宋体;">，可能在传递指针的过程中，修改了这个结构体，然后再返回这个值，引起混乱。而函数式的语言就是，需要根据函数的返回值，决定下一步的执行。因此就不会出现这种问题。这门语言很有意思，大家可以学习一下，实际上比其他语言都要有意思（老师原语）。</span></p>  <p>&nbsp;</p>  <p>Python<span style="font-family:宋体;">是一门年轻语言，在</span>Google<span style="font-family:宋体;">和</span>facebook<span style="font-family:宋体;">有相当多的工程师使用这门语言来进行开发，很适合网络编程，不要认为网络编程就是</span>HTML<span style="font-family:宋体;">，网页之类，动态网页还需要处理后台数据库的交互等问题。</span>Python<span style="font-family:宋体;">才</span>16~17<span style="font-family:宋体;">年的历史，所以不会有想</span>C/C++<span style="font-family:宋体;">，</span>Java<span style="font-family:宋体;">那样的缺陷，课程的最后有个大作业，做一个网页服务器，不会像</span>Apache<span style="font-family:宋体;">那么大，但是能够解析</span>XML,HTML<span style="font-family:宋体;">，后台进行处理，生成动态页面。</span>Python<span style="font-family:宋体;">有很多类库，是面向对象的语言，解释执行，可以一边写一边解释执行，还有很多函数库，可以借用</span>Scheme<span style="font-family:宋体;">的思想来做函数式编程，处理网络编程很有用户。</span></p>  <p>&nbsp;</p>  <p><span style="font-family:宋体;">在过去课程最后是</span>C++<span style="font-family:宋体;">高级编程，后来就使用</span>Java<span style="font-family:宋体;">，，但是后来另外一个班教授的内容更深入，所以不交</span>Java<span style="font-family:宋体;">了。后来使用</span>python<span style="font-family:宋体;">，效果不错，课程最后是用</span>python<span style="font-family:宋体;">开发，会领会到其中美妙之处。</span></p>  <p>&nbsp;</p>  <p><span style="font-family:宋体;">最后还会介绍一下其他语言和范式，不过你们在今后</span>15<span style="font-family: 宋体;">年碰到的编程范式，我应该都见过（这个老师好自信啊）</span></p><p><br /><span style="font-family: 宋体;"></span></p><p><span style="font-family:宋体;">最后课程结束，整个过程17分钟左右。下周会发超多讲义，并会让你们做一个C/C++中指针的底层原理的研究报告。Over。<br /></span></p>  </div><img src ="http://www.cppblog.com/deercoder/aggbug/173163.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/deercoder/" target="_blank">deercoder</a> 2012-04-29 18:26 <a href="http://www.cppblog.com/deercoder/archive/2012/04/29/173163.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>