<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="http://feeds.qzone.qq.com/rss.xsl" version="1.0"?>
<rss version="2.0" xmlns:qz="http://qzone.qq.com">
<channel>
<title><![CDATA[Tomsdinary]]></title>
<description><![CDATA[大学纪念]]></description>
<link>http://843858859.qzone.qq.com</link>
<lastBuildDate>Wed, 25 Nov 2009 17:13:21 GMT</lastBuildDate>
<generator>Qzone</generator>
<language>zh-cn</language>
<copyright>Copyright (C), 2005-2008, Tencent Tech. Co., Ltd.</copyright>
<pubDate>Tue, 24 Nov 2009 11:35:12 GMT</pubDate>

<item>
<title><![CDATA[如何用VC6.0集成开发环境来构建MASM32汇编的编程环境]]></title>
<link>http://843858859.qzone.qq.com/blog/1259062512</link>
<description><![CDATA[<a href="http://www.360doc.com/content/090203/10/59579_2446700.html" target="_blank">http://www.360doc.com/content/090203/10/59579_2446700.html</a><wbr /><br> <br><span style="font-weight:bold"><wbr />如何用VC6.0集成开发环境来构建MASM32汇编的编程环境（原创）</span><wbr /><br><br>作者：maxzhou88（周哥）<br><br>  　开发高性能的程序少不了用汇编编程，限于C语言中内嵌汇编语言的局限（如在C代码中混合汇编语言编程时，很难实现跳表)，一些代码必须书写在独立的汇编源文件中。遗憾的是，在调试时，只能看到裸的汇编码，而不能到懂标号，变量等，现在能这样C与ASM混合编程就方便多了。<br><br>编程环境：VC6.0，Masm32v8<br><br>优点：<br>[1] 使用VC6.0集成开发环境可以利用其强大的Debug功能来实现源代码级调试(Source Code Debug),（看变量、设置断点、查看MASM32的高级命令展开......）<br>[2] 使用VC6.0的资源编辑器，可视化编辑资源。<br>[3] 实现C/C++与ASM的混合编程。<br>[4] 在窗口下比在CMD下工作符合一般人的习惯，再也不需要写makefile文件或xxx.bat文件了。<br><br>方法：<br>[1] 安装VC6.0，这个我就说了，大家都会的哦,一般我将它安装在 C:\Program Files\ Microsoft Visual Studio。<br>[2] 安装MASMv8.exe,一般我将它安装在 D:\MASM32 下。<br>[3] 将Win32ASM（masm32）中的ml.exe和ml.err拷贝到C:\Program Files\ Microsoft Visual Studio\VC98\Bin<br>[4] 使用VC6.0新建一个空工程，如：hello（类型为：win32 console、win32 application、DLL等均可）。<br>[5] 把汇编和资源文件拷至新建工程目录下（hello.asm，hello.rc），并把这些文件加入工程中(将*.asm添加到Source Files, 将*.rc添加到Resource Files)。<br>[6] 配置IDE（这就配置一次就搞定）：在VC的菜单tools/option…/paths(include files)中添加一个路径d:\MASM32\INCLUDE <br>[7] 配置工程（每个工程都要这样配置）：打开工程设置（project settings）,点击*.asm文件选择（Custom Build）,<br>                                      命令中加上： ml /c /coff /Zi /Fo$(TargetDir)\$(InputName).obj $(InputPath)<br>                                      输出中加上： $(TargetDir)\$(InputName).obj<br>    注意选Settings for: Win32 Debug 和 Win32 release，将上面的两条都加上，而且每个*.ASM文件（如有多个ASM时）都这样设置。<br><br>[8] 点击VC的编译（build）就可以运行了哦。<br><br>    至此就可以使用VC调试器源码级调试汇编程序了，可以设置断点，察看变量、内存、寄存器等，masm出现语法错误时可以双击output window中的错误行定位到程序中的指定行。<br>    为了不在debug和release目录中产生超大的预编译头文件xxxx.pch,在工程设置（project settings）中的C/C++ -&gt; Precompiled Headers的选项上选择&quot;不使用预编译头&quot;,其实就现在的电脑而言,不使用预编译头也能快速地编译C代码的哦.<br><br>    资源编译/编辑器蛮好用的.只是还有个问题我也没有搞懂:VC6.0的资源编译/编辑器不支持16进制的资源ID,非要用10进制的,我是用两种方法解决的:一是将资源文件*.rc中的ID改成10进制，这样就可以编辑修改了；二是直接用老罗书中的rc文件导入,但在VC6.0中不要打开编辑它就可以了. 有人能告诉我VC6.0的资源编辑器用16进制ID的方法嘛,可能这很简单,我没有去深究罢了.<br><br>有空来踩踩我的空间哦:http://hi.baidu.com/maxzhou88<br>该文在我的百度空间:http://hi.baidu.com/maxzhou88/blog/item/7c7b4b09181ce186d1581b8f.html<br>Win32 C++/ASM 混合编程的Demo下载: http://maxzhou88.ys168.com/pc<br><br>    我在学老罗的MASM32程序时都是象这样在VC6.0的集成环境下工作的，他书中的例子我基本都试验过，比在DOS（CMD窗口）下方便多了，也不要什么makefile文件，建个proj项目就搞定，最重要的是用VC的资源编辑器来编辑资源比原先手工编辑方便多了，如果有什么问题欢迎大家交流哦！<br><br>                                                         周哥（maxzhou88） 写于 2009-01-21<br><br>为了方便大家配置VC6.0 ，我在这里贴两张图：<br><wbr /><a href="http://b26.photo.store.qq.com/http_imgload.cgi?/rurl4_b=8250b2761d6f3d599cb1ff5372780a03ebf1e0a883fdf351555516ae07a3d40fabd8df4d71c18fc3ed21ef9d6921c6c7c6785c5c30ace00594fc2be54c43ea6e31f31d9bffa4e78002f54bc7ca783fd5a53ec99e&amp;a=26&amp;b=26" target="_blank"><img style="width:670px;height:448px;border:0;" src="http://b26.photo.store.qq.com/http_imgload.cgi?/rurl4_b=8250b2761d6f3d599cb1ff5372780a03ebf1e0a883fdf351555516ae07a3d40fabd8df4d71c18fc3ed21ef9d6921c6c7c6785c5c30ace00594fc2be54c43ea6e31f31d9bffa4e78002f54bc7ca783fd5a53ec99e&amp;a=26&amp;b=26" /></a><wbr /><br>　　<br>这是配置项目中每个ASM文件的Custom Build 注意：Debug 和 Release 版本都要设置)<br><wbr /><a href="http://b26.photo.store.qq.com/http_imgload.cgi?/rurl4_b=8250b2761d6f3d599cb1ff5372780a03dbf1a6e6c908b10ab82fcce5b5ced99cea23ab8bcf6ac8a1b8cf6812f766cf17cda93efd7abb46922458ca52d48d24437f6f51f5ba1717a534e65be054da39e9f8dc805b&amp;a=26&amp;b=26" target="_blank"><img style="width:549px;height:387px;border:0;" src="http://b26.photo.store.qq.com/http_imgload.cgi?/rurl4_b=8250b2761d6f3d599cb1ff5372780a03dbf1a6e6c908b10ab82fcce5b5ced99cea23ab8bcf6ac8a1b8cf6812f766cf17cda93efd7abb46922458ca52d48d24437f6f51f5ba1717a534e65be054da39e9f8dc805b&amp;a=26&amp;b=26" /></a><wbr /><br><br><br>这是配置VC6.0的IDE，就设置一遍就搞定了。<br><br>不过这两张图是我百度空间的，但百度是不提供图片外链服务的哦！别急，先分别右击这两张图的图框，在弹出菜单的“属性”中COPY图片的URL地址，然后将地址在IE中打开，这时图片就下载你机器的IE缓冲区中，再将这个看不到图的页面按F5刷新一下，哈哈！IE就直接从缓冲区中取图了，你也就看得见了。没有办法啊，对不能外链的图就只能这样麻烦得做了哦。<br><br>    另外，我在调试MASM32程序时还经常开CMD窗来实时查看变量，这也是种很好的Debug方法，其实在Win32下无所谓 windows窗口程序和console 控制台程序，也就是说在建立工程时可以选console 控制台程序类型来写windows窗口程序，反之亦然。我一般是这样做的，先将工程以windows窗口程序类型来建立新工程，当要用CMD窗口来调试输出变量时，我就将工程的link选项卡中的Project options中的subsystem:windows 换成 subsystem:console就可以了，这时候编译连接后程序运行就会出CMD窗口，当调试完后再改回subsystem:windows即可。<wbr /><a href="http://b26.photo.store.qq.com/http_imgload.cgi?/rurl4_b=8250b2761d6f3d599cb1ff5372780a0349723af3995dc8c5e631df25e8d2bf16c40330634094d20cad85ad6d47bcd23dfcba7add0ffd9c8d19e9c7bb2723a029605c4aac1fd3b7c6a273d6298ad973760e4a2487&amp;a=26&amp;b=26" target="_blank"><img style="width:670px;height:448px;border:0;" src="http://b26.photo.store.qq.com/http_imgload.cgi?/rurl4_b=8250b2761d6f3d599cb1ff5372780a0349723af3995dc8c5e631df25e8d2bf16c40330634094d20cad85ad6d47bcd23dfcba7add0ffd9c8d19e9c7bb2723a029605c4aac1fd3b7c6a273d6298ad973760e4a2487&amp;a=26&amp;b=26" /></a><wbr /><br><br><br><br>CMD控制台输出的代码片段如下:<br><br>.data?<br>szBuffer   db   'hello the world' ,0dh, 0ah ;要调试的输出内容<br>hStdOut   dd   ? ;控制台标准输出句柄，在CMD中是默认打开的<br>dwBytesWrite dd   ?<br>;用下列语句就可以实现CMD的输出<br>invoke WriteConsole, hStdOut, addr szBuffer, sizeof szBuffer, addr dwBytesWrite, NULL <!--v:3.2--> ]]></description>
<category><![CDATA[技术知识]]></category>
<author><![CDATA[843858859@qq.com(Tomsdinary)]]></author>
<comments>http://843858859.qzone.qq.com/blog/1259062512#comment</comments>
<qz:effect>142606849</qz:effect>
<pubDate>Tue, 24 Nov 2009 11:35:12 GMT</pubDate>
<guid>http://843858859.qzone.qq.com/blog/1259062512</guid>
</item>

<item>
<title><![CDATA[C语言版生产者消费者  Windows平台]]></title>
<link>http://843858859.qzone.qq.com/blog/1258978558</link>
<description><![CDATA[#include &lt;process.h&gt;<br>#include &lt;windows.h&gt;<br>#define SIZE 20<br>int in, out;<br>int buffer[SIZE];<br>HANDLE hFull;<br>HANDLE hEmpty;<br>HANDLE hMutex;<br>unsigned int _stdcall Producer (void* )<br>{<br> int x=0;<br> for ( ;; )<br> {<br>  ::WaitForSingleObject(hFull, INFINITE);<br>  ::WaitForSingleObject(hMutex, INFINITE);<br>  buffer[in]=x++;<br>  printf(&quot;produce %d\n&quot;, buffer[in]);<br>  in=(in+1)%SIZE;<br>  ::ReleaseMutex(hMutex);<br>  ::ReleaseSemaphore(hEmpty, 1, NULL);<br> }<br> return 0;<br>}<br>unsigned int _stdcall Customer (void* )<br>{<br> int y;<br> for ( ;; )<br> {<br>  ::WaitForSingleObject(hEmpty, INFINITE);<br>  ::WaitForSingleObject(hMutex, INFINITE);<br>  y=buffer[out];<br>  out=(out+1)%SIZE;<br>  printf(&quot;consume %d\n&quot;, y);<br>  ::ReleaseMutex(hMutex);<br>  ::ReleaseSemaphore(hFull, 1, NULL);<br>  ::Sleep(1000);<br> }<br> return 0;<br>}<br>int _tmain(int argc, _TCHAR* argv[])<br>{<br> in=out=0;<br> hFull=::CreateSemaphore(NULL, SIZE, SIZE, NULL);<br> hEmpty=::CreateSemaphore(NULL, 0, SIZE, NULL);<br> hMutex=::CreateMutex(NULL, FALSE, NULL);<br> HANDLE hProducer=(HANDLE)::_beginthreadex(NULL, 0, Producer, NULL, 0, NULL);<br> HANDLE hCustomer=(HANDLE)::_beginthreadex(NULL, 0, Customer, NULL, 0, NULL);<br> ::WaitForSingleObject(hCustomer, INFINITE);<br> ::CloseHandle(hMutex);<br> ::CloseHandle(hFull);<br> ::CloseHandle(hEmpty);<br> ::CloseHandle(hProducer);<br> ::CloseHandle(hCustomer);<br> <br> return 0;<br>} <!--v:3.2--> ]]></description>
<category><![CDATA[程序设计之路]]></category>
<author><![CDATA[843858859@qq.com(Tomsdinary)]]></author>
<comments>http://843858859.qzone.qq.com/blog/1258978558#comment</comments>
<qz:effect>142606848</qz:effect>
<pubDate>Mon, 23 Nov 2009 12:15:58 GMT</pubDate>
<guid>http://843858859.qzone.qq.com/blog/1258978558</guid>
</item>

<item>
<title><![CDATA[Java版生产者消费者模型]]></title>
<link>http://843858859.qzone.qq.com/blog/1258978406</link>
<description><![CDATA[package book.thread.product;<br>/**<br> * 产品的仓库类<br> * 内部采用数组来表示循环队列，以存放产品。<br> */<br>public class Warehouse {<br> //仓库的容量<br> private static int CAPACITY = 11;<br> //仓库里的产品<br> private Product[] products;<br> <br> //[front, rear)区间的产品是未被消费的<br> //当前仓库中第一个未被消费的产品的下标<br> private int front = 0;<br> //仓库中最后一个未被消费的产品的下标加1<br> private int rear = 0;<br> public Warehouse(){<br>  this.products = new Product[CAPACITY];<br> }<br> public Warehouse(int capacity) {<br>  this();<br>  if (capacity &gt; 0){<br>   CAPACITY = capacity + 1;<br>   this.products = new Product[CAPACITY];<br>  }<br> }<br> /**<br>  * 从仓库获取一个产品<br> */<br> public Product getProduct() throws InterruptedException {<br>  synchronized (this) {<br>   //标志消费者线程是否还在运行<br>   boolean consumerRunning = true;<br>   //获取当前线程<br>   Thread currentThread = Thread.currentThread();<br>   if (currentThread instanceof Consumer){<br>    consumerRunning = ((Consumer)currentThread).isRunning();<br>   } else {<br>    //非消费者不能获取产品<br>    return null;<br>   }<br>   //如果仓库中没有产品，而且消费者线程还在运行，则消费者线程继续等待。<br>   while ((front == rear) &amp;&amp; consumerRunning){<br>    wait();<br>    consumerRunning = ((Consumer)currentThread).isRunning();<br>   }<br>   //如果消费者线程已经没有运行了，则退出该方法，取消获取产品<br>   if (!consumerRunning){<br>    return null;<br>   }<br>   //取当前未被消费的第一个产品<br>   Product product = products[front];<br>   System.out.println(&quot;Consumer[&quot; + currentThread.getName()<br>     + &quot;] getProduct: &quot; + product);<br>   //将当前未被消费产品的下标后移一位，如果到了数组末尾，则移动到首部。<br>   front = (front + 1 + CAPACITY) % CAPACITY;<br>   System.out.println(&quot;仓库中还没有被消费的产品数量：&quot;<br>     + (rear + CAPACITY - front) % CAPACITY);<br>   //通知其他等待线程<br>   notify();<br>   return product;<br>  }<br> }<br> /**<br>  * 向仓库存储一个产品<br>  */<br> public void storageProduct(Product product) throws InterruptedException {<br>  synchronized (this) {<br>   //标志生产者线程是否在运行<br>   boolean producerRunning = true;<br>   //获取当前线程<br>   Thread currentThread = Thread.currentThread();<br>   if (currentThread instanceof Producer){<br>    producerRunning = ((Producer)currentThread).isRunning();<br>   } else {<br>    //不是生产者不能存储产品<br>    return;<br>   }<br>   //如果最后一个未被消费产品与第一个未被消费的产品的下标紧挨着，<br>   //则说明没有存储空间，如果没有存储空间而且生产者线程还在运行，则等待仓库释放产品。<br>   while (((rear + 1) % CAPACITY == front) &amp;&amp; producerRunning) {<br>    wait();<br>    producerRunning = ((Producer)currentThread).isRunning();<br>   }<br>   //如果生产者线程已经停止了，则停止产品的存储。<br>   if (!producerRunning){<br>    return;<br>   }<br>   //保存参数产品到仓库<br>   products[rear] = product;<br>   System.out.println(&quot;Producer[&quot; + Thread.currentThread().getName()<br>     + &quot;] storageProduct: &quot; + product);<br>   //将rear下标循环后移一位<br>   rear = (rear + 1) % CAPACITY;<br>   System.out.println(&quot;仓库中还没有被消费的产品数量：&quot;<br>     + (rear + CAPACITY - front) % CAPACITY);<br>   notify();<br>  }<br> }<br>}<br>package book.thread.product;<br>/**<br> * 生产者类，采用线程，模拟生产者的行为<br> */<br>class Producer extends Thread {<br> // 生产者存储产品的仓库<br> private Warehouse warehouse;<br> // 产品的名字<br> private static int produceName = 0;<br> //是否需要结束线程的标志位<br> private boolean running = false;<br> public Producer(Warehouse warehouse, String name) {<br>  super(name);<br>  this.warehouse = warehouse;<br> }<br> public void start(){<br>  this.running = true;<br>  super.start();<br> }<br> public void run() {<br>  Product product;<br>  try {<br>   while (running) {<br>    //生产并存储产品<br>    product = new Product((++produceName) + &quot;&quot;);<br>    this.warehouse.storageProduct(product);<br>    sleep(300);<br>   }<br>  } catch (InterruptedException ie) {<br>   ie.printStackTrace();<br>  }<br> }<br> /**<br>  * 停止生产者线程<br>  */<br> public void stopProducer(){<br>  synchronized (warehouse){<br>   this.running = false;<br>   //通知等待仓库的线程<br>   warehouse.notifyAll();<br>  }<br> }<br> //生产者线程是否在运行<br> public boolean isRunning() {<br>  return running;<br> }<br>}<br>package book.thread.product;<br>/**<br> *消费者，采用线程，模拟消费者行为<br> */<br>class Consumer extends Thread {<br> //消费者获取产品的仓库<br> private Warehouse warehouse;<br> //是否需要结束线程的标志位<br> private boolean running = false;<br> public Consumer(Warehouse warehouse, String name) {<br>  super(name);<br>  this.warehouse = warehouse;<br> }<br> public void start(){<br>  this.running = true;<br>  super.start();<br> }<br> <br> public void run() {<br>  Product product;<br>  try {<br>   while (running) {<br>    //从仓库中获取产品<br>    product = warehouse.getProduct();<br>    sleep(500);<br>   }<br>  } catch (InterruptedException ie) {<br>   ie.printStackTrace();<br>  }<br> }<br> /**<br>  * 停止消费者线程<br>  */<br> public void stopConsumer(){<br>  synchronized (warehouse){<br>   this.running = false;<br>   //通知等待仓库的线程<br>   warehouse.notifyAll();<br>  }<br> }<br> //消费者线程是否在运行<br> public boolean isRunning() {<br>  return running;<br> }<br>}<br>package book.thread.product;<br>/**<br> * 产品类<br> */<br>public class Product {<br> //产品名<br> private String name;  <br> <br> public Product(String name){<br>  this.name=name;   <br> }  <br> public String toString() {  <br>  return &quot;Product-&quot; + name;  <br> }<br>}<br>package book.thread.product;<br>/**<br> * 测试生产者——消费者<br> * 支持多个生产者和消费者<br> */<br>public class TestProduct {<br> public static void main(String[] args) {<br>  //建立一个仓库，容量为10<br>  Warehouse warehouse = new Warehouse(10);<br>  <br>  //建立生产者和消费者<br>  Producer producers1 = new Producer(warehouse, &quot;producer-1&quot;);<br>  Producer producers2 = new Producer(warehouse, &quot;producer-2&quot;);<br>  Producer producers3 = new Producer(warehouse, &quot;producer-3&quot;);<br>  Consumer consumers1 = new Consumer(warehouse, &quot;consumer-1&quot;);<br>  Consumer consumers2 = new Consumer(warehouse, &quot;consumer-2&quot;);<br>  Consumer consumers3 = new Consumer(warehouse, &quot;consumer-3&quot;);<br>  Consumer consumers4 = new Consumer(warehouse, &quot;consumer-4&quot;);<br>  //启动生产者和消费者线程<br>  producers1.start();<br>  producers2.start();<br>  consumers1.start();<br>  producers3.start();<br>  consumers2.start();<br>  consumers3.start();<br>  consumers4.start();<br>  //让生产者消费者程序运行1600ms<br>  try {<br>   Thread.sleep(1600);<br>  } catch (InterruptedException e) {<br>   e.printStackTrace();<br>  }<br>  //停止生产者和消费者的线程<br>  producers1.stopProducer();<br>  consumers1.stopConsumer();<br>  producers2.stopProducer();<br>  consumers2.stopConsumer();<br>  producers3.stopProducer();<br>  consumers3.stopConsumer();<br>  consumers4.stopConsumer();<br> }<br>} <!--v:3.2--> ]]></description>
<category><![CDATA[技术知识]]></category>
<author><![CDATA[843858859@qq.com(Tomsdinary)]]></author>
<comments>http://843858859.qzone.qq.com/blog/1258978406#comment</comments>
<qz:effect>142606848</qz:effect>
<pubDate>Mon, 23 Nov 2009 12:13:26 GMT</pubDate>
<guid>http://843858859.qzone.qq.com/blog/1258978406</guid>
</item>

<item>
<title><![CDATA[我的第一个MASM32窗口应用]]></title>
<link>http://843858859.qzone.qq.com/blog/1258954488</link>
<description><![CDATA[.386<br>.model flat, stdcall<br>option casemap:none<br>include windows.inc<br>include gdi32.inc<br>includelib gdi32.lib<br>include user32.inc<br>includelib user32.lib<br>include kernel32.inc<br>includelib kernel32.lib<br>.data?<br> hInstance dd ?<br> hWinMain  dd ?<br>.const<br> szClassName db 'MyClass', 0<br> szCaptionMain db 'My first Window', 0<br> szText db 'Win32 Assembly, Simple and powerful', 0<br>.code<br> <br>WindowProc_ proc uses ebx edi esi,<br> hWnd:dword, message:dword, wParam:dword, lParam:dword<br> local @stPs:PAINTSTRUCT<br> local @stRect:RECT<br> local @hDC:dword<br> <br> mov eax, message<br> .if eax == WM_PAINT<br>  invoke BeginPaint, hWnd, addr @stPs<br>  mov @hDC, eax<br>  invoke GetClientRect, hWnd, addr @stRect<br>  invoke DrawText, @hDC, addr szText, -1, addr @stRect, DT_SINGLELINE or DT_CENTER or DT_VCENTER<br>  invoke EndPaint, hWnd, addr @stPs<br> .elseif eax == WM_CLOSE<br>  invoke DestroyWindow, hWinMain<br>  invoke PostQuitMessage, NULL<br> .else<br>  invoke DefWindowProc, hWnd, message, wParam, lParam<br>  ret<br> .endif<br> xor eax, eax<br> ret<br>WindowProc_ endp<br>WinMain_ proc<br> local @stWndClass:WNDCLASSEX<br> local @stMsg:MSG<br> invoke GetModuleHandle, NULL<br> <br> mov hInstance, eax<br> invoke RtlZeroMemory, addr @stWndClass, sizeof @stWndClass<br> invoke LoadCursor, 0, IDC_ARROW<br> mov @stWndClass.hCursor, eax<br> push hInstance<br> pop @stWndClass.hInstance<br> mov @stWndClass.cbSize, sizeof WNDCLASSEX<br> mov @stWndClass.lpfnWndProc, offset WindowProc_<br> mov @stWndClass.hbrBackground, COLOR_WINDOW+1<br> mov @stWndClass.lpszClassName,offset szClassName<br>    invoke RegisterClassEx,addr @stWndClass<br>  invoke  CreateWindowEx,WS_EX_CLIENTEDGE,\<br>                     offset szClassName,offset szCaptionMain,\<br>                        WS_OVERLAPPEDWINDOW,\<br>                        100,100,600,400,\<br>                        NULL,NULL,hInstance,NULL<br>    mov hWinMain,eax<br>    invoke  ShowWindow,hWinMain,SW_SHOWNORMAL<br>    invoke   UpdateWindow,hWinMain<br> .while   TRUE<br>     invoke    GetMessage,addr @stMsg,NULL,0,0<br>        .break    .if eax  == 0<br>        invoke    TranslateMessage,addr @stMsg<br>        invoke    DispatchMessage,addr @stMsg<br>    .endw<br>   ret<br>WinMain_ endp<br>start:<br> call     WinMain_<br>    invoke   ExitProcess,NULL<br>end      start <!--v:3.2--> ]]></description>
<category><![CDATA[程序设计之路]]></category>
<author><![CDATA[843858859@qq.com(Tomsdinary)]]></author>
<comments>http://843858859.qzone.qq.com/blog/1258954488#comment</comments>
<qz:effect>142606848</qz:effect>
<pubDate>Mon, 23 Nov 2009 05:34:48 GMT</pubDate>
<guid>http://843858859.qzone.qq.com/blog/1258954488</guid>
</item>

<item>
<title><![CDATA[我的第一个MASM32应用]]></title>
<link>http://843858859.qzone.qq.com/blog/1258954444</link>
<description><![CDATA[.386<br>.model flat, stdcall<br>option casemap:none<br>include windows.inc<br>include user32.inc<br>includelib user32.lib<br>include kernel32.inc<br>includelib kernel32.lib<br>.data<br>　　szCaption db 'I love you', 0<br>　　szText db 'Happy birthday to you', 0<br>.code <br>start:<br> 　　invoke MessageBox, NULL, offset szText, offset szCaption, MB_OK or MB_ICONINFORMATION<br> 　　invoke ExitProcess, NULL<br>end start <!--v:3.2--> ]]></description>
<category><![CDATA[程序设计之路]]></category>
<author><![CDATA[843858859@qq.com(Tomsdinary)]]></author>
<comments>http://843858859.qzone.qq.com/blog/1258954444#comment</comments>
<qz:effect>142606848</qz:effect>
<pubDate>Mon, 23 Nov 2009 05:34:04 GMT</pubDate>
<guid>http://843858859.qzone.qq.com/blog/1258954444</guid>
</item>

<item>
<title><![CDATA[Java线程同步]]></title>
<link>http://843858859.qzone.qq.com/blog/1258778160</link>
<description><![CDATA[　　注：wait notify 都是Object的方法<br>同步（阻塞） ：是一种防止对共享资源访问导致的数据不一致的一种模式。<br>详细请参看操作系统。<br><br>在Java中，由于对多线程的支持，对同步的控制主要通过以下几个方法，synchronized，和wait(),notify()和notifyAll(),下面进行一一的讲解：<br><br>A关键字synchronized<br>每个java对象都有一把锁， 当有多个线程同时访问共享资源的时候， 需要Synchronize 来控制安全性， synchronize 分 synchronize 方法 和synchronize块，使用synchronize块时， 一定要显示的获得该对象的锁（如synchronize（object))而方法则不需要。<br>java的内存模型是对每一个进程有一个主内存， 每个线程有自己的内存， 他们从主内存中取数据， 然后计算， 再存入主内存中。 <br>并发问题如下：如果多个线程同事操作同一数据， A线程从主内存中取的I的值为1， 然后进行加1操作， 这时B线程也取I的值， 进行加2操作， 然后A存入2到主内存中， B也存入， 这样就覆盖了A的值（同数据库中的并发问题一样）。<br>解决办法是用synchronize， 如用synchronized（I）。被synchronize 修饰的方法（块）把以下三步操作当成一个原子操作：取数据， 操作数据， 存数据。 我们知道原子操作是不可以被打断的， 所以其保证了数据一致性， 这样同一时间只有一个线程再执行， 对性能有一定的影响。这也是synchronize的第二个作用：保证统一时间只有一个线程再运行。 当实现SOCKET连接的时候经常用到.<br>JAVA中规定对非FLOAT, LONG的原始类型的取和存操作为原子操作。 其实就是对一个字（32位）的取，存位原始操作， 因为FLOAT, LONG为两个字节的长度， 所以其取， 存为非原子操作。 如果想把他们也变为原子操作， 可以用VOLATILE关键字来修饰<br><br>使用方法：<br>作用区域主要有两种：<br>1.方法<br>2.代码块<br>被synchronized声明的方法被称为同步方法，被其修饰的代码块称为同步语句。无论是同步方法还是同步语句，只要声明为同步了，在同一时刻，同一个对象的同步XX是不可以被同时访问的，而不同对象之间的同步方法是互不干扰的。<br><br>具体实现（如下代码都在某个类定义中）：<br>同步方法：<br>Public synchronized void change() {<br>//<br>}<br><br>同步语句：（因为效率问题，有时考虑使用同步语句块）<br>    Public void change() {<br>Synchronized(this) {<br><br>}<br>}<br>这个同步语句是针对当前对象的，有时，我们就是想让一段代码同步，可能与当前对象并没什么关系，可以自定义同步的锁。如下：<br>private byte[]  lock= new byte[0];<br><br> <br>  Public void change() {<br>Synchronized(lock) {<br><br>}<br>}<br>自定义锁注意事项：<br>1必须是private，防止在类外部引用改变。<br>2如果可能用到，重写get方法，返回对象的clone,而不是本身。<br> <br> <br>其他用法：<br>Synchronized除了可以作用于方法，代码块，还可以作用于静态方法，类，某个实例。但是都存在效率问题，一定要慎用。<br><br>Class Foo 　　{ 　　<br><br>public synchronizedstatic void methodAAA()// 同步的static 函数　　<br>{ 　　<br><br>//….　　<br><br>} 　<br>　 public void methodBBB() 　　{ 　　<br><br>synchronized(Foo.class)// class literal(类名称字面常量)　<br><br>　} }<br>这样修饰后代表的是：统一时刻，被修饰部分只有一个对象可以运行，因为它的声明是针对类的。<br><br>2.wait()/notify()/notifyAll()<br><br>注意：<br>在Java中，每个对象都有个对象锁标志(Object lock flag)与之想关联，当一个线程A调用对象的一段synchronized代码时，<br>  它首先要获取与这个对象关联的对象锁标志，然后执行相应的代码，执行结束后，把这个对象锁标志返回给对象；因此，在线程A执行<br>  synchronized代码期间，如果另一个线程B也要执行同一对象的一段synchronized代码时（不一定与线程A执行的相同），它将<br>  要等到线程A执行完后，才能继续....<br>  <br>  如何利用wait() notify() notifyAll()?<br>  <br>  在synchronized代码被执行期间，线程可以调用对象的wait()方法，释放对象锁标志，进入等待状态，并且可以调用notify()或者<br>  notifyAll()方法通知正在等待的其他线程。notify()通知等待队列中的第一个线程，notifyAll()通知的是等待队列中的所有线程<br><span style="text-decoration:underline;"><wbr /></span><wbr /><br>本文来自CSDN博客，转载请标明出处：<a href="http://blog.csdn.net/weizhaozhe/archive/2009/02/22/3922647.aspx" target="_blank">http://blog.csdn.net/weizhaozhe/archive/2009/02/22/3922647.aspx</a><wbr /> <!--v:3.2--> ]]></description>
<category><![CDATA[技术知识]]></category>
<author><![CDATA[843858859@qq.com(Tomsdinary)]]></author>
<comments>http://843858859.qzone.qq.com/blog/1258778160#comment</comments>
<qz:effect>142606848</qz:effect>
<pubDate>Sat, 21 Nov 2009 04:36:00 GMT</pubDate>
<guid>http://843858859.qzone.qq.com/blog/1258778160</guid>
</item>

<item>
<title><![CDATA[谷歌操作系统没有技术含量]]></title>
<link>http://843858859.qzone.qq.com/blog/1258769469</link>
<description><![CDATA[1、启动快速是Linux+SSD的功劳。从国外的网站得知，现在版本的谷歌操作系统启动时间是7秒钟，这个成绩只能说还好，并且不能完全算谷歌的功劳。假设一个没有预装任何应用、新装的简化版本Linux，加上一个飞速的SSD固态硬盘，也差不多就是这个时间了。<br><br>而对比一下Windows 7，如果同样的硬件环境，会稍长一些，但并不让人抓狂。<br><br>2、所有应用都基于Web，这是Chrome浏览器+一堆web应用的功劳。从这个意义上来说，谷歌操作系统的发布，其实是它苦心经营多年的最后一步而已。在谷歌的思想中，操作系统唯一存在的价值，就是让Chrome浏览器能运行、并正常访问互联网，仅此而已。<br><br>3、全新的安全计算模式，差不多就是有了验证机制的还原精灵。由于所有行为都在浏览器中操作，所有数据都存于云端，所以谷歌操作系统无需考虑数据备份、数据安全问题，这就意味着，它能随意让操作系统重新恢复不管病毒、木马如何攻击你的系统，一切清零即可。<br><br>所以我认为单纯讲谷歌操作系统没有什么技术含量可言，但这并不代表我不欣赏它，更不代表它未来没有市场。所谓技术含量与市场占有率，根本就没有什么逻辑关系。如果谷歌操作系统能够成功击败Windows，最大的功臣应该是谷歌一切以网络为中心的思想，最重要的工具应该是Chrome浏览器。<br><br>但我还要提出一个观点：在未来的很长时间里，谷歌操作系统依然还只能是个玩具，它尚不具备与Windows抗衡的整体实力。不是它不够出色，而是谷歌需要芯片厂商、软件商、开发者、PC厂商等诸多盟友的支持。<br><br>但问题可能就在这里，对于那些诞生在Windows同时代的软件商们，他们已经习惯了靠收取授权费过活，它们的经营思路很多都是与互联网相悖的，要说服它们，不是那么容易。更何况，谷歌操作系统本身在砸很多人的饭碗。<br><br><span style="color:#cc3300;font-size:24px;line-height:1.8em;"><span style="font-weight:bold"><wbr />总之，谷歌操作系统不是一件技术的事，是一件利益重新划分的事。</span><wbr /></span><wbr /> <!--v:3.2--> ]]></description>
<category><![CDATA[IT新闻]]></category>
<author><![CDATA[843858859@qq.com(Tomsdinary)]]></author>
<comments>http://843858859.qzone.qq.com/blog/1258769469#comment</comments>
<qz:effect>134218240</qz:effect>
<pubDate>Sat, 21 Nov 2009 02:11:09 GMT</pubDate>
<guid>http://843858859.qzone.qq.com/blog/1258769469</guid>
</item>

<item>
<title><![CDATA[谷歌Chrome OS说明会：失望大于希望？]]></title>
<link>http://843858859.qzone.qq.com/blog/1258768572</link>
<description><![CDATA[<a href="http://news.csdn.net/a/20091120/215051.html" target="_blank">http://news.csdn.net/a/20091120/215051.html</a><wbr /><br> <br>这两天，谷歌发布Chrome OS的消息引得人们格外关注和期待。为此笔者在此前写了篇对于此款操作系统提前发布的文章，提出了自己的一些困惑。还好，就在这篇文章的两天后，今天凌晨，谷歌在美国举行了Chrome OS的说明会。这至少验证了笔者之前的判断，谷歌此次只是说明会，而非发布，因为其一是根本不会提供用户的下载，其二是笔者之前文章的困惑在谷歌的说明会上基本没有找到答案，三是在Chrome操作系统新闻说明会上，谷歌产品副总裁Sundar Pichai就上市时间明确表态，2010年假期前有可能发布。不过通过说明会上再简单不过的演示，笔者对于谷歌的Chrome OS还是有了些比较模糊的认识。<br><br><span style="font-weight:bold"><wbr />是Chrome浏览器的翻版吗？</span><wbr />至少从界面上看，实在是太像了。唯一不同的是，在这个浏览器中，多了些谷歌称之为的Panel的东西，就是应用程序吧。当然这些应用程序基本是都是谷歌自己的在线应用程序。例如Gmail、Google Doc等。点击后就会链接到谷歌相关应用程序的网站运行。从这点上看，这些所谓Panel图表更像是一个个应用网站的链接。如果这就是最终Chrome OS的界面的话，这样的操作系统可以称之为操作系统吗？不就是在Chrome浏览器中加了些链接吗？从谷歌说明会一上来，谷歌副总裁Sundar Pichai就大谈Chrome浏览器就知道谷歌Chrome OS与Chrome浏览器的密切关系，但令笔者没有想到的是这种密切竟然让人误以为Chrome OS就是Chrome浏览器，当然除了界面外，还有那再简单不过的应用链接。<br><br><span style="font-weight:bold"><wbr />是免费的操作系统吗？</span><wbr />之前，业内和人们为谷歌Chrome OS兴奋不已和充满期待的一个重要原因是谷歌的Chrome OS会像谷歌多数的产品一样免费提供给用户使用。例如用户可以免费下载或者OEM厂商免费预装到PC中。不过谷歌今天的说明会中提及的预装方式，至少让用户可以免费下载这条路已经行不通了。之前笔者曾经撰文称谷歌操作系统推广的关键在PC中的预装，否则用户根本没有必要再去安装一个操作系统，即使是免费下载。看谷歌还是很清楚这点的。此外，预装谷歌Chrome OS操作系统的PC（硬件）厂商都是要经过谷歌验证的，这意味着OEM厂商预装时是要付费的，就是付费多少的问题了。还有就是谷歌之所以采取这种策略，还在于可以巧妙地回避其硬件兼容性差的软肋。<br><br><span style="font-weight:bold"><wbr />用户选择终端会受限和被绑定吗？</span><wbr />从谷歌说明会上的介绍看，不支持硬盘，与OEM厂商的认证等可以确认的是，用户未来选择终端的类型可能会受到限制。例如拿谷歌称的未来主要支持上网本看，首先主流的笔记本用户将无法使用谷歌的Chrome OS。此外，就是在上网本市场，用户选择上网本的种类（包括同一厂商的）也要依据OEM厂商预装的数量和种类而定。而用户一旦选择了预装有Chrome OS的上网本，将无法安装别的系统和应用，用户有被利用Chrome OS绑定某一OEM厂商硬件上的危险。换言之，用户购买的某一预装有Chrome OS的上网本，只能运行这个系统和基于其上的应用（主要是谷歌的在线应用），否则就只能是个摆设。难怪谷歌在说明会上称，希望使用谷歌Chrome OS系统的用户，最好还有另外的一台PC（笔记本）。言外之意，装有Chrome OS的笔记本将是Google系统和应用的专有平台。<br><br><span style="font-weight:bold"><wbr />离线后的应用将无法运行吗？</span><wbr />从说明会上的演示看，用户在登陆进入谷歌的Chrome OS系统后只有始终在线，才能运行日常的一些程学（例如文字处理、游戏等），一旦离线，所有的应用都将被终止。因为Chrome OS不支持硬盘，同时谷歌声称出于安全性的考虑，Chrome OS不支持任何程序的安装。这很符合谷歌的希望用户始终在线的战略，但以操作系统的形式强制用户滞留在网上这种做法确实值得商榷。其次，这种操作系统的机制还会导致，除了断网，一旦没有网络，用户的终端将一无是处。不过人家谷歌已经解释了，Chrome OS使得用户的PC更像是一个大的缓存，只不过这个缓存的代价对于用户来说是不是太大了。有限的应用，无法替换的系统、始终在线和由此而被绑定的终端。<br>除了这些模糊认识之外，笔者认为谷歌此次说明会上总结的谷歌Chrome OS的快速性、易用性以及安全性的特点也令人比较模糊，尤其是在上述的模糊未能清晰前。类似于浏览器的操作系统（不知与Chrome浏览器机制是否有很大的相似性），启动一个浏览器自然比启动一个真正的操作系统要快得多，这也是为何谷歌在说明会上提出对于之前的Chrome浏览器进行了20多次改进的原因。至于易用性，在界面上点击几个网站的链接，自然比运行一个程序要简单得多，而安全性，不让任何非谷歌认证程序的本地运行和安装（而且没有硬盘），自然是安全的，而且这个系统只是充当硬缓存的作用，只要谷歌服务器那边安全性没有问题的话。但这些有想放一部分是在牺牲掉了用户选择、使用和便利的前提下获得的。<br><br>总之通过谷歌的这次说明会，笔者认为这符合谷歌的互联网战略，但对于市场和用户而言，确是失望大于希望。所幸的是，距离谷歌正式发布Chrome OS还有近一年的时间，希望谷歌到时候真的可以带给市场和用户以惊喜。 <!--v:3.2--> ]]></description>
<category><![CDATA[IT新闻]]></category>
<author><![CDATA[843858859@qq.com(Tomsdinary)]]></author>
<comments>http://843858859.qzone.qq.com/blog/1258768572#comment</comments>
<qz:effect>142606848</qz:effect>
<pubDate>Sat, 21 Nov 2009 01:56:12 GMT</pubDate>
<guid>http://843858859.qzone.qq.com/blog/1258768572</guid>
</item>

<item>
<title><![CDATA[VC10中的C++0x特性 part 3 (1)：声明之类型]]></title>
<link>http://843858859.qzone.qq.com/blog/1258766708</link>
<description><![CDATA[今天我要讲 decltype，它让完美转发函数能够返回任意类型的东西。对编写高度泛型的人来说这是很有趣的的特性。<br><br><span style="font-weight:bold"><wbr />返回</span><wbr /><span style="font-weight:bold"><wbr />类</span><wbr /><span style="font-weight:bold"><wbr />型</span><wbr /><span style="font-weight:bold"><wbr />问题</span><wbr /><br><br>C++98/03 有一个有意思的盲点：给定一个像 <span style="font-weight:bold"><wbr />x * y</span><wbr /> 的表达式， <span style="font-weight:bold"><wbr />x</span><wbr /> 和 <span style="font-weight:bold"><wbr />y</span><wbr /> 是任意类型，你却没法知道 <span style="font-weight:bold"><wbr />x * y</span><wbr /> 的类型。假如 <span style="font-weight:bold"><wbr />x</span><wbr /> 是 <span style="font-weight:bold"><wbr />Watts </span><wbr />类型的， <span style="font-weight:bold"><wbr />y</span><wbr /> 是<span style="font-weight:bold"><wbr /> Seconds</span><wbr /> 类型的，那 <span style="font-weight:bold"><wbr />x * y</span><wbr /> 的类型可能会是 Joules 类型的。 给定声明 <span style="font-weight:bold"><wbr />print(const T&amp; t)</span><wbr />，调用 <span style="font-weight:bold"><wbr />print( x * y )</span><wbr /> ，在这里 <span style="font-weight:bold"><wbr />T</span><wbr /> 会被推导为 <span style="font-weight:bold"><wbr />Joules</span><wbr /> 类型。但反过来却不是这样的：当你写个函数 <span style="font-weight:bold"><wbr />multiply(const A&amp; a, const B&amp; b) </span><wbr />，你无法指定它的通用返回类型。即使是实例化成 <span style="font-weight:bold"><wbr />multiply&lt;A, B&gt;()</span><wbr /> ，编译器也晓得 <span style="font-weight:bold"><wbr />x * y</span><wbr /> 的类型，但你就是没办法得到那样的信息（指返回类型）。C++0x 中的关键词 <span style="font-weight:bold"><wbr />decltype </span><wbr />扫除了这个盲点，让你能够说“ <span style="font-weight:bold"><wbr />multiply()</span><wbr /> 返回 <span style="font-weight:bold"><wbr />x * y</span><wbr /> 类型的东西”。（<span style="font-weight:bold"><wbr />decltype </span><wbr />是 &quot;declared type&quot; 的缩写，我把它读作谐音 “speckle type”。）<br><br><span style="font-weight:bold"><wbr />decltype</span><wbr /><span style="font-weight:bold"><wbr />：模式</span><wbr /><br><br>下面是一个完全泛化的封装 +() 操作符的函数因子。这个“加法”因子不是一个模板，但它有一个模板函数，这个模板函数带两个任意类型（当然是不同类型的）参数，并把它们想加，然后返回任意类型（可能跟两个参数的类型完全不同）的结果。C:\Temp&gt;type plus.cpp<br>#include &lt;algorithm&gt;<br>#include &lt;iostream&gt;<br>#include &lt;iterator&gt;<br>#include &lt;ostream&gt;<br>#include &lt;string&gt;<br>#include &lt;utility&gt;<br>#include &lt;vector&gt;<br>using namespace std;<br> <br>struct Plus {<br>    template &lt;typename T, typename U&gt;<br>    auto operator()(T&amp;&amp; t, U&amp;&amp; u) const<br>    -&gt; decltype(forward&lt;T&gt;(t) + forward&lt;U&gt;(u)) {<br>        return forward&lt;T&gt;(t) + forward&lt;U&gt;(u);<br>    }<br>};<br> <br>int main() {<br>    vector&lt;int&gt; i;<br>    i.push_back(1);<br>    i.push_back(2);<br>    i.push_back(3);<br> <br>    vector&lt;int&gt; j;<br>    j.push_back(40);<br>    j.push_back(50);<br>    j.push_back(60);<br><br>    vector&lt;int&gt; k;<br>    vector&lt;string&gt; s;<br>    s.push_back(&quot;cut&quot;);<br>    s.push_back(&quot;flu&quot;);<br>    s.push_back(&quot;kit&quot;);<br> <br>    vector&lt;string&gt; t;<br>    t.push_back(&quot;e&quot;);<br>    t.push_back(&quot;ffy&quot;);<br>    t.push_back(&quot;tens&quot;);<br> <br>    vector&lt;string&gt; u;<br> <br>    transform(i.begin(), i.end(), j.begin(), back_inserter(k), Plus());<br>    transform(s.begin(), s.end(), t.begin(), back_inserter(u), Plus());<br> <br>    for_each(k.begin(), k.end(), [](int n) { cout &lt;&lt; n &lt;&lt; &quot; &quot;; });<br>    cout &lt;&lt; endl;<br> <br>    for_each(u.begin(), u.end(), [](const string&amp; r) { cout &lt;&lt; r &lt;&lt; &quot; &quot;; });<br>    cout &lt;&lt; endl;<br>}<br> <br>C:\Temp&gt;cl /EHsc /nologo /W4 plus.cpp<br>plus.cpp<br> <br>C:\Temp&gt;plus<br>41 52 63<br>cute fluffy kittens<br><br>拿 C++98/03 <span style="font-weight:bold"><wbr />&lt;functional&gt;</span><wbr /> 中的 <span style="font-weight:bold"><wbr />std::plus&lt;T&gt;</span><wbr /> (在 C++0x 没有变动)来作对比，后者是一个类模板，你不得不传递模板参数类型来调用 <span style="font-weight:bold"><wbr />plus&lt;int&gt;()</span><wbr /> 和 <span style="font-weight:bold"><wbr />plus&lt;string&gt;()</span><wbr />，重复声明一次元素类型。并且后者那个形式为 <span style="font-weight:bold"><wbr />T operator()(const T&amp; x, const T&amp; y) </span><wbr />的非模板函数调用操作符，如果不借助于隐式类型转换，就不能将两种不同类型的东西相加，更不用说 3 种不同类型的情况了（译注：两个参数类型 + 一个返回类型）。（你可以传递 <span style="font-weight:bold"><wbr />string</span><wbr /> 和 <span style="font-weight:bold"><wbr />const char *</span><wbr /> 类型的实参来调用 <span style="font-weight:bold"><wbr />const plus&lt;string&gt;()</span><wbr />，那样的话就会在串接操作之前，基于第二个参数(<span style="font-weight:bold"><wbr />const char *</span><wbr />)构建一个临时 <span style="font-weight:bold"><wbr />string</span><wbr />，这样做在性能上不可取）。 再者，因为它的参数是 <span style="font-weight:bold"><wbr />const T&amp;</span><wbr /> 形式的，这就不能使用 C++0x 的 <span style="font-weight:bold"><wbr />move </span><wbr />语意来获得好处。<span style="font-weight:bold"><wbr />Plus</span><wbr /> 避免了上述问题：调用 <span style="font-weight:bold"><wbr />Plus()</span><wbr /> 不需要重复声明元素的类型，它也可以处理 “3 种” 不同类型的情况，并且它用了完美转发，因而能够使用 move 语意。<span style="font-weight:bold"><wbr /><br><br>trailing return type</span><wbr /><br><br>现在让我们再来看看这个模板函数调用操作符：<br><br>template &lt;typename T, typename U&gt;<br><span style="font-weight:bold"><wbr />auto</span><wbr /> operator()(T&amp;&amp; t, U&amp;&amp; u) const<br><span style="font-weight:bold"><wbr />-&gt; decltype(forward&lt;T&gt;(t) + forward&lt;U&gt;(u))</span><wbr /> {<br>    return forward&lt;T&gt;(t) + forward&lt;U&gt;(u);<br>}<br><br>这里的 <span style="font-weight:bold"><wbr />auto</span><wbr /> 与 <span style="font-weight:bold"><wbr />for ( auto i = v.begin(); i != v.end(); ++i)</span><wbr /> 中的含义完全不同, 在 for 中它是指“把用来初始化对象的类型当做对象的类型”，而在这里它是指“这个函数有 <span style="font-weight:bold"><wbr />trailing-return-type</span><wbr />，只有指定实参之后，才能确定它返回什么类型”(C++0x 提案 <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2857.pdf" target="_blank"><span style="color:#000080;line-height:1.8em;">N2857</span><wbr /></a><wbr /> 中把这个称作 “<span style="font-weight:bold"><wbr /><span style="font-style:italic"><wbr />late-specified return type</span><wbr /></span><wbr />”，但它将被重命名为 “<span style="font-weight:bold"><wbr />trailing-retrun-type</span><wbr />”（提案 <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2859.pdf" target="_blank"><span style="color:#000080;line-height:1.8em;">N2859</span><wbr /></a><wbr /> ）)。这里看起来和 lambda 函数是如何指定返回类型的很相似，其实它们就是一样的。<span style="font-weight:bold"><wbr />lambda </span><wbr />函数的返回类型必须出现在 <span style="font-weight:bold"><wbr />lambda </span><wbr />导引符 <span style="font-weight:bold"><wbr />[]</span><wbr /> 之后（右边）。在这里，<span style="font-weight:bold"><wbr />decltype-powered</span><wbr /> 类型也必须出现在函数参数 <span style="font-weight:bold"><wbr />t</span><wbr /> 和 <span style="font-weight:bold"><wbr />u</span><wbr /> 之后（右边）。<span style="font-weight:bold"><wbr />autoT</span><wbr /> 和 <span style="font-weight:bold"><wbr />U</span><wbr /> 对它是可见的，但是函数参数 <span style="font-weight:bold"><wbr />t</span><wbr /> 和 <span style="font-weight:bold"><wbr />u </span><wbr />还不可见，这就是为什么需要 <span style="font-weight:bold"><wbr />decltype </span><wbr />的原因。（从技术上来讲， <span style="font-weight:bold"><wbr />decltype(forward&lt;T&gt;(*static_cast&lt;T *&gt;(0)) + forward&lt;U&gt;(*static_cast&lt;U *&gt;(0))</span><wbr /><span style="font-weight:bold"><wbr />）</span><wbr /> 可以在左边出现，但那看起来会让人不舒服）。<br><br>至于在返回语句中还要使用与传给 <span style="font-weight:bold"><wbr />decltype </span><wbr />的表达式相同的形式，是为了确保在任何情况下都能正确工作。（突击测验：为什么 decltype(t + u) 就不对呢？）。这里的重复是不可避免的，但因为集中-只出现一次且代码位置靠近，所以不会有什么危险。<span style="font-weight:bold"><wbr /><br><br>另一个例子</span><wbr /><br><br>考虑到例子的完整性，下面是一个 “3种” 不同类型的示例：<br><br>C:\Temp&gt;type mult.cpp<br>#include &lt;algorithm&gt;<br>#include &lt;iostream&gt;<br>#include &lt;iterator&gt;<br>#include &lt;ostream&gt;<br>#include &lt;utility&gt;<br>#include &lt;vector&gt;<br>using namespace std;<br> <br>struct Multiplies {<br>    template &lt;typename T, typename U&gt;<br>    auto operator()(T&amp;&amp; t, U&amp;&amp; u) const<br>    -&gt; decltype(forward&lt;T&gt;(t) * forward&lt;U&gt;(u)) {<br>        return forward&lt;T&gt;(t) * forward&lt;U&gt;(u);<br>    }<br>};<br> <br>class <br>public:<br>    explicit <br>    int get() const { return m_n; }<br>private:<br>    int m_n;<br>};<br> <br>class Seconds {<br>public:<br>    explicit Seconds(const int n) : m_n(n) { }<br>    int get() const { return m_n; }<br>private:<br>    int m_n;<br>};<br> <br>class Joules {<br>public:<br>    explicit Joules(const int n) : m_n(n) { }<br>    int get() const { return m_n; }<br>private:<br>    int m_n;<br>};<br> <br>Joules operator*(const &amp; w, const Seconds&amp; s) {<br>    return Joules(w.get() * s.get());<br>}<br> <br>int main() {<br>    vector&lt; <br>    w.push_back( <br>    w.push_back( <br>    w.push_back( <br> <br>    vector&lt;Seconds&gt; s;<br>    s.push_back(Seconds(5));<br>    s.push_back(Seconds(6));<br>    s.push_back(Seconds(7));<br> <br>    vector&lt;Joules&gt; j;<br> <br>    transform(w.begin(), w.end(), s.begin(), back_inserter(j), Multiplies());<br> <br>    for_each(j.begin(), j.end(), [](const Joules&amp; r) { cout &lt;&lt; r.get() &lt;&lt; endl; });<br>}<br> <br>C:\Temp&gt;cl /EHsc /nologo /W4 mult.cpp<br>mult.cpp<br> <br>C:\Temp&gt;mult<br>10<br>18<br>28<br><br>你可能会问“所有的这些处理真的有必要么”，答案是 Yes ，有必要。我已经介绍了完美转发和 decltype 是如何让算术运算函数因子使用起来更容易（不用重复声明元素类型），更灵活（可以混合使用不同的参数和返回类型），更有效率（使用 move 语意）。最重要的是，完美转发和 decltype 让你能够编写更简洁明了的代码，而不灵活和低效的代码不是简洁明了的-这点是我们无法忽视的。<br><br><span style="font-weight:bold"><wbr />高</span><wbr /><span style="font-weight:bold"><wbr />级规则<br><br>decltype </span><wbr />是有一些规则来驱动的。然而，如果你遵照上面的模式就没关系，能正常工作。我很少那样说 C++ ，但是在这里是这样的。<br><br>虽然大多数 <span style="font-weight:bold"><wbr />decltype </span><wbr />应用遵循上面介绍的模式，但 <span style="font-weight:bold"><wbr />decltype </span><wbr />还可以用于其他环境。在那些情况下，你就用到了 <span style="font-weight:bold"><wbr />decltype</span><wbr /> 的高级模式，你应该全面地阅读那些规则，它们在 C++0x 提案 <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2857.pdf" target="_blank"><span style="color:#000080;line-height:1.8em;">N2857</span><wbr /></a><wbr />.2 [dcl.type.simple]/4 中被给出。<span style="font-weight:bold"><wbr /><br><br>等等，</span><wbr /><span style="font-weight:bold"><wbr />还</span><wbr /><span style="font-weight:bold"><wbr />有一些要</span><wbr /><span style="font-weight:bold"><wbr />说</span><wbr /><span style="font-weight:bold"><wbr />的<br><br>decltype </span><wbr />是第五个且是最后一个添加到VC10中的 C++0x 核心语言特性。虽然VC10 CTP中还没有，但 VC10 Bata 1中会有。而且 VC10 Beta 1 中还有很多 C++0x 标准库特性，我会在后续文章中介绍它们。<br><br>Stephan T. Lavavej<br>Visual C++ Libraries Developer<br>Published Wednesday, April 22, 2009 10:06 AM by <a href="http://blogs.msdn.com/user/Profile.aspx?UserID=33825" target="_blank"><span style="color:#000080;line-height:1.8em;">vcblog</span><wbr /></a><wbr /><br>翻译：<a href="http://www.cppblog.com/kesalin/" target="_blank"><span style="color:#000080;line-height:1.8em;">飘飘白云</span><wbr /></a><wbr /><br><span style="color:#000080;line-height:1.8em;"><br></span><wbr /><br>(转载时请注明作者和出处。未经许可，请勿用于商业用途) <!--v:3.2--> ]]></description>
<category><![CDATA[技术知识]]></category>
<author><![CDATA[843858859@qq.com(Tomsdinary)]]></author>
<comments>http://843858859.qzone.qq.com/blog/1258766708#comment</comments>
<qz:effect>142606848</qz:effect>
<pubDate>Sat, 21 Nov 2009 01:25:08 GMT</pubDate>
<guid>http://843858859.qzone.qq.com/blog/1258766708</guid>
</item>

<item>
<title><![CDATA[VC10中的C++0x特性 part 2（3）:右值引用]]></title>
<link>http://843858859.qzone.qq.com/blog/1258719029</link>
<description><![CDATA[<span style="font-weight:bold"><wbr />move </span><wbr /><span style="font-weight:bold"><wbr />语意：可移动成员（</span><wbr /><span style="font-weight:bold"><wbr />movable member)</span><wbr /><br><br>C++0x 的标准类型（像 vector, string, regex） 都有 move 构造函数和 move 赋值函数。而且我们也已经看到了如何在我们自己的类中通过手动管理资源来实现 move 语意（像前面的 remote_integer 类）。如果类中包含可移动数据成员（像 vector, string, regex, remote_integer ）时该怎么办呢？编译器不会自动帮我们自动产生 move 构造函数和 move 赋值函数，所以我们必须手动编写它们。很幸运，有了 std::move() 编写它们是很容易的。<br> <br>C:\Temp&gt;type point.cpp<br>#include &lt;stddef.h&gt;<br>#include &lt;iostream&gt;<br>#include &lt;ostream&gt;<br>using namespace std;<br> <br>template &lt;typename T&gt; struct RemoveReference {<br>     typedef T type;<br>};<br> <br>template &lt;typename T&gt; struct RemoveReference&lt;T&amp;&gt; {<br>     typedef T type;<br>};<br> <br>template &lt;typename T&gt; struct RemoveReference&lt;T&amp;&amp;&gt; {<br>     typedef T type;<br>};<br> <br>template &lt;typename T&gt; typename RemoveReference&lt;T&gt;::type&amp;&amp; Move(T&amp;&amp; t) {<br>    return t;<br>}<br> <br>class remote_integer {<br>public:<br>    remote_integer() {<br>        cout &lt;&lt; &quot;Default constructor.&quot; &lt;&lt; endl;<br> <br>        m_p = NULL;<br>    }<br> <br>    explicit remote_integer(const int n) {<br>        cout &lt;&lt; &quot;Unary constructor.&quot; &lt;&lt; endl;<br> <br>        m_p = new int(n);<br>    }<br> <br>    remote_integer(const remote_integer&amp; other) {<br>        cout &lt;&lt; &quot;Copy constructor.&quot; &lt;&lt; endl;<br> <br>        if (other.m_p) {<br>            m_p = new int(*other.m_p);<br>        } else {<br>            m_p = NULL;<br>        }<br>    }<br> <br>    remote_integer(remote_integer&amp;&amp; other) {<br>        cout &lt;&lt; &quot;MOVE CONSTRUCTOR.&quot; &lt;&lt; endl;<br> <br>        m_p = other.m_p;<br>        other.m_p = NULL;<br>    }<br> <br>    remote_integer&amp; operator=(const remote_integer&amp; other) {<br>        cout &lt;&lt; &quot;Copy assignment operator.&quot; &lt;&lt; endl;<br> <br>        if (this != &amp;other) {<br>            delete m_p;<br> <br>            if (other.m_p) {<br>                m_p = new int(*other.m_p);<br>            } else {<br>                m_p = NULL;<br>            }<br>        }<br> <br>        return *this;<br>    }<br> <br>    remote_integer&amp; operator=(remote_integer&amp;&amp; other) {<br>        cout &lt;&lt; &quot;MOVE ASSIGNMENT OPERATOR.&quot; &lt;&lt; endl;<br> <br>        if (this != &amp;other) {<br>            delete m_p;<br> <br>            m_p = other.m_p;<br>            other.m_p = NULL;<br>        }<br> <br>        return *this;<br>    }<br> <br>    ~remote_integer() {<br>        cout &lt;&lt; &quot;Destructor.&quot; &lt;&lt; endl;<br> <br>        delete m_p;<br>    }<br> <br>    int get() const {<br>        return m_p ? *m_p : 0;<br>    }<br> <br>private:<br>    int * m_p;<br>};<br> <br>class remote_point {<br>public:<br>    remote_point(const int x_arg, const int y_arg)<br>        : m_x(x_arg), m_y(y_arg) { }<br> <br>    remote_point(remote_point&amp;&amp; other)<br>        : m_x(Move(other.m_x)),<br>          m_y(Move(other.m_y)) { }<br> <br>    remote_point&amp; operator=(remote_point&amp;&amp; other) {<br>        m_x = Move(other.m_x);<br>        m_y = Move(other.m_y);<br>        return *this;<br>    }<br> <br>    int x() const { return m_x.get(); }<br>    int y() const { return m_y.get(); }<br> <br>private:<br>    remote_integer m_x;<br>    remote_integer m_y;<br>};<br> <br>remote_point five_by_five() {<br>    return remote_point(5, 5);<br>}<br> <br>remote_point taxicab(const int n) {<br>    if (n == 0) {<br>        return remote_point(1, 1728);<br>    }<br> <br>    remote_point ret(729, 1000);<br> <br>    return ret;<br>}<br> <br>int main() {<br>    remote_point p = taxicab(43112609);<br> <br>    cout &lt;&lt; &quot;(&quot; &lt;&lt; p.x() &lt;&lt; &quot;, &quot; &lt;&lt; p.y() &lt;&lt; &quot;)&quot; &lt;&lt; endl;<br> <br>    p = five_by_five();<br> <br>    cout &lt;&lt; &quot;(&quot; &lt;&lt; p.x() &lt;&lt; &quot;, &quot; &lt;&lt; p.y() &lt;&lt; &quot;)&quot; &lt;&lt; endl;<br>}<br> <br>C:\Temp&gt;cl /EHsc /nologo /W4 /O2 point.cpp<br>point.cpp<br> <br>C:\Temp&gt;point<br>Unary constructor.<br>Unary constructor.<br>MOVE CONSTRUCTOR.<br>MOVE CONSTRUCTOR.<br>Destructor.<br>Destructor.<br>(729, 1000)<br>Unary constructor.<br>Unary constructor.<br>MOVE ASSIGNMENT OPERATOR.<br>MOVE ASSIGNMENT OPERATOR.<br>Destructor.<br>Destructor.<br>(5, 5)<br>Destructor.<br>Destructor.<br> <br>现在你看到啦，按成员移动（memberwise move）是很容易做到的。注意， remote_point 的 move 赋值函数没有进行自我赋值检查，是因为 remote_integer 已经检查过了。也要注意到 remote_point 隐式声明的拷贝构造函数，拷贝赋值函数和析构函数都正常运作。<br> <br>到现在，你应该对 move 语意已经非常熟悉了。（希望不是抓狂啊！）为了测试你新获得的这个不可思议的技能，请为前面的例子写一个 +() 操作符函数当作练习吧。<br> <br>最后的提醒：只要你的类支持 move 语意，你就应该实现 move 构造函数和 move 赋值函数。因为不仅仅是你平常使用这些类时可从 move 语意中获利， STL 容器和算法也能从中获利，通过廉价的 move 省下昂贵的拷贝开销。<br><br><div style="text-align:center;">(转载请注明出处，作者与译者信息，请勿用于商业用途)</div> <!--v:3.2--> ]]></description>
<category><![CDATA[技术知识]]></category>
<author><![CDATA[843858859@qq.com(Tomsdinary)]]></author>
<comments>http://843858859.qzone.qq.com/blog/1258719029#comment</comments>
<qz:effect>142606848</qz:effect>
<pubDate>Fri, 20 Nov 2009 12:10:29 GMT</pubDate>
<guid>http://843858859.qzone.qq.com/blog/1258719029</guid>
</item>

</channel>
</rss>

