??xml version="1.0" encoding="utf-8" standalone="yes"?>精品无码久久久久久久久久,99国产精品久久,狠狠色丁香久久婷婷综合_中 http://www.shnenglu.com/jacky2019/q个kisser不太?/description>zh-cnWed, 07 May 2025 03:16:10 GMTWed, 07 May 2025 03:16:10 GMT60dxtrans.h missing in Microsoft DirectX SDK (November 2007)http://www.shnenglu.com/jacky2019/archive/2010/04/08/111974.htmlkkkkThu, 08 Apr 2010 08:31:00 GMThttp://www.shnenglu.com/jacky2019/archive/2010/04/08/111974.htmlhttp://www.shnenglu.com/jacky2019/comments/111974.htmlhttp://www.shnenglu.com/jacky2019/archive/2010/04/08/111974.html#Feedback0http://www.shnenglu.com/jacky2019/comments/commentRss/111974.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/111974.html解决办法Q来?http://social.msdn.microsoft.com/forums/en-US/windowssdk/thread/ed097d2c-3d68-4f48-8448-277eaaf68252/Q?br>
1.使用 August 2007 DirectX SDK.

2. U除所有和dxtrans.h有关?br>
Remove anything to do with "dxtrans.h" and "IDXEffect" .

Say, for file "qedit.h"

//#include "dxtrans.h" -- Line 498 

// IDxtCompositor //: public IDXEffect -- Line 837
// IDxtAlphaSetter //: public IDXEffect -- Line 1151
// IDxtJpeg //: public IDXEffect -- Line 1345
// IDxtKey //: public IDXEffect -- Line 1735






kk 2010-04-08 16:31 发表评论
]]>
c++ volatile关键?/title><link>http://www.shnenglu.com/jacky2019/archive/2010/04/01/111249.html</link><dc:creator>kk</dc:creator><author>kk</author><pubDate>Thu, 01 Apr 2010 02:54:00 GMT</pubDate><guid>http://www.shnenglu.com/jacky2019/archive/2010/04/01/111249.html</guid><wfw:comment>http://www.shnenglu.com/jacky2019/comments/111249.html</wfw:comment><comments>http://www.shnenglu.com/jacky2019/archive/2010/04/01/111249.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.shnenglu.com/jacky2019/comments/commentRss/111249.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/jacky2019/services/trackbacks/111249.html</trackback:ping><description><![CDATA[<span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: rgb(0,0,0); WORD-SPACING: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class=Apple-style-span>c++中的volatile关键字一直没有用过。最q用了一下。该关键字的意思就是告诉编译器不要对该变量q行优化Q用地址对该变量q行取D不要直接用该变量已经存在cach/寄存器中的倹{?br><br>试代码如下Q?br> <div style="BORDER-BOTTOM: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; PADDING-BOTTOM: 4px; BACKGROUND-COLOR: #eeeeee; PADDING-LEFT: 4px; WIDTH: 98%; PADDING-RIGHT: 5px; FONT-SIZE: 13px; WORD-BREAK: break-all; BORDER-TOP: #cccccc 1px solid; BORDER-RIGHT: #cccccc 1px solid; PADDING-TOP: 4px"><span style="COLOR: #008080"> 1</span><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif"><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> volatile.cpp : Defines the entry point for the console application.<br></span><span style="COLOR: #008080"> 2</span><span style="COLOR: #008000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//<br></span><span style="COLOR: #008080"> 3</span><span style="COLOR: #008000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080"> 4</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif">#include </span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">stdafx.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080"> 5</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif"><br></span><span style="COLOR: #008080"> 6</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif"><br></span><span style="COLOR: #008080"> 7</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> _tmain(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> argc, _TCHAR</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> argv[])<br></span><span style="COLOR: #008080"> 8</span><span style="COLOR: #000000"><img id=Codehighlighter1_134_292_Open_Image onclick="this.style.display='none'; Codehighlighter1_134_292_Open_Text.style.display='none'; Codehighlighter1_134_292_Closed_Image.style.display='inline'; Codehighlighter1_134_292_Closed_Text.style.display='inline';" align=top src="http://www.shnenglu.com/Images/OutliningIndicators/ExpandedBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_134_292_Closed_Image onclick="this.style.display='none'; Codehighlighter1_134_292_Closed_Text.style.display='none'; Codehighlighter1_134_292_Open_Image.style.display='inline'; Codehighlighter1_134_292_Open_Text.style.display='inline';" align=top src="http://www.shnenglu.com/Images/OutliningIndicators/ContractedBlock.gif"></span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_134_292_Closed_Text><img src="http://www.shnenglu.com/Images/dot.gif"></span><span id=Codehighlighter1_134_292_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080"> 9</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif">    </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">volatile int a = 1;</span><span style="COLOR: #008000"><br></span><span style="COLOR: #008080">10</span><span style="COLOR: #008000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif"></span><span style="COLOR: #000000">    </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> a </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">11</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif">    printf (</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">a = %d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, a);<br></span><span style="COLOR: #008080">12</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif"><br></span><span style="COLOR: #008080">13</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif">    __asm<br></span><span style="COLOR: #008080">14</span><span style="COLOR: #000000"><img id=Codehighlighter1_206_238_Open_Image onclick="this.style.display='none'; Codehighlighter1_206_238_Open_Text.style.display='none'; Codehighlighter1_206_238_Closed_Image.style.display='inline'; Codehighlighter1_206_238_Closed_Text.style.display='inline';" align=top src="http://www.shnenglu.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="DISPLAY: none" id=Codehighlighter1_206_238_Closed_Image onclick="this.style.display='none'; Codehighlighter1_206_238_Closed_Text.style.display='none'; Codehighlighter1_206_238_Open_Image.style.display='inline'; Codehighlighter1_206_238_Open_Text.style.display='inline';" align=top src="http://www.shnenglu.com/Images/OutliningIndicators/ContractedSubBlock.gif">    </span><span style="BORDER-BOTTOM: #808080 1px solid; BORDER-LEFT: #808080 1px solid; BACKGROUND-COLOR: #ffffff; DISPLAY: none; BORDER-TOP: #808080 1px solid; BORDER-RIGHT: #808080 1px solid" id=Codehighlighter1_206_238_Closed_Text><img src="http://www.shnenglu.com/Images/dot.gif"></span><span id=Codehighlighter1_206_238_Open_Text><span style="COLOR: #000000">{<br></span><span style="COLOR: #008080">15</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif">        mov DWORD ptr [ebp</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">], 10h // 修改a的gؓ0x10<br></span><span style="COLOR: #008080">16</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif">    }</span></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">17</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif"><br></span><span style="COLOR: #008080">18</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif">    printf (</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">a = %d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, a);<br></span><span style="COLOR: #008080">19</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif"><br></span><span style="COLOR: #008080">20</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif">    getchar();<br></span><span style="COLOR: #008080">21</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif"><br></span><span style="COLOR: #008080">22</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif">    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br></span><span style="COLOR: #008080">23</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/ExpandedBlockEnd.gif">}</span></span><span style="COLOR: #000000"><br></span><span style="COLOR: #008080">24</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif"><br></span><span style="COLOR: #008080">25</span><span style="COLOR: #000000"><img align=top src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif"></span></div> </span><br>如果~译器没有优化的话,打印出来的值应该是1?6。反之,如果没有使用volatileQ优化之后应该打印出来的??<br><br>我在vc6和vc2008下测试了一下:<br>-----------------------------------------------------------------------------------------<br><br>vc2008<br>-----------------------------------------------------------------------------------------<br>没有关键字volatile<br>debug下打印的?1 ?1 ---Z么会被优化了呢?我的优化~译选项是disabled?br>release下打印的?1 ?1<br>有关键字volatile<br><font face=宋体>debug下打印的?1 ?1 --- 很奇怪!<br>release下打印的?1 ?16<br><br>我想可能是编译器对debug下作了特D处理。而且该程序非常简?/font><br><br>vc6.0<br><font face=宋体>-----------------------------------------------------------------------------------------<br>没有关键字volatile<br><font face=宋体>debug下打印的?1 ?16<br>release下打印的?1 ?1</font><br>有关键字volatile<br><font face=宋体>debug下打印的?1 ?16<br>release下打印的?1 ?1 --- 很奇怪!<br><br><br>结Q?br>在多U程多核的情况下Q要防止被编译器优化Q?/font></font> <img src ="http://www.shnenglu.com/jacky2019/aggbug/111249.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/jacky2019/" target="_blank">kk</a> 2010-04-01 10:54 <a href="http://www.shnenglu.com/jacky2019/archive/2010/04/01/111249.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>环Ş~冲http://www.shnenglu.com/jacky2019/archive/2010/04/01/111243.htmlkkkkThu, 01 Apr 2010 01:17:00 GMThttp://www.shnenglu.com/jacky2019/archive/2010/04/01/111243.htmlhttp://www.shnenglu.com/jacky2019/comments/111243.htmlhttp://www.shnenglu.com/jacky2019/archive/2010/04/01/111243.html#Feedback0http://www.shnenglu.com/jacky2019/comments/commentRss/111243.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/111243.html环Ş~冲是可以不用加锁的。下面是一个实现的环Ş~冲。用c实现Q可能会出现write满情况,q种情况D的结果就是write不成功,数据没写q去?/pre>
我这里只是简单的丢了?/pre>
  1 //
  2 
  3 #include "stdafx.h"
  4 #include <windows.h>
  5 #include <time.h>
  6 #include <stdlib.h>
  7 
  8 #define MAX_BUF_LEN 20        // buf len // 必须要大?
  9 int nRead = 0;                // read pos
 10 int nWrite = 0;                // write pos
 11 int buf[MAX_BUF_LEN] = {0}; // loop buf
 12 
 13 #define NN 20000
 14 __int64 sum = 0;
 15 __int64 lose = 0;
 16 __int64 total = (__int64)(1+NN)*(__int64)NN/2;
 17 bool bWriteFinished = false;
 18 
 19 void WriteBuf(int n)
 20 {
 21     int rpos = nRead;
 22     int wpos = nWrite;
 23     wpos++;
 24     // buf满(即write又追上了readQ? 注ؓ了避免与初始状态重复判?br> 25     // 所以这里最后一个buf没有写就认ؓ已经满了。所以MAX_BUF_LEN不能?
 26     // q里Q直接丢弃该buf
 27     if (wpos % MAX_BUF_LEN == rpos % MAX_BUF_LEN)
 28     {
 29         lose += n;
 30         return;
 31     }
 32 
 33     buf[nWrite] = n;
 34     nWrite++;
 35     if (nWrite == MAX_BUF_LEN)
 36         nWrite = 0;
 37 }
 38 
 39 int ReadBuf()
 40 {
 41     if (nWrite == nRead)
 42         return -1;
 43 
 44     int n = buf[nRead];
 45     nRead++;
 46     if (nRead == MAX_BUF_LEN)
 47         nRead = 0;
 48     return n;
 49 }
 50 
 51 DWORD WINAPI ReadThread(LPVOID lpParameter)
 52 {
 53     int tmp = 0;
 54     int count = 0;
 55     while (true)
 56     {
 57         //printf("ReadThread = %d\n", ReadBuf());
 58         tmp = ReadBuf();
 59         if (-1 != tmp)
 60         {
 61             count++;
 62             sum += tmp;
 63             if (count == NN)
 64             {
 65                 printf ("ReadThread finished!\n");
 66                 break;
 67             }
 68         }
 69         else if (bWriteFinished)
 70         {
 71             printf ("ReadThread finished222!\n");
 72             break;
 73         }
 74 
 75         Sleep(rand() % 10);
 76     }
 77     return 0;
 78 }
 79 
 80 DWORD WINAPI WriteThread(LPVOID lpParameter)
 81 {
 82     int n = 0;
 83     while (true)
 84     {
 85         n++;
 86         WriteBuf(n);
 87         if (n == NN)
 88         {
 89             printf ("WriteThread finished!\n");
 90             bWriteFinished = true;
 91             break;
 92         }
 93 
 94         Sleep(rand() % 10);
 95     }
 96     return 0;
 97 }
 98 
 99 int main(int argc, char* argv[])
100 {
101     srand(time(NULL));
102 //     for (int i = 0; i < 10; i++)
103 //     {
104 //         printf ("rand = %d\n", rand() % 10);
105 //     }
106 
107     DWORD threadid[2= {0};
108     HANDLE hThread[2= {0};
109     int param = 0;
110     hThread[0= CreateThread(NULL, 0, ReadThread, &param, CREATE_SUSPENDED, &threadid[0]);
111     ResumeThread(hThread[0]);
112     hThread[1= CreateThread(NULL, 0, WriteThread, &param, CREATE_SUSPENDED, &threadid[1]);
113     ResumeThread(hThread[1]);
114 
115     getchar();
116 
117     printf ("total = %lld\n", total);
118     printf ("lose = %lld\n", lose);
119     printf ("sum = %lld\n", sum);
120 
121     if (total == lose + sum)
122     {
123         printf ("loop buf works well!\n");
124     }
125     else
126     {
127         printf ("loop buf works wrong!\n");
128     }
129 
130     return 0;
131 }
132 
上面是加了测试代码的Q我试了一下似乎没问题?/pre>
注意Q这里只允许一个线E读Q一个线E写。如果是多个U程d的话Q需要锁Q?/pre>
另外Q很多细节都没考虑q去


kk 2010-04-01 09:17 发表评论
]]>人生最高境?/title><link>http://www.shnenglu.com/jacky2019/archive/2008/12/19/69790.html</link><dc:creator>kk</dc:creator><author>kk</author><pubDate>Fri, 19 Dec 2008 00:07:00 GMT</pubDate><guid>http://www.shnenglu.com/jacky2019/archive/2008/12/19/69790.html</guid><wfw:comment>http://www.shnenglu.com/jacky2019/comments/69790.html</wfw:comment><comments>http://www.shnenglu.com/jacky2019/archive/2008/12/19/69790.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/jacky2019/comments/commentRss/69790.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/jacky2019/services/trackbacks/69790.html</trackback:ping><description><![CDATA[人生最高境界:<br>    拿沙特工资,住英国房子,用瑞典手机,戴瑞士手表,娉国女人,包日本二Ӟ做泰国按摩,开德国轿RQ坐国飞机Q喝法国U酒Q吃x鲜Q抽古巴雪茄Q穿意大利皮鞋,玩西班牙女郎Q看奥地利歌剧,C|斯别墅Q雇菲律宑֥佣,配以色列保镖Q洗土耛_桑拿Q当中国q部.<br> <img src ="http://www.shnenglu.com/jacky2019/aggbug/69790.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/jacky2019/" target="_blank">kk</a> 2008-12-19 08:07 <a href="http://www.shnenglu.com/jacky2019/archive/2008/12/19/69790.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>存储q程 stored procedurehttp://www.shnenglu.com/jacky2019/archive/2007/11/06/35937.htmlkkkkTue, 06 Nov 2007 02:37:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/11/06/35937.htmlhttp://www.shnenglu.com/jacky2019/comments/35937.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/11/06/35937.html#Feedback0http://www.shnenglu.com/jacky2019/comments/commentRss/35937.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/35937.html 

定义Q?br>        常用的或很复杂的工作,预先用SQL语句写好q用一个指定的名称存储h,   那么以后要叫数据?/font>提供与已定义好的存储q程的功能相同的服务?只需调用execute,卛_自动完成命o?br>        讲到q里,可能有h要问Q这么说存储q程是一堆SQL语句而已啊?
        Microsoft公司Z么还要添加这个技术呢?
        那么存储q程与一般的SQL语句有什么区别呢?

        存储q程的优点:
          1.存储q程只在创造时q行~译Q以后每ơ执行存储过E都不需再重新编译,而一般SQL语句每执行一ơ就~译一?所以用存储过E可提高数据库执行速度?br>          2.当对数据库进行复杂操作时(如对多个表进行Update,Insert,Query,DeleteӞQ可此复杂操作用存储过E封装v来与数据库提供的事务处理l合一起用?br>          3.存储q程可以重复使用,可减数据库开发h员的工作?br>          4.安全性高,可设定只有某此用hhҎ定存储过E的使用?br>        存储q程的种c:
          1.pȝ存储q程Q以sp_开?用来q行pȝ的各设?取得信息.相关理工作,
          ?nbsp;  sp_help是取得指定对象的相关信?br>          2.扩展存储q程   以XP_开?用来调用操作pȝ提供的功?br>          exec   master..xp_cmdshell   'ping   10.8.16.1'
          3.用户自定义的存储q程,q是我们所指的存储q程
          常用格式
          Create   procedure   procedue_name
          [@parameter   data_type][output]
          [with]{recompile|encryption}
          as
          sql_statement
        解释:  
        outputQ表C此参数是可传回?br>        with   {recompile|encryption}
        recompile:表示每次执行此存储过E时都重新编译一?br>        encryption:所创徏的存储过E的内容会被加密
        ?
          表book的内容如?br>          ~号   书名   h
          001   C语言入门   $30
          002   PowerBuilder报表开?nbsp;  $52
          实例1:查询表Book的内容的存储q程
          create   proc   query_book
          as  
          select   *   from   book
          go
          exec   query_book
          实例2:加入一W记录到表book,q查询此表中所有书c的总金?br>          Create   proc   insert_book
          @param1   char(10),@param2   varchar(20),@param3   money,@param4   money   output
          with   encryption   ---------加密
          as
          insert   book(~号,书名Qh|   Values(@param1,@param2,@param3)
          select   @param4=sum(h)   from   book
          go
          执行例子:  
          declare   @total_price   money  
          exec   insert_book   '003','Delphi   控g开发指?,$100,@total_price
          print   '总金额ؓ'+convert(varchar,@total_price)
          go
       
存储q程?U传回?
          1.以Return传回整数
          2.以output格式传回参数
          3.Recordset
        传回值的区别:
          output和return都可在批ơ程式中用变量接?而recordset则传回到执行Ҏ的客L?nbsp; 
        实例3Q设有两个表为Product,Order,其表内容如下Q?br>          Product
          产品~号   产品名称   客户订数  
          001   钢笔   30  
          002   毛笔   50  
          003   铅笔   100  
          Order  
          产品~号   客户?nbsp;  客户订金
          001   南山?nbsp;  $30
          002   |湖?nbsp;  $50
          003   宝安?nbsp;  $4
        请实现按~号接条?两个表q接成一个时表,该表只含~号.产品?客户?订金.总金?
        总金?订金*订数,临时表放在存储过E中
        代码如下:
          Create   proc   temp_sale
          as
          select   a.产品~号,a.产品名称,b.客户?b.客户订金,a.客户订数*   b.客户订金   as总金?br>          into   #temptable   from   Product   a   inner   join   Order   b   on   a.产品~号=b.产品~号
          if   @@error=0  
          print   'Good'
          else
          print   'Fail'
          go

--------------------------------------------------------------------------------------------------------------------

存储q程介绍  

一、先介绍一下什么是存储q程  
存储q程是利用SQL   Server所提供的Tranact-SQL语言所~写的程序。Tranact-SQL语言是SQL   Server提供专ؓ设计数据库应用程序的语言Q它是应用程序和SQL   Server数据库间的主要程序式设计界面。它好比Oracle数据库系l中的Pro-SQL和Informix的数据库pȝ能够中的Informix-4GL语言一栗这c语a主要提供以下功能Q让用户可以设计出符合引用需求的E序Q?nbsp; 
1)、变量说?nbsp; 
2)、ANSI兼容的SQL命o(如Select,Update….)  
3)、一般流E控制命?if…else…、while….)  
4)、内部函?nbsp; 

二、存储过E的书写格式  

CREATE   PROCEDURE   [拥有?]存储q程名[;E序~号]  
[(参数#1,…参数#1024)]  
[WITH  
{RECOMPILE   |   ENCRYPTION   |   RECOMPILE,   ENCRYPTION}  
]  
[FOR   REPLICATION]  
AS   E序?nbsp; 

其中存储q程名不能超q?28个字。每个存储过E中最多设?024个参?nbsp; 
(SQL   Server   7.0以上版本),参数的用方法如?  

@参数?nbsp;  数据cd   [VARYING]   [=内定值]   [OUTPUT]  

每个参数名前要有一?#8220;@”W号,每一个存储过E的参数仅ؓ该程序内部?参数的类型除了IMAGE外,其他SQL   Server所支持的数据类型都可用?nbsp; 
[=内定值]相当于我们在建立数据库时讑֮一个字D늚默认|q里是ؓq个参数讑֮默认倹{[OUTPUT]是用来指定该参数是既有输入又有输出值的Q也是在调用了q个存储q程Ӟ如果所指定的参数值是我们需要输入的参数Q同时也需要在l果中输出的Q则该项必须为OUTPUTQ而如果只是做输出参数用,可以用CURSORQ同时在使用该参数时Q必L定VARYING和OUTPUTq两个语句?nbsp; 

例子:  
CREATE   PROCEDURE   order_tot_amt   @o_id   int,@p_tot   int   output   AS  
SELECT   @p_tot   =   sum(Unitprice*Quantity)  
FROM   orderdetails  
WHERE   ōrdered=@o_id  

例子说明:  
该例子是建立一个简单的存储q程order_tot_amt,q个存储q程Ҏ用户输入的定单IDL(@o_id),由定单明l表(orderdetails)中计该定单销售总额[单h(Unitprice)*数量(Quantity)],q一金额通过@p_totq一参数输出l调用这一存储q程的程?nbsp; 

三、在SQL   Server中执行存储过E?/strong>  

在SQL   Server的查询分析器中,输入以下代码:  
declare   @tot_amt   int  
execute   order_tot_amt   1,@tot_amt   output  
select   @tot_amt  

以上代码是执行order_tot_amtq一存储q程Q以计算出定单编号ؓ1的定单销售金额,我们定义@tot_amt出参敎ͼ用来承接我们所要的l果



kk 2007-11-06 10:37 发表评论
]]>
汉字~码问题http://www.shnenglu.com/jacky2019/archive/2007/11/01/35693.htmlkkkkThu, 01 Nov 2007 06:53:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/11/01/35693.htmlhttp://www.shnenglu.com/jacky2019/comments/35693.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/11/01/35693.html#Feedback0http://www.shnenglu.com/jacky2019/comments/commentRss/35693.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/35693.htmlhttp://www.css8.cn/css8_document/gb2312.htm

׃常常要和汉字处理打交道,因此Q我常常受到汉字~码问题的困扰。在不断的打M坚持中,也积累了一Ҏ字编码方面的l验Q想和大家一起分享?/font>

一、汉字编码的U类

    汉字~码中现在主要用到的有三c,包括GBKQ?span lang=EN-US>GB2312?span lang=EN-US>Big5?/span>

    1?span lang=EN-US>GB2312又称国标码,由国家标准d发布Q?/span>1981q?/span>5?/span>1日实施,通行于大陆。新加坡{地也用此~码。它是一个简化字的编码规范,当然也包括其他的W号、字母、日文假名等Q共7445个图形字W,其中汉字?/span>6763个。我们^时说6768个汉字,实际上里Ҏ5个编码ؓI白Q所以d?/span>6763个汉字?/span>

      GB2312规定“对Q意一个图形字W都采用两个字节表示Q每个字节均采用七位~码表示”Q习惯上U第一个字节ؓ“高字?#8221;Q第二个字节?#8220;低字?#8221;?/span>GB2312中汉字的~码范围为,W一字节0xB0-0xF7(对应十进制ؓ176-247)Q第二个字节0xA0-0xFEQ对应十q制?span lang=EN-US>160-254Q?/span>

    GB2312代码表分ؓ94个区Q对应第一字节Q?/span>0xa1-0xfeQ;每个?/span>94个位Q?/span>0xa1-0xfeQ,对应W二字节Q两个字节的值分别ؓ区号值和位号值加32Q?/span>2OHQ,因此也称为区位码?/span>01-09ZؓW号、数字区Q?/span>16-87Zؓ汉字区(0xb0-0xf7Q,10-15区?/span>88-94区是有待q一步标准化的空白区?/span>

 

       2?/span>Big5又称大五码,主要为香港与台湾使用Q即是一个繁体字~码?/span>每个汉字׃个字节构成,W一个字节的范围?/span>0X81Q?/span>0XFEQ即129-255Q,?/span>126U。第二个字节的范围不q箋Q分别ؓ0X40Q?/span>0X7EQ即64-126Q,0XA1Q?/span>0XFEQ即161-254Q,?/span>157U?/span>

 

    3?span lang=EN-US>GBK?span lang=EN-US>GB2312的扩展,是向上兼容的Q因?span lang=EN-US>GB2312中的汉字的编码与GBK中汉字的相同。另外,GBK中还包含J体字的~码Q它?span lang=EN-US>Big5~码之间的关pLq没有弄明白Q好像是不一致的?span lang=EN-US>GBK中每个汉字仍然包含两个字节,W一个字节的范围?span lang=EN-US>0x81-0xFEQ即129-254Q,W二个字节的范围?span lang=EN-US>0x40-0xFEQ即64-254Q?span lang=EN-US>GBK中有码位23940个,包含汉字21003个?/span>

                                    

                                   ?span lang=EN-US>1 汉字~码范围

名称

W一字节

W二字节

GB2312

0xB0-0xF7(176-247)

0xA0-0xFEQ?/span>160-254Q?/span>

GBK

0x81-0xFEQ?/span>129-254Q?/span>

0x40-0xFEQ?/span>64-254Q?/span>

Big5

0x81-0xFEQ?/span>129-255Q?/span>

0x40-0x7EQ?/span>64-126Q?/span>

0xA1Q?/span>0xFEQ?/span>161-254Q?/span>

 

 

二、对汉字q行hash

    Z处理汉字的方便,在查找汉字的时候,我们通常会用?span lang=EN-US>hash的方法,那怎么来确定一个汉字位|呢Q这和每种~码的排列有关了Q这里主要给ZU?span lang=EN-US>hash函数的策略?/span>

    对于GB2312~码Q设输入的汉字ؓGBwordQ我们可以采用公?span lang=EN-US>(C1-176)*94 + (C2-161)GBindex。其中,C1表示W一字节Q?span lang=EN-US>C2表示W二字节。具体如下:

    GBindex = ((unsigned char)GBword.at(0)-176)*94 + (unsigned char)GBword.at(1) - 161;

    之所以用unsigned charcdQ是因ؓchar是一个字节,如果?span lang=EN-US>unsigend intQ因?span lang=EN-US>int?span lang=EN-US>4个字节的Q所以会造成扩展Q导致错误?/span>

       对于GBK~码Q设输入的汉字ؓGBKwordQ则可以采用公式   index=(ch1-0x81)*190+(ch2-0x40)-(ch2/128)Q其?span lang=EN-US>ch1是第一字节Q?span lang=EN-US>ch2是第二字节?/span>

    具体的,

    GBKindex = ((unsigned char)GBKword[0]-129)*190 +

               ((unsigned char)GBKword[1]-64) - (unsigned char)GBKword[1]/128;

 

三、怎样判断一个汉字的是什么编?/span>

直接Ҏ汉字的编码范围判断,对于GB2312?span lang=EN-US>GBK可用下面两个E序实现?/span>

1、判断是否是GB2312

bool isGBCode(const string& strIn)

{

    unsigned char ch1;

    unsigned char ch2;

   

    if (strIn.size() >= 2)

    {

        ch1 = (unsigned char)strIn.at(0);

        ch2 = (unsigned char)strIn.at(1);

        if (ch1>=176 && ch1<=247 && ch2>=160 && ch2<=254)

            return true;

        else return false;

    }

    else return false;

}

2、判断是否是GBK~码

bool isGBKCode(const string& strIn)

{

    unsigned char ch1;

    unsigned char ch2;

   

    if (strIn.size() >= 2)

    {

        ch1 = (unsigned char)strIn.at(0);

        ch2 = (unsigned char)strIn.at(1);

        if (ch1>=129 && ch1<=254 && ch2>=64 && ch2<=254)

            return true;

        else return false;

    }

    else return false;

}

 

3、对?span lang=EN-US>Big5

    它的范围为:高字节从0xA0?span lang=EN-US>0xFEQ低字节?span lang=EN-US>0x40?span lang=EN-US>0x7EQ和0xA1?span lang=EN-US>0xFE两部分。判断一个汉字是否是BIG5~码Q可以如上对字符的编码范围判断即可。如何定位呢Q那么也惌所有编码排列ؓ一个二l坐标,U坐标是高字节,横坐标是低字节。这样一行上的汉字个敎ͼ(0x7E-0x40+1)+(0xFE-0xA1+1)Q?span lang=EN-US>157。那么定位算法分两块Qؓ:  

    if 0x40<=ch2<=0x7E: #is big5 char

    index=((ch1-0xA1)*157+(ch2-0x40))*2

    elif 0xA1<=ch2<=0xFE: #is big5 char

    index=((ch1-0xA1)*157+(ch2-0xA1+63))*2

 

对于W二块,计算偏移量时因ؓ有两块数|所以在计算后面一D值时Q不要忘了前面还有一D倹{?span lang=EN-US>0x7E-0x40+1=63?/span>

 

四、如果判断一个字W是西文字符q是中文字符

    大家知道西文字符主要是指ASCII码,它用一个字节表C。且q个字符转换成数字之后,该数字是大于0的,而汉字是两个字节的,W一个字节的转化为数字之后应该是于0的,因此可以Ҏ每个字节转化为数字之后是否小?span lang=EN-US>0Q判断它是否是汉字?/span>

    例如Q设输入字ؓstrinQ则Q?/span>

     If (strin.at(0) < 0)

       cout << ”是汉?span lang=EN-US>” << endl;

     else cout << ”不是汉字” << endl;



kk 2007-11-01 14:53 发表评论
]]>
常用数据cd使用转换详解http://www.shnenglu.com/jacky2019/archive/2007/11/01/35657.htmlkkkkThu, 01 Nov 2007 01:30:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/11/01/35657.htmlhttp://www.shnenglu.com/jacky2019/comments/35657.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/11/01/35657.html#Feedback0http://www.shnenglu.com/jacky2019/comments/commentRss/35657.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/35657.htmlhttp://www.vckbase.com/study/article/data_convert.htm




常用数据cd使用转换详解
作者:E佩?/p>


读者层ơ:初学

刚接触VC~程的朋友往往对许多数据类型的转换感到qh不解Q本文将介绍一些常用数据类型的使用?br>
我们先定义一些常见类型变量借以说明

int i = 100;
long l = 2001;
float f=300.2;
double d=12345.119;
char username[]="E佩?;
char temp[200];
char *buf;
CString str;
_variant_t v1;
_bstr_t v2;

一、其它数据类型{换ؓ字符?/strong>

  • 短整?int)
    itoa(i,temp,10);///i转换为字W串攑օtemp?最后一个数字表C十q制
    itoa(i,temp,2); ///按二q制方式转换
  • 长整?long)
    ltoa(l,temp,10);
  • 点?float,double)
    用fcvt可以完成转换,q是MSDN中的例子:
    int decimal, sign;
    char *buffer;
    double source = 3.1415926535;
    buffer = _fcvt( source, 7, &decimal, &sign );
    q行l果:source: 3.1415926535 buffer: '31415927' decimal: 1 sign: 0
    decimal表示数点的位置,sign表示W号:0为正敎ͼ1?
  • CString变量
    str = "2008北京奥运";
    buf = (LPSTR)(LPCTSTR)str;
  • BSTR变量
    BSTR bstrValue = ::SysAllocString(L"E序?);
    char * buf = _com_util::ConvertBSTRToString(bstrValue);
    SysFreeString(bstrValue);
    AfxMessageBox(buf);
    delete(buf);
  • CComBSTR变量
    CComBSTR bstrVar("test");
    char *buf = _com_util::ConvertBSTRToString(bstrVar.m_str);
    AfxMessageBox(buf);
    delete(buf);
  • _bstr_t变量
    _bstr_tcd是对BSTR的封装,因ؓ已经重蝲?操作W,所以很Ҏ使用
    _bstr_t bstrVar("test");
    const char *buf = bstrVar;///不要修改buf中的内容
    AfxMessageBox(buf);

  • 通用Ҏ(针对非COM数据cd)
    用sprintf完成转换
    char  buffer[200];
                    char  c = '1';
                    int   i = 35;
                    long  j = 1000;
                    float f = 1.7320534f;
                    sprintf( buffer, "%c",c);
                    sprintf( buffer, "%d",i);
                    sprintf( buffer, "%d",j);
                    sprintf( buffer, "%f",f);
                    

二、字W串转换为其它数据类?/font>
strcpy(temp,"123");

  • 短整?int)
    i = atoi(temp);
  • 长整?long)
    l = atol(temp);
  • 点(double)
    d = atof(temp);
  • CString变量
    CString name = temp;
  • BSTR变量
    BSTR bstrValue = ::SysAllocString(L"E序?);
    ...///完成对bstrValue的?br>SysFreeString(bstrValue);
  • CComBSTR变量
    CComBSTRcd变量可以直接赋?br>CComBSTR bstrVar1("test");
    CComBSTR bstrVar2(temp);
  • _bstr_t变量
    _bstr_tcd的变量可以直接赋?br>_bstr_t bstrVar1("test");
    _bstr_t bstrVar2(temp);

三、其它数据类型{换到CString
使用CString的成员函数Format来{?例如:

  • 整数(int)
    str.Format("%d",i);
  • 点?float)
    str.Format("%f",i);
  • 字符串指?char *){已l被CString构造函数支持的数据cd可以直接赋?br>str = username;
  • 对于Format所不支持的数据cdQ可以通过上面所说的关于其它数据cd转化到char *的方法先转到char *Q然后赋值给CString变量?br>

四、BSTR、_bstr_t与CComBSTR

  • CComBSTR 是ATL对BSTR的封装,_bstr_t是C++对BSTR的封?BSTR?2位指?但ƈ不直接指向字串的~冲区?br>char *转换到BSTR可以q样:
    BSTR b=_com_util::ConvertStringToBSTR("数据");///使用前需要加上comutil.h和comsupp.lib
    SysFreeString(bstrValue);
    反之可以使用
    char *p=_com_util::ConvertBSTRToString(b);
    delete p;
    具体可以参考一Q二D落里的具体说明?br>
    CComBSTR与_bstr_t对大量的操作W进行了重蝲Q可以直接进?,!=,=={操作,所以用非常方ѝ?br>特别是_bstr_t,大家使用它?br>

 

五、VARIANT 、_variant_t ?COleVariant

  • VARIANT的结构可以参考头文gVC98\Include\OAIDL.H中关于结构体tagVARIANT的定义?br>对于VARIANT变量的赋|首先lvt成员赋|指明数据cdQ再对联合结构中相同数据cd的变量赋|举个例子Q?br>VARIANT va;
    int a=2001;
    va.vt=VT_I4;///指明整型数据
    va.lVal=a; ///赋?br>
    对于不马上赋值的VARIANTQ最好先用Void VariantInit(VARIANTARG FAR* pvarg);q行初始?其本质是vt讄为VT_EMPTY,下表我们列Dvt与常用数据的对应关系:

    Byte bVal; // VT_UI1.
    Short iVal; // VT_I2.
    long lVal; // VT_I4.
    float fltVal; // VT_R4.
    double dblVal; // VT_R8.
    VARIANT_BOOL boolVal; // VT_BOOL.
    SCODE scode; // VT_ERROR.
    CY cyVal; // VT_CY.
    DATE date; // VT_DATE.
    BSTR bstrVal; // VT_BSTR.
    DECIMAL FAR* pdecVal // VT_BYREF|VT_DECIMAL.
    IUnknown FAR* punkVal; // VT_UNKNOWN.
    IDispatch FAR* pdispVal; // VT_DISPATCH.
    SAFEARRAY FAR* parray; // VT_ARRAY|*.
    Byte FAR* pbVal; // VT_BYREF|VT_UI1.
    short FAR* piVal; // VT_BYREF|VT_I2.
    long FAR* plVal; // VT_BYREF|VT_I4.
    float FAR* pfltVal; // VT_BYREF|VT_R4.
    double FAR* pdblVal; // VT_BYREF|VT_R8.
    VARIANT_BOOL FAR* pboolVal; // VT_BYREF|VT_BOOL.
    SCODE FAR* pscode; // VT_BYREF|VT_ERROR.
    CY FAR* pcyVal; // VT_BYREF|VT_CY.
    DATE FAR* pdate; // VT_BYREF|VT_DATE.
    BSTR FAR* pbstrVal; // VT_BYREF|VT_BSTR.
    IUnknown FAR* FAR* ppunkVal; // VT_BYREF|VT_UNKNOWN.
    IDispatch FAR* FAR* ppdispVal; // VT_BYREF|VT_DISPATCH.
    SAFEARRAY FAR* FAR* pparray; // VT_ARRAY|*.
    VARIANT FAR* pvarVal; // VT_BYREF|VT_VARIANT.
    void FAR* byref; // Generic ByRef.
    char cVal; // VT_I1.
    unsigned short uiVal; // VT_UI2.
    unsigned long ulVal; // VT_UI4.
    int intVal; // VT_INT.
    unsigned int uintVal; // VT_UINT.
    char FAR * pcVal; // VT_BYREF|VT_I1.
    unsigned short FAR * puiVal; // VT_BYREF|VT_UI2.
    unsigned long FAR * pulVal; // VT_BYREF|VT_UI4.
    int FAR * pintVal; // VT_BYREF|VT_INT.
    unsigned int FAR * puintVal; //VT_BYREF|VT_UINT.

  • _variant_t是VARIANT的封装类Q其赋值可以用强制类型{换,其构造函C自动处理q些数据cd?br>使用旉加上#include <comdef.h>
    例如Q?br>long l=222;
    ing i=100;
    _variant_t lVal(l);
    lVal = (long)i;

  • COleVariant的用与_variant_t的方法基本一P请参考如下例子:
    COleVariant v3 = "字符?, v4 = (long)1999;
    CString str =(BSTR)v3.pbstrVal;
    long i = v4.lVal;

六、其它一些COM数据cd

  • ҎProgID得到CLSID
    HRESULT CLSIDFromProgID( LPCOLESTR lpszProgID,LPCLSID pclsid);
    CLSID clsid;
    CLSIDFromProgID( L"MAPI.Folder",&clsid);
  • ҎCLSID得到ProgID
    WINOLEAPI ProgIDFromCLSID( REFCLSID clsid,LPOLESTR * lplpszProgID);
    例如我们已经定义?CLSID_IApplication,下面的代码得到ProgID
    LPOLESTR pProgID = 0;
    ProgIDFromCLSID( CLSID_IApplication,&pProgID);
    ...///可以使用pProgID
    CoTaskMemFree(pProgID);//不要忘记释放

七、ANSI与Unicode
UnicodeUCؓ宽字W型字串,COM里用的都是Unicode字符丌Ӏ?/p>

  • ANSI转换到Unicode
    (1)通过Lq个宏来实现Q例? CLSIDFromProgID( L"MAPI.Folder",&clsid);
    (2)通过MultiByteToWideChar函数实现转换,例如:
    char *szProgID = "MAPI.Folder";
    WCHAR szWideProgID[128];
    CLSID clsid;
    long lLen = MultiByteToWideChar(CP_ACP,0,szProgID,strlen(szProgID),szWideProgID,sizeof(szWideProgID));
    szWideProgID[lLen] = '\0';
    (3)通过A2W宏来实现,例如:
    USES_CONVERSION;
    CLSIDFromProgID( A2W(szProgID),&clsid);
  • Unicode转换到ANSI
    (1)使用WideCharToMultiByte,例如:
    // 假设已经有了一个Unicode ?wszSomeString...
    char szANSIString [MAX_PATH];
    WideCharToMultiByte ( CP_ACP, WC_COMPOSITECHECK, wszSomeString, -1, szANSIString, sizeof(szANSIString), NULL, NULL );
    (2)使用W2A宏来实现,例如:
    USES_CONVERSION;
    pTemp=W2A(wszSomeString);

八、其?/strong>

  • Ҏ息的处理中我们经帔R要将WPARAM或LPARAM{?2位数据(DWORD)分解成两?6位数据(WORD),例如Q?br>LPARAM lParam;
    WORD loValue = LOWORD(lParam);///取低16?br>WORD hiValue = HIWORD(lParam);///取高16?br>
  • 对于16位的数据(WORD)我们可以用同LҎ分解成高低两?位数?BYTE),例如:
    WORD wValue;
    BYTE loValue = LOBYTE(wValue);///取低8?br>BYTE hiValue = HIBYTE(wValue);///取高8?br>
  • 两个16位数据(WORDQ合?2位数?DWORD,LRESULT,LPARAM,或WPARAM)
    LONG MAKELONG( WORD wLow, WORD wHigh );
    WPARAM MAKEWPARAM( WORD wLow, WORD wHigh );
    LPARAM MAKELPARAM( WORD wLow, WORD wHigh );
    LRESULT MAKELRESULT( WORD wLow, WORD wHigh );

  • 两个8位的数据(BYTE)合成16位的数据(WORD)
    WORD MAKEWORD( BYTE bLow, BYTE bHigh );

  • 从R(red),G(green),B(blue)三色得到COLORREFcd的颜色?br>COLORREF RGB( BYTE byRed,BYTE byGreen,BYTE byBlue );
    例如COLORREF bkcolor = RGB(0x22,0x98,0x34);

  • 从COLORREFcd的颜色值得到RGB三个颜色?br>BYTE Red = GetRValue(bkcolor); ///得到U颜?br>BYTE Green = GetGValue(bkcolor); ///得到lK?br>BYTE Blue = GetBValue(bkcolor); ///得到兰颜?br>

九、注意事?/strong>
假如需要用到ConvertBSTRToString此类函数,需要加上头文gcomutil.h,q在setting中加入comsupp.lib或者直接加?pragma comment( lib, "comsupp.lib" )

后记Q本文匆匆写成,错误之处在所隑օQ欢q指?



kk 2007-11-01 09:30 发表评论
]]>
“休息”了半年http://www.shnenglu.com/jacky2019/archive/2007/10/29/35443.htmlkkkkMon, 29 Oct 2007 05:34:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/10/29/35443.htmlhttp://www.shnenglu.com/jacky2019/comments/35443.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/10/29/35443.html#Feedback0http://www.shnenglu.com/jacky2019/comments/commentRss/35443.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/35443.html

人生像龟兔赛跑。一开始领先不代表你会一直领先。同P一开始落后不代表你会一直落后。但是如果你下不了决心,不可能努力,没有自制力,没毅力的话,你肯定不会领先的?br>
乐观Q开朗,U极的态度。好长时间没有体会到领先带给我的乐趣了;好长旉没有体会到学习技术带l我的快乐了。该重新归队Q好好学习,好好工作了?br>
废话不多_开工?img height=20 src="http://www.shnenglu.com/Emoticons/QQ/12.gif" width=20 border=0>

kk 2007-10-29 13:34 发表评论
]]>
python与c++交互学习入门?http://www.shnenglu.com/jacky2019/archive/2007/06/06/25662.htmlkkkkWed, 06 Jun 2007 08:25:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/06/06/25662.htmlhttp://www.shnenglu.com/jacky2019/comments/25662.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/06/06/25662.html#Feedback7http://www.shnenglu.com/jacky2019/comments/commentRss/25662.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/25662.htmlq次讲讲Q如何扩展c++库。通过boost.python把c++库编译成python能够调用的dll?/p>


通过上一ơ的教程后,大家都应该会使用boost.python了。把c++E序~译成pyd文g。由于c++有很多特性,所以,如果你的E?/p>

序用了很多的c++Ҏ的话,那么你必d很多工作了。像虚拟函数Q函数重载,l承Q默认值等{。具体如何{化,请参

boost.python的文档了?/p>


q几天尝试着把c++E序库编译成python可调用的dllQ不知道Z么一直不可用。。很是郁闗老是昄如下的错误:

Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    import pydll
ImportError: No module named pydll

意思是说找不到dll。我把dll都copy到python/dlls下了q是不行Q而且我确定python的sys.path包含了python/dlls目录了?/p>

很是不解。网上也很难扑ֈ资料Qgoogle了很长时间找不到有用的资料,好像中文斚w的资料很的。今天尝试了一下google

英文资料Q终于有了新的发玎ͼ
http://mail.python.org/pipermail/c++-sig/2007-February/011971.html
You are using Python2.5. In this version of Python you have to have
file extension
to be "pyd" - sge.pyd

--
Roman Yakovenko
C++ Python language binding
http://www.language-binding.net/

有h到的问题跟我的是一L。后面那个Roman回答了一下,是文件扩展名的问题!Q!Z么不支持dll呢?不解。回去试

了一下把后缀名改了就成功了。。。why???


下面来看一下我的那个简单的例子Q?br>q个例子来自于网上,
http://www.vckbase.com/document/viewdoc/?id=1540
C++ 扩展和嵌?Python
作者:胡金?br>源码下蝲地址Q?a >http://www.vckbase.com/code/downcode.asp?id=2777


q是一个非常简单的dll工程。给python提供了一个函数static PyObject* Recognise(PyObject *self, PyObject *args)?/p>


1、不使用boost.python库来直接构徏dll
接下来,我们来用C++为Python~写扩展模块(动态链接库)Qƈ在PythonE序中调用C++开发的扩展功能函数。生成一个取名ؓ

pyUtil的Win32 DLL工程Q除了pyUtil.cpp文g以外Q从工程中移除所有其它文Ӟq填入如下的代码Q?

// pyUtil.cpp
#ifdef PYUTIL_EXPORTS
#define PYUTIL_API __declspec(dllexport)
#else
#define PYUTIL_API __declspec(dllimport)
#endif

#include<windows.h>
#include<string>
#include<Python.h>
BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
        )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
std::string Recognise_Img(const std::string url)
{
    //q回l果
    return "从dll中返回的数据... : " +url;
}
static PyObject* Recognise(PyObject *self, PyObject *args)
{
    const char *url;
    std::string sts;
    if (!PyArg_ParseTuple(args, "s", &url))
        return NULL;
    sts = Recognise_Img(url);
    return Py_BuildValue("s", sts.c_str() );
}
static PyMethodDef AllMyMethods[] = {
    {"Recognise",  Recognise, METH_VARARGS},//暴露lPython的函?br>    {NULL,      NULL}        /* Sentinel */
};
extern "C" PYUTIL_API void initpyUtil()
{
    PyObject *m, *d;
    m = Py_InitModule("pyUtil", AllMyMethods); //初始化本模块Qƈ暴露函数
    d = PyModule_GetDict(m);
}

在Python代码中调用这个动态链接库Q?(记得把dll的扩展名改ؓ.pydQ另外dll的\径要能够被检索到)
import pyUtil
result = pyUtil.Recognise("input url of specific data")
print "the result is: "+ result

 

2、用boost.python库来构徏dll
用C++为Python写扩展时Q如果您愿意使用Boost.Python库的话,开发过E会变得更开心JQ要~写一个与上述pyUtil同样功能

的动态链接库Q只需把文件内Ҏ换ؓ下面的代码。当Ӟ~译需要boost_python.lib支持Q运行需要boost_python.dll支持

?
#include<string>
#include <boost/python.hpp>
using namespace boost::python;
#pragma comment(lib, "boost_python.lib")
std::string strtmp;
char const* Recognise(const char* url)
{
    strtmp ="从dll中返回的数据... : ";
    strtmp+=url;
    return strtmp.c_str();
}
BOOST_PYTHON_MODULE(pyUtil)
{
    def("Recognise", Recognise);
}

可以非常明显地看刎ͼ用了boost.python库之后,单了很多。因为boost.pythonZ做了很多的事情。。恩?/p>

 

好像没有讲很多有用的东西Q光儡讲了Q呵c。。我也还在l学习之中。下ơ写点什么呢Ql学习了?/p>

 



kk 2007-06-06 16:25 发表评论
]]>
c++中嵌入python入门4 ?Boost.Pythonhttp://www.shnenglu.com/jacky2019/archive/2007/06/01/25254.htmlkkkkFri, 01 Jun 2007 02:32:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/06/01/25254.htmlhttp://www.shnenglu.com/jacky2019/comments/25254.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/06/01/25254.html#Feedback5http://www.shnenglu.com/jacky2019/comments/commentRss/25254.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/25254.html坏境python25 + vs2005 (2005真耗资源阿。。?

有一D|间没写blog了。这几天都在研究怎么装c++Q让python可以用c++的库。在|上发现了boost.pythonq个好咚咚。不

q在使用q程中碰C炚w题。本文教大家如何?/p>

char const* greet()
{
   return "hello, world";
}

装成python。实际上q是python教程里面的咚咚?/p>


首先下蝲BoostQ?a >www.boost.org。boost.python在boost里面了。在visual studio 2005 command prompt中navigation?/p>

boost\boost_1_34_0\下。记得一定要用visual studio 2005 command promptq个vs2005带的toolsQ不要用cmd.exeQ否则会

到很多错误的。然后就是把bjam.exe拯C个能被找到的目录下,或者直接也拯到boost\boost_1_34_0\下即可。然后,

讄python的根目录和python的版本,也可直接把它们加到坏境目录中Q那样就不用每次都设|一下?br>set PYTHON_ROOT=c:/python25
set PYTHON_VERSION=2.5

接着可以直接运行了Qbjam -sTOOLS=vc-8_0
整个~译q程要很长时间。。?/p>

成功之后Q就会有好多个boost_python-vc80-****.dll,.lib的,把他们都拯C个能被系l找到的目录Q不妨直接把他们?/p>

扔到c:\windows\system32下?/p>

接着Q我们开始编译hello。navigation到boost\boost_1_34_0\libs\python\example\tutorial下,bjam -sTOOLS=vc-8_0q行

Q在bin的目录下即会生成hello.pyd。这下就基本成功了,如果没成功的话,check一下上面boost_python的那些dll能否被系

l找到。另外,q里有python25的一个bug。。。我׃很长旉才在python的mail lists中找C。寒。。?/p>

错误如下所C:
D:\Learn\Python\boost\boost_1_34_0\libs\python\example\tutorial>bjam
Jamroot:17: in modules.load
rule python-extension unknown in module Jamfile</D:/Learn/Python/boost/boost_1_3
4_0/libs/python/example/tutorial>.
D:/Learn/Python/boost/boost_1_34_0/tools/build/v2/build\project.jam:312: in load
-jamfile
D:/Learn/Python/boost/boost_1_34_0/tools/build/v2/build\project.jam:68: in load
D:/Learn/Python/boost/boost_1_34_0/tools/build/v2/build\project.jam:170: in proj
ect.find
D:/Learn/Python/boost/boost_1_34_0/tools/build/v2\build-system.jam:237: in load
D:\Learn\Python\boost\boost_1_34_0\libs\python\example\..\..\..\tools\build\v2/k
ernel\modules.jam:261: in import
D:\Learn\Python\boost\boost_1_34_0\libs\python\example\..\..\..\tools\build\v2/k
ernel/bootstrap.jam:132: in boost-build
D:\Learn\Python\boost\boost_1_34_0\libs\python\example\boost-build.jam:7: in mod
ule scope

解决办法如下Q?br>在boost\boost_1_34_0\tools\build\v2\目录下找到user-config.jam文gQ打开?br>import toolset : using ;
下面加一行代码:
using python ;
再重新编译一下boostQ然后就没问题了。tutorial里面的hello能顺利编译通过。ps.q个问题困扰了我好长旉。。sigh。?/p>

?/p>

~译成功后会产生一个hello.pydQ在bin的目录下面?/p>


有好多办法测试此hello.pyd是否可以用?br>Ҏ一Q把它拷贝到python25\dlls下,打开IDLEQ?br>>>> import hello
>>> hello.greet()
'hello, world'
>>>
Ҏ二,直接在当前目录下写一个python文gQ然后直接调用hello.pyd卛_。MQhello.pyd是一个python文g了。。嗯

。操作hello.pyd根其他python文g是一L?br>q样成功了?/p>

如果到如下错误Q是因ؓpȝ找不到boost_python的dll。强烈徏议把他们都扔到system32下!?/p>

>>> import hello

Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    import hello
ImportError: DLL load failed: 找不到指定的模块?br>>>>


说明Qhello.cpp在boost\boost_1_34_0\libs\python\example\tutorial目录下。里面的内容是:

//  Copyright Joel de Guzman 2002-2004. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt
//  or copy at http://www.boost.org/LICENSE_1_0.txt)
//  Hello World Example from the tutorial
//  [Joel de Guzman 10/9/2002]

char const* greet()
{
   return "hello, world";
}

#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
using namespace boost::python;

BOOST_PYTHON_MODULE(hello)
{
    def("greet", greet);
}


其中
BOOST_PYTHON_MODULE(hello)
{
    def("greet", greet);
}
是对greet从c++向python的一个封装声明吧Q装换就交给boost了?/p>

 

先写到这里了。下ơ再写。。嗯



kk 2007-06-01 10:32 发表评论
]]>
W记本主板坏?/title><link>http://www.shnenglu.com/jacky2019/archive/2007/05/31/25203.html</link><dc:creator>kk</dc:creator><author>kk</author><pubDate>Thu, 31 May 2007 07:58:00 GMT</pubDate><guid>http://www.shnenglu.com/jacky2019/archive/2007/05/31/25203.html</guid><wfw:comment>http://www.shnenglu.com/jacky2019/comments/25203.html</wfw:comment><comments>http://www.shnenglu.com/jacky2019/archive/2007/05/31/25203.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.shnenglu.com/jacky2019/comments/commentRss/25203.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/jacky2019/services/trackbacks/25203.html</trackback:ping><description><![CDATA[郁闷Q极度郁闗。? <img src ="http://www.shnenglu.com/jacky2019/aggbug/25203.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/jacky2019/" target="_blank">kk</a> 2007-05-31 15:58 <a href="http://www.shnenglu.com/jacky2019/archive/2007/05/31/25203.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c++中嵌入python入门3http://www.shnenglu.com/jacky2019/archive/2007/05/17/24286.htmlkkkkThu, 17 May 2007 07:16:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/05/17/24286.htmlhttp://www.shnenglu.com/jacky2019/comments/24286.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/05/17/24286.html#Feedback3http://www.shnenglu.com/jacky2019/comments/commentRss/24286.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/24286.htmlq次主要讲讲怎么把python中的class嵌入到c++中去?br>Z讲讲元组的操作和怎么~译python源代码?/p>

1. 首先讲讲元组的操?br>׃参数是通过元组传进ȝQ所以我们不能老是通过Py_BuildValueq个函数来操作元l,那样太不方便了?br>Python提供了元l相关的操作Q下面这个例子演CZ如何操作。主要是下面几个函数Q?br>//new一个元l,传入size
pArgs = PyTuple_New(argc - 3); 
//set元组的直Q第一个ؓ元组Q第二个为indexQ从0开始)Q第三个为value
PyTuple_SetItem(pArgs,0,Py_BuildValue("i",2000) );
PyTuple_SetItem(pArgs,1,Py_BuildValue("i",8) );

来自python doc的一个例?/p>

#include <Python.h>
int
main(int argc, char *argv[])
{
    PyObject *pName, *pModule, *pDict, *pFunc;
    PyObject *pArgs, *pValue;
    int i;

    if (argc < 3) {
        fprintf(stderr,"Usage: call pythonfile funcname [args]\n");
        return 1;
    }

    Py_Initialize();
    pName = PyString_FromString(argv[1]);
    /* Error checking of pName left out */

    pModule = PyImport_Import(pName);
    Py_DECREF(pName);

    if (pModule != NULL) {
        pFunc = PyObject_GetAttrString(pModule, argv[2]);
        /* pFunc is a new reference */

        if (pFunc && PyCallable_Check(pFunc)) {
            pArgs = PyTuple_New(argc - 3);
            for (i = 0; i < argc - 3; ++i) {
                pValue = PyInt_FromLong(atoi(argv[i + 3]));
                if (!pValue) {
                    Py_DECREF(pArgs);
                    Py_DECREF(pModule);
                    fprintf(stderr, "Cannot convert argument\n");
                    return 1;
                }
                /* pValue reference stolen here: */
                PyTuple_SetItem(pArgs, i, pValue);
            }
            pValue = PyObject_CallObject(pFunc, pArgs);
            Py_DECREF(pArgs);
            if (pValue != NULL) {
                printf("Result of call: %ld\n", PyInt_AsLong(pValue));
                Py_DECREF(pValue);
            }
            else {
                Py_DECREF(pFunc);
                Py_DECREF(pModule);
                PyErr_Print();
                fprintf(stderr,"Call failed\n");
                return 1;
            }
        }
        else {
            if (PyErr_Occurred())
                PyErr_Print();
            fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);
        }
        Py_XDECREF(pFunc);
        Py_DECREF(pModule);
    }
    else {
        PyErr_Print();
        fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
        return 1;
    }
    Py_Finalize();
    return 0;
}


2. class操作
把下面加入到test2.py中去。定义了一个很单的c,有一个name成员变量Q一个printName成员函数
class TestClass:
    def __init__(self,name):
        self.name = name

    def printName(self):
        print self.name

cpp文g
#include <python.h>
int main()
{
 Py_Initialize();

 PyObject * pModule = NULL;
 PyObject * pFunc   = NULL;
 PyObject * pArg    = NULL;
 PyObject * pClass  = NULL;
 PyObject * pObject = NULL;

 pModule = PyImport_ImportModule("test2");
 pClass  = PyObject_GetAttrString(pModule, "TestClass");//得到那个c?br> pArg = PyTuple_New(1);
 PyTuple_SetItem(pArg, 0, Py_BuildValue("s", "Jacky"));
 pObject = PyEval_CallObject(pClass, pArg);//生成一个对象,或者叫作实?/p>

 pFunc = PyObject_GetAttrString(pObject, "printName");//得到该实例的成员函数
 PyEval_CallObject(pFunc, NULL);//执行该实例的成员函数

 Py_Finalize();

 return 0;
}


没有什么资料,先写到q里了。下面介l一下怎么build python25的源代码

3. ~译python源代?br>Z么要~译呢?因ؓ没有python25_d.libQ呵c顺便可以了解一下代码结构?br>解压~后Q有好多目录Q其中pcbuild和pcbuild8是我们要的。pcbuild对应着vc7.1?pcbuild8对应着vc8.0?br>因ؓ在用vc7.1Q也是2003了。所以我p说怎么?003来编译吧。事实上是从一位牛人那里学来的

http://blog.donews.com/lemur/archive/2005/12/17/660973.aspxQ那位大哥大概一q半前就在解剖python了,厉害

ѝ看来我只能后来居上了,娃哈哈。我按照他说的试了一下,~译成功Q?/p>

不过遇到一点小问题Q用vc2003打开那个solution的时候,发现作者没有把source code controlLQ郁P害的?/p>

们打开的时候一堆messagebox。不q不用管它就好了Q一直确定。最后试了一下那个python25_d.libQ没问题。不q记

得把python25_d.dll copyC个能被找到的目录Q比如说c:\windows\system32\下面。python25.dll也在q个目录?/p>

面。over。恩?/p>

 



kk 2007-05-17 15:16 发表评论
]]>
c++中嵌入python入门2http://www.shnenglu.com/jacky2019/archive/2007/05/17/24276.htmlkkkkThu, 17 May 2007 03:28:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/05/17/24276.htmlhttp://www.shnenglu.com/jacky2019/comments/24276.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/05/17/24276.html#Feedback0http://www.shnenglu.com/jacky2019/comments/commentRss/24276.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/24276.html1. 一个有一个参数的例子

python文g
#Filename test2.py

def Hello(s):
    print "Hello, world!"
    print s

cpp文g
#include <python.h>
int main()
{
 Py_Initialize();

 PyObject * pModule = NULL;
 PyObject * pFunc   = NULL;
 PyObject * pArg    = NULL;

 pModule = PyImport_ImportModule("test2");
 pFunc   = PyObject_GetAttrString(pModule, "Hello");
 pArg    = Py_BuildValue("(s)", "function with argument");

 PyEval_CallObject(pFunc, pArg);

 Py_Finalize();

 return 0;
}

注意Q参数要以tuple元组形式传入。因个函数只要一个参敎ͼ所以我们直接?s)构造一个元l了?/p>

2. 一个有两个参数的例?/p>

python文g中加入以下代码,一个加函数
def Add(a, b):
    print "a+b=", a+b

cpp文gQ只改了两行Q有注释的那两行
#include <python.h>
int main()
{
 Py_Initialize();

 PyObject * pModule = NULL;
 PyObject * pFunc   = NULL;
 PyObject * pArg    = NULL;

 pModule = PyImport_ImportModule("test2");
 pFunc   = PyObject_GetAttrString(pModule, "Add");//l于告别hello world了,开始用新的函?br> pArg    = Py_BuildValue("(i,i)", 10, 15);//构造一个元l?/p>

 PyEval_CallObject(pFunc, pArg);

 Py_Finalize();

 return 0;
}

其它的就cM了。。。基本上Q我们知道了怎么在c++中用python中的函数。接下来学习一下如何用python中的

class?/p>

附:Py_BuildValue的用例子,来自python documentationQ?/p>

    Py_BuildValue("")                        None
    Py_BuildValue("i", 123)                  123
    Py_BuildValue("iii", 123, 456, 789)      (123, 456, 789)
    Py_BuildValue("s", "hello")              'hello'
    Py_BuildValue("ss", "hello", "world")    ('hello', 'world')
    Py_BuildValue("s#", "hello", 4)          'hell'
    Py_BuildValue("()")                      ()
    Py_BuildValue("(i)", 123)                (123,)
    Py_BuildValue("(ii)", 123, 456)          (123, 456)
    Py_BuildValue("(i,i)", 123, 456)         (123, 456)
    Py_BuildValue("[i,i]", 123, 456)         [123, 456]
    Py_BuildValue("{s:i,s:i}",
                  "abc", 123, "def", 456)    {'abc': 123, 'def': 456}
    Py_BuildValue("((ii)(ii)) (ii)",
                  1, 2, 3, 4, 5, 6)          (((1, 2), (3, 4)), (5, 6))



kk 2007-05-17 11:28 发表评论
]]>
c++中嵌入python入门1http://www.shnenglu.com/jacky2019/archive/2007/05/17/24269.htmlkkkkThu, 17 May 2007 03:03:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/05/17/24269.htmlhttp://www.shnenglu.com/jacky2019/comments/24269.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/05/17/24269.html#Feedback6http://www.shnenglu.com/jacky2019/comments/commentRss/24269.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/24269.html本h是用vc2003+python2.5学习的,其它的也应该差不了多?/p>

0. 坏境讄
把python的include/libs目录分别加到vc的include/lib directories中去。另外,׃python没有提供debug libQ体地说Q就是没有提供python25_d.lib了。你可以自己~译python的源代码来得到python25_d.lib的,偶还没试q,呵呵。而且|上找了一下也没下载到。所以,如果你想要在debug下运行程序的话,你要把pyconfig.hQ在python25/include/目录下)的大概是?83行,把pragma comment(lib,"python25_d.lib")Ҏpragma comment(lib,"python25.lib")Q让python都用非debug lib.

1. 开始编E了
#include <python.h>
W一步就是包含python的头文g

2. 看一个很单的例子
1)python文gtest.pyQ很单的定义了一个函?/p>

#Filename test.py
def Hello():
    print "Hello, world!"

q个应该能看懂的吧?否则的话Q回dl练python吧,呵呵。《简明Python教程》Swaroop, C. H. 著。沈z元  译?/p>


2)cpp文g

#include <python.h> //包含头文Ӟ在c++中嵌入pythonQ这是必ȝ
int main()
{
 Py_Initialize();

 PyObject * pModule = NULL;
 PyObject * pFunc   = NULL;

 pModule = PyImport_ImportModule("test");
 pFunc   = PyObject_GetAttrString(pModule, "Hello");
 PyEval_CallObject(pFunc, NULL);

 Py_Finalize();

 return 0;
}

W一步还是包含头文g

W二步,使用python之前Q要调用Py_Initialize();q个函数q行初始化?br>帮助文档中如是说Q?br>The basic initialization function is Py_Initialize(). This initializes the table of loaded modules, and creates the fundamental modules __builtin__, __main__, sys, and exceptions. It also initializes the module search path (sys.path).

反正Q一开始你一定要调用?/p>

W三步,声明一些Python的变量,PyObjectcd的。其实声明也可放在前面,q个倒是无所谓的?/p>

W四步,import moduleQ也是你的脚本名字Q不需要加后缀名,否则会出错的?/p>

W五步,从你importq来的module中得C要的函数
 pFunc   = PyObject_GetAttrString(pModule, "Hello");
上面的例子已l够清楚的了Q最后一个是你要得到的函数的名字

W六步,调用PyEval_CallObject来执行你的函敎ͼW二个参Cؓ我们要调用的函数的函敎ͼ本例子不含参敎ͼ所以设|ؓNULL?/p>

W七步,调用Py_FinalizeQ这个根Py_Initialize相对应的。一个在最前面Q一个在最后面?/p>

 

W一ơ写教程。这个例子非常简单,本h也还在学习当中阿Q只能保证大家能够把q个例子q行h。徏议大家去看python的documentaionQ里面有讲怎么embedding python的。先写到q里Q其实目前也只学到这么多Q呵c下ơ学了更多以后再写。Over。恩?/p>

 



kk 2007-05-17 11:03 发表评论
]]>
sighhttp://www.shnenglu.com/jacky2019/archive/2007/05/08/23647.htmlkkkkTue, 08 May 2007 13:14:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/05/08/23647.htmlhttp://www.shnenglu.com/jacky2019/comments/23647.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/05/08/23647.html#Feedback0http://www.shnenglu.com/jacky2019/comments/commentRss/23647.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/23647.html

kk 2007-05-08 21:14 发表评论
]]>
The difference between GetDC and GetWindowDChttp://www.shnenglu.com/jacky2019/archive/2007/04/21/22467.htmlkkkkSat, 21 Apr 2007 04:54:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/04/21/22467.htmlhttp://www.shnenglu.com/jacky2019/comments/22467.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/04/21/22467.html#Feedback0http://www.shnenglu.com/jacky2019/comments/commentRss/22467.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/22467.htmlGetDC

The GetDC function retrieves a handle of a display device context (DC) for the client area of the specified window. The display device context can be used in subsequent GDI functions to draw in the client area of the window.

This function retrieves a common, class, or private device context depending on the class style specified for the specified window. For common device contexts, GetDC assigns default attributes to the device context each time it is retrieved. For class and private device contexts, GetDC leaves the previously assigned attributes unchanged.

HDC GetDC(

    HWND hWnd                 // handle of window 

   );         

Parameters

hWnd

Identifies the window whose device context is to be retrieved.

 

GetWindowDC

The GetWindowDC function retrieves the device context (DC) for the entire window, including title bar, menus, and scroll bars. A window device context permits painting anywhere in a window, because the origin of the device context is the upper-left corner of the window instead of the client area.

GetWindowDC assigns default attributes to the window device context each time it retrieves the device context. Previous attributes are lost.

HDC GetWindowDC(

    HWND hWnd                 // handle of window 

   );         

Parameters

hWnd

Identifies the window with a device context that is to be retrieved.



kk 2007-04-21 12:54 发表评论
]]>
求n!的结果中末尾0的个?/title><link>http://www.shnenglu.com/jacky2019/archive/2007/04/19/22306.html</link><dc:creator>kk</dc:creator><author>kk</author><pubDate>Thu, 19 Apr 2007 07:30:00 GMT</pubDate><guid>http://www.shnenglu.com/jacky2019/archive/2007/04/19/22306.html</guid><wfw:comment>http://www.shnenglu.com/jacky2019/comments/22306.html</wfw:comment><comments>http://www.shnenglu.com/jacky2019/archive/2007/04/19/22306.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/jacky2019/comments/commentRss/22306.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/jacky2019/services/trackbacks/22306.html</trackback:ping><description><![CDATA[<p><span>l于悟到了?/span></p> <p><span>首先Q很Ҏ惛_的就是,?/span>0<span>的个敎ͼ是?/span>5<span>的个敎ͼ如果q个你都想不明白的话Q那。。。再好好x吧,呵呵Q;</span></p> <p><span>接下来,如何?/span>5<span>的个数呢Q如果遍历一遍的话,那显然是太慢了!因ؓq种计算题太有规律了Q想了好久,l于惛_来了Q?/span></p> <p>Result = 0; // <span>最后的l果</span></p> <p>while ( N >= 5 )</p> <p>{</p> <p> N /= 5;</p> <p> Result += N;</p> <p>}</p> <p>// <span>l束了?/span></p> <p> </p> <p><span>没错Q就是这么简单!下面单说说ؓ什么这样子做是对的Q偶试了一下,没问题,呵呵Q:</span></p> <p><span>W一ơ除?/span>5<span>表示</span>5<span>的倍数的个敎ͼ</span></p> <p><span>W二ơ除?/span>5<span>表示</span>5<span>的^方的倍数的个敎ͼQ显Ӟ</span>5<span>的^Ҏ含了两个</span>0<span>Q?/span></p> <p><span>。。。依此类?/span></p> <p><span>最后当</span>N<5<span>了,l束?/span></p> <p> </p> <p><span>小的验证一下:</span></p> <p>26<span>Q?/span></p> <p>26/5 = 5<span>Q?/span> 5/5 = 1<span>Q那么最?/span>0<span>的个数就?/span>6<span>了。用</span>Google<span>了一下,l果</span>G<span>大叔直接用有效数字表CZQ?/span>@$%$%@$%<span>。。。不q应该是没错了。恩?/span></p> <p>Sigh<span>Q知道结果后才知道原来这么简单的阿,偶土了?/span></p> <img src ="http://www.shnenglu.com/jacky2019/aggbug/22306.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/jacky2019/" target="_blank">kk</a> 2007-04-19 15:30 <a href="http://www.shnenglu.com/jacky2019/archive/2007/04/19/22306.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>48 Ways to Wisdom - Way 4, Introduce Yourself to Yourselfhttp://www.shnenglu.com/jacky2019/archive/2007/04/18/22222.htmlkkkkWed, 18 Apr 2007 08:22:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/04/18/22222.htmlhttp://www.shnenglu.com/jacky2019/comments/22222.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/04/18/22222.html#Feedback4http://www.shnenglu.com/jacky2019/comments/commentRss/22222.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/22222.htmlDid you ever get on a train going somewhere, only to find that you're headed in the wrong direction?

The same thing happens in life. We set goals and make plans - and sometimes discover that we're on "the wrong train."

Bi-vinat ha-lave literally means "understanding the heart." The heart is the seat of emotions. We say: "My heart is heavy, my heart is lifted, my heart is broken," etc. To understand your heart is to understand your true inner self.

Many people go through life making assumptions about who they are. They never take time to "meet" themselves. Don't be afraid of discovering that the "real you" may be different than the "current you."

Often a crisis hits at midlife when people ask: "What's my life about? Is this all worth it?" We've heard stories of people who suddenly change direction, quitting their job and getting divorced. You know, like the successful doctor who decides he never wanted to go into medicine in the first place -- so he drops it and becomes an artist.

Knowing yourself is the essence of being alive. If you don't know yourself, you are not living. If you don't know what makes you tick, you're a robot, a puppet, a zombie.

So don't wait for a crisis. Life is too short to take wrong trains.

GETTING STARTED

Think of someone you'd be fascinated to meet, someone you'd really like to find out what makes him tick.

Now realize the most fascinating person you could ever meet is ... yourself.

Sit down, say hello, and introduce yourself to yourself. Become familiar with yourself as if you'd just met a long-lost cousin. Interview yourself. Ask questions about your life and the direction you're going. Search out your dreams -- both the ones you're fulfilling and the ones you've pushed to the back of your mind.

Get down to basics. You want to be rich. You want to be famous. You want to be good. You want to accomplish. You want meaning. You want to be creative. But why do you want all this? What's driving you? What you really want out of life?

The process of self-discovery involves asking a series of questions, always probing deeper until the underlying truth emerges. Ask yourself 10 questions that you would ask an intimate friend. Then wait for answers. Don't worry, no one is going to poke fun at you.

  1. What is the purpose of life?
  2. What is my goal in life?
  3. Why did I choose this career?
  4. How do I spend my spare time?
  5. What is my motivation for doing what I do?
  6. What really makes me happy?
  7. Am I as happy as I want to be?
  8. Is it more important to be rich or to be happy?
  9. What are my future plans? Why?
  10. What are my secret dreams and ambitions?

Don't be surprised if the answers aren't immediate. This process can take many months. Stick with it and find out what makes you tick. The answers are hiding in there. After all, you have a fascinating partner.

Finally, the most important question to ask is:

"What am I living for?"

It sounds like a simple question, but many are embarrassed to ask it. A voice inside us says, "Nah, why ask such a basic question?" We're resistant because we know this requires a lot of difficult soul-searching. And when you thoroughly know yourself, then you have changed. You've changed your relationship with yourself and the world.

CONFIDENCE IN DECISION-MAKING

People often avoid making decisions out of fear of making a mistake.

Actually, the failure to make decisions is one of life's biggest mistakes.

Imagine the beggar who receives a letter saying that he's inherited a million dollars. If he doesn't read the letter, is he rich ... or not?

Similarly, God gave us the free will to make choices in life and achieve greatness. But if we're not aware of our free will, then we don't really have it. And then we wind up blaming others when things go wrong -- even though we know the decision is really up to us.

If you're not using your potential, it wears away at your confidence. Do you know what your potential is? Have you tried to use it? You have to tackle life. You haven't given up yet, have you? Let's get on with the game, with the business of really living, of not just "going through the motions."

Know the difference between "making decisions" and just floating, falling into place. Did you choose to go to college? Or perhaps you had nothing to do with the decision. Was it something you just did because you graduated high school and everybody else was doing it? Did you think it through and actually make a decision?

Imagine this private conversation of a college student:

Why am I going to college?
To get a degree.
Why?
Because I want to get into a good graduate school.
Why?
So I'll get a good job.
Why?
So I can pay back my college loans!

Through the process of questioning, he reveals a logical fault in his motivation. Really, the primary reason for going to college should be to acquire wisdom, knowledge and information. In other words, to get an education!

Now try the process yourself, using this example:

Why do I want to get married?

Don't accept pat answers. Keep asking "Why, why why?" Be frank. It's yourself. Ask any question you like. Be patient and persistent. Eventually you'll get an answer.

When you thoroughly analyze an issue, then you can make wise decisions with confidence.

Identify where you lack confidence. What makes you nervous? What situations inhibit you from being yourself? Why can't you make decisions? Is it that you don't know how to make decisions? Or that you doubt your decisions after they're made? Or you just don't feel like making decisions?

Enjoy making decisions. Deal with the world you live in. That's loving the dynamics of life.

ISOLATE YOUR BLOCKS

Anytime you find it difficult to achieve a goal, figure out what's holding you back.

Everyone has problems. Being aware of these problems is the key to getting in touch with yourself. Because as long as you don't face problems, they fester and bug you from behind.

Write your "blocks" on a piece of paper. That's a good step in the right direction. By isolating specific obstacles, you turn them into concrete challenges that require solutions.

Ask yourself:

  • Am I lazy? Why?
  • Am I disorganized? Why?
  • Do I get angry? When?
  • Why do ever I get defensive? About what?
  • What makes me jealous?
  • What makes me arrogant?
  • Do I have trouble making decisions? Why?
  • Do I lack self-discipline?
  • Do I lack self-confidence?
  • Why don't I take more initiative?

Negative character traits are the roots of our problems. Make a list of your negative traits, and identify when they affect you the most. Then analyze what triggers these reactions in you. Finally, formulate an effective counter-approach.

Working through this takes time. But do you have anything better to be doing right now?

READ YOUR EMOTIONS

Get in touch with your emotional state. Take a reading of how you feel. Happy? Angry? Tense? Sad? Emotions are a measuring stick for what's going on below the surface. It's like taking your temperature. If you're sick, you need to be aware so you can fix the problem.

Find out why you're upset. Who or what is pressuring you? Is it an internal or an external problem? Identify it.

Let's say you are irritated. Why?

Because the boss chewed me out.
So why am I irritated?
Because I resent him.
So what? Why does that bother me?
Because I feel I am no good.
I'm no good? He's nuts!

Get out of yourself and track it down. If you don't, it's just irritation. And the next thing you know, you'll go home and yell at your kids.

Once you've identified what causes negative feelings, adjust yourself to minimize the impact. Either avoid these situations, or prepare yourself to handle them when they arise.

Further, root out negative motivations that corrupt your behavior. Let's say that you give charity. Why? One motivation is to help humanity. Another is the pleasure of being constructive. A third is the desire to do the right thing. These are all positive motivations. A negative motivation for giving charity is: "I want people to admire me." That's corruptive.

The next time you give charity, do so anonymously. Eliminate the wrong reasons. They are destructive.

The same goes with the positive emotions. Be aware of how your emotional state affects decisions. For example, don't buy a new stereo when you're in a euphoric mood. Wait. Think it over. You are susceptible.

Pinpoint what makes you happy. You can have more joy on a daily basis by formulating some practical applications. You got up in the morning, it's a gorgeous day and you feet great. You're energized. Now take that feeling and teach yourself how to get up on the right side -- every day!

Another example: You did a good job and got the boss's compliment. Now focus: Do you need the boss to tell you did a good job? No! Create your own pleasure out of doing a good job.

GET IN TOUCH WITH YOUR TWO SIDES

Everyone has an urge for greatness. We want self respect, power, fame. We want to accomplish, to be strong, to do the right thing, to even save the world.

Yet at the same time, we have a counter-urge to run away from responsibility, to get into bed and crawl under the covers.

Someone may say, "Life is beautiful," but he doesn't feel it. His emotions hold him back and he walks around going, "Ugh, life is a burden."

Recognize the volcano of conflict within you: What you truly "want," versus what you "feel" like. This is the conflict between body and soul.

Once you appreciate the dichotomy, you can identify at any moment whether your body or soul is talking. This makes it possible to live with sanity and choose the right thing.

The next step is to make peace between your two sides. The easiest way is to squash your drive to be great. But life is not about taking the easy way out. Just because you feel uncomfortable about an idea doesn't mean it's wrong for you. It's hard to break habits, and growth can be frightening.

For example, would you rather be happy or rich? Okay, you'd rather be happy. Now imagine this exchange:

"Come on, I'll teach you how to be happy. All it requires is effort and change."

"Oh, I'd love to, but I can't right now. It's impossible. I've got a flight to catch."

"Really? I'll pay you $10,000 a week to work on happiness."

"Sure! Where do I sign up?"

"Oh, but I thought you can't right now..."

We conceal our problems with rationalization: "I'll wreck my mind thinking about what life is about! Nobody really knows what life is about. It's not going to work. Nothing can be done about it anyway. I don't really care. It's not worth the time!"

The Sages say that a person only makes a mistake when overcome by a moment of insanity. So realize that you are fighting "insanity." It is not logical. You've got to be on guard. Because if you get off track, you'll pay for it down the road.

So ... do you want to change? What have you got against it? Feel the antipathy of the body. We are so darn lazy. The body just wants to sleep. "Aaaah ... I don't want to change. I'm happy enough. I'm comfortable in my niche of misery." Are you rich enough? No! So are you happy enough?

You see the importance of tracking that down? You have to identify the animal you are fighting. "The dread of change."

If you're alert, you see the enemy. You can fight it. You may lose a struggle with the body, but at least you have your confidence. "I know what I am doing."

COAX THE BODY

Get in touch with your spiritual core. Know what is driving you. Don't let free will be a subconscious thing. You want greatness. But the body says that's too much effort.

To try to convince the body, try to identify the tangible benefit. "Why is it necessary? What will it do for me?" You have to bring it home to emotional realization. "What do I lose?" What do I gain?" Only then will the idea have power. And you'll get out there and do it.

Here's the secret formula: Identify with your intellect, and coax your heart along. For example, if you're emotionally convinced of the benefit of getting into shape, then even when you break out in a cold sweat and your heart is doing palpitations, you will keep going. Because you have decided, "I want this," you know it is important.

To avoid negative backlash, your emotions have to feel comfortable with the changes you make. Learn to relax and reassure the body. Cajole the body and say, "It won't be so bad. Remember the last time you made an effort, how great you felt!" Be encouraging and reward yourself for success.

Don't say it doesn't work. You haven't made the effort. Don't give up on your intuition and perception. Just realize you haven't yet brought it home to actualization.

Consider how the basic human drives affect you: security, self-respect, honor, passions, social pressure, and possessions. Pay particularly close attention to how you accept responsibility. Let's say that you made a mistake. You want to apologize in a full and forthright manner. Yet you feel like forgetting the whole thing, hiding, running away and saying "it's not my fault."

This is the volcano. We want to be tough, dedicated and powerful -- yet we feel like being marshmallows. Choosing the path of the soul doesn't come naturally. It takes a lot of time and hard work.

KNOW WHAT YOU KNOW

Don't think that just because you understand something, you are living with it. It is possible to believe one way, and yet act another. It happens to us all the time. You can believe it's important to eat healthy food, yet gorge yourself on French fries and chocolate cake.

Our actions are determined by our level of clarity. If we understand an idea on just a superficial level, then we'll have difficulty sticking to it when the going gets tough.

Next time you go to a funeral, watch carefully. When they remove the body from the chapel, the mourners start to cry. Are they crying because they want to body to stay there?! No. All of a sudden there is a realization of death, that he won't be coming back. At the cemetery, they lower the casket into the ground and the mourners cry again. It's the emotional realization that death is final now.

Until you align your feelings with reality, you are in dreamland. Growth begins in the mind, but your heart has to buy into everything your mind discovers. Only then will you integrate these ideas into day-to-day life.

A lot of people believe in God. There are very few people who live with God. Does that make sense? You have to assimilate something that you've accepted as true. It has to become part of you.

FIVE-FINGER CLARITY

You've got to know yourself cold, just like you know your hand has five fingers. How do you know you are on the right path? How do you know you're not making a mistake right now?

To develop this clarity, articulate the important principles that guide your life. For example, in Judaism we say that love is an obligation. Is this reasonable? Work the issue through with yourself:

"Ridiculous. You can't obligate me to love."
"But if I have children, will I love them?"
"Of course I'm going to love my kids!"
"How do I know? I don't know what kind of kids I'm going to have. Maybe they'll be brats and I won't love them."
"I will. I'm obligated to love my children."

Do you see the contradiction? On an intuitive level, you know that love is an obligation. But the concept is not so clear that you can articulate it.

Take your time. Sort out the basic aspects of living. Ask yourself important questions about life's global and spiritual issues.

--?What is the meaning of existence?
--?What's good about living?
--?How do I feel about humanity?
--?What is the afterlife?
--?How do I understand good versus evil?
--?Do I have free will? How do I activate it?
--?What makes me sad? Is it okay to be sad?
--?How do I feel about God?
--?Am I proud to be a Jew?
--?How do I understand the Holocaust?

Some of these topics may be unpleasant to think about. If so, why is it unpleasant? Track it down.

Don't just use slogans to parrot things that you heard. Know why you are doing what you are doing. Otherwise, it's just society talking. You may have adopted part of society without analyzing its validity. Check it out.

Work through all the issues until you have "five-finger clarity." A human being who knows what he wants will get there. By hook or by crook. It's like a homing mechanism on a missile. If you program it right, you will get there.

WHY IS "KNOWING YOURSELF" AN INGREDIENT IN WISDOM?

  • You can know truth if you look honestly into yourself.
  • Emotions are powerful forces of greatness. Know them. Harness them.
  • Identify your problems. It's the beginning of solving them.
  • If you don't get it straight now, you're bound to make some bad mistakes.
  • Don't be afraid of finding out who you really are.
  • Use your free will as a conscious tool for better living.
  • If you're angry or upset, track it down. What's the root?
  • If you're acting illogically, at least acknowledge that to yourself!
  • The key to sanity is letting truth into the body.
  • You can't afford to wait too long to get to know yourself. Because you are the most fascinating person you'll ever meet.

 



kk 2007-04-18 16:22 发表评论
]]>
动态语ahttp://www.shnenglu.com/jacky2019/archive/2007/04/16/22034.htmlkkkkMon, 16 Apr 2007 10:15:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/04/16/22034.htmlhttp://www.shnenglu.com/jacky2019/comments/22034.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/04/16/22034.html#Feedback1http://www.shnenglu.com/jacky2019/comments/commentRss/22034.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/22034.html所谓动态语aQ也叫脚本语aQ就是说一U在执行期间才去发现数据cd的程序设计语aQ主要创Z些需?/strong>l常更新的动态系l?/span>常见的有Python, Lua, Perl, PHP{?/span>

以往Q我们所使用的语aQ比?/span>CQ?/span>C++{等Q都UCؓ静态语a。什么是静态语a呢?是_在用数据之前,我们必须首先定义数据cdQ这些数据类型包?/span>int, float, double{等。就相当于在使用它们之前Q首先要为它们分配好内存I间Q而动态语a刚刚是相反的,它是在得到数据类型之后,再ؓ它分配内存空间?/span>

“脚本语言除了接近口语化的设计外,另加上简化后的语法。(除了内徏的命令外Q通常仅需单的逻辑判断与数D即可胜任)因此用脚本语a制作游戏Q不再是非程序员不可的工作(除了pȝ本n的修订)Q企Mh员也可以很快地进入状态。另外,如果来需要将游戏UL到其他^台时Q比L序与资料的盘栚w节的设计Q利用脚本语a来开发的游戏Q只需要修改系l本w,脚本语言部分本n毋须更动Q相形之下出现问题的Z与范围就~小了很多?/span>



kk 2007-04-16 18:15 发表评论
]]>
名言http://www.shnenglu.com/jacky2019/archive/2007/04/13/21808.htmlkkkkFri, 13 Apr 2007 08:42:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/04/13/21808.htmlhttp://www.shnenglu.com/jacky2019/comments/21808.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/04/13/21808.html#Feedback0http://www.shnenglu.com/jacky2019/comments/commentRss/21808.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/21808.html

kk 2007-04-13 16:42 发表评论
]]>
Intel.VTune.Performance.Analyzer.v8.0.014.ISO下蝲http://www.shnenglu.com/jacky2019/archive/2007/04/13/21797.htmlkkkkFri, 13 Apr 2007 08:07:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/04/13/21797.htmlhttp://www.shnenglu.com/jacky2019/comments/21797.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/04/13/21797.html#Feedback2http://www.shnenglu.com/jacky2019/comments/commentRss/21797.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/21797.htmlhttp://down.gogobox.com.tw/kisser/7ir3
下蝲的时候要安装一个ActiveX插g的?br>

kk 2007-04-13 16:07 发表评论
]]>
Finding crash information using the MAP file 2http://www.shnenglu.com/jacky2019/archive/2007/04/10/21584.htmlkkkkTue, 10 Apr 2007 03:27:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/04/10/21584.htmlhttp://www.shnenglu.com/jacky2019/comments/21584.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/04/10/21584.html#Feedback0http://www.shnenglu.com/jacky2019/comments/commentRss/21584.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/21584.htmlFinding crash information using the MAP file
http://www.shnenglu.com/jacky2019/archive/2007/04/09/21527.html
上文中的关于说明的W?/span>2Ҏ有问题的

偶又试了一ơ,发现lines number可能是有问题的,而且也不是我的那U算法。不q函数名肯定是对?br>
在vckbase中又发现一好文,所以就又脓q来了。不q可惜的是,q是没能解决dll的地址映射问题Q无法track到dll内的信息Q可惜了?br>

?#8220;仅通过崩溃地址扑և源代码的出错?#8221;一文的补充与改q?/strong>

作者:上v伟功通信 roc

下蝲源代?/font>

  M老罗?#8220;仅通过崩溃地址扑և源代码的出错?/font>”(下称"|文")一文后Q感觉该文还是可以学C东西的。不q文中尚存在有些说法不妥Q以及有些操作太J琐的地?。ؓ此,本h在学习了此文后,在多ơ实验实践基上,把该文中的一些内容进行补充与改进Q希望对大家调试E序Q尤其是release版本的程序有帮助 。欢q各位朋友批评指正?br>

一、该Ҏ适用的范?/strong>
  在windowsE序中造成E序崩溃的原因很多,而文中所q的Ҏ仅适用?׃条语句当卛_LE序崩溃。如原文中D的除Cؓ零的崩溃例子。而笔者在实际工作中碰到更多的情况?指针指向一非法地址 Q然后对指针的内容进行了Q读或写的操作。例如:

void Crash1()
{
char * p =(char*)100;
*p=100;
}

  q些原因造成的崩溃,无论是debug版本Q还是release版本的程序,使用该方法都可找到造成崩溃的函数或子程序中的语句行Q具体方法的下面q会补充说明?另外Q实践中另一U常见的造成E序崩溃的原?函数或子E序中局部变量数l越界付|造成函数或子E序q回地址遭覆盖,从而造成函数或子E序q回时崩溃。例?

#include 
void Crash2();
int main(int argc,char* argv[])
{
Crash2();
return 0;
}
void Crash2()
{
char p[1];
strcpy(p,"0123456789");
}

在vc中编译运行此E序的release版本Q会跛_如下的出错提C框?


图一 上面例子q行l果

  q里昄的崩溃地址?0x34333231。这U由前面语句造成的崩溃根源,在后l程序中Ҏ昄出来的情况,昄用该文所q的Ҏ无能ؓ力了。不q在此例中多还有些蛛丝马迹可寻扑ֈ崩溃的原?函数Crash2中的局部数lp只有一个字节大?Q显然拷?0123456789"q个字符串会把超出长度的字符串拷贝到数组p的后面,?(p+1)=''1''Q?(p+2)=''2''Q?(p+3)=''3''Q?(p+4)=4。。。。。。而字W?'1''的ASC码的gؓ0x31Q?'2''?x32Q?'3''?x33Q?'4''?x34。。。。。,׃intel的cpu中int型数据是低字节保存在低地址?Q所以保存字W串''1234''的内存,昄Z?字节的int型数时就?x34333231。显然拷?0123456789"q个字符串时Q?1234"q几个字W把函数Crash2的返回地址l覆?Q从而造成E序崩溃。对于类似的q种造成E序崩溃的错误朋友们q有其他Ҏ排错的话Q欢q一起交讨论?br>

二、设|编译生map文g的方?/strong>
  该文中生map文g的方法是手工d~译参数来生map文g。其实在vc6的IDE中有产生map文g的配|选项的。操作如?先点击菜?Project"->"Settings。。?Q弹出的属性页中选中"Link"?Q确保在"category"中选中"General"Q最后选中"Generate mapfile"的可选项。若要在在map文g中显CLine numbers的信息的?Q还需在project options 中加?mapinfo:lines 。Line numbers信息对于"|文"所用的Ҏ来定位出错源代码行很重要 Q但W者后面会介绍更加好的Ҏ来定位出错代码行Q那U方法不需要Line numbers信息?


图二 讄产生MAP文g


三、定位崩溃语句位|的Ҏ
  "|文"所q的定位Ҏ中,扑ֈ产生崩溃的函C|的Ҏ是正的Q即在map文g列出的每个函数的起始地址中,最q的且不大于崩溃地址的地址即ؓ包含崩溃语句的函数的地址 。但之后的再q一步的定位出错语句行的Ҏ不是最妥当Q因为那U方法前提是Q假讑֟地址的值是 0x00400000 Q以及一般的 PE 文g的代码段都是?0x1000偏移开始的 。虽然这U情况很普遍Q但在vc中还是可以基地址讄为其他数Q比如设|ؓ0x00500000Q这时仍旧套?br>

 崩溃行偏U?= 崩溃地址 - 0x00400000 - 0x1000 

的公式显然无法找到崩溃行偏移?其实上述公式若改?br>

崩溃行偏U?= 崩溃地址 - 崩溃函数l对地址 + 函数相对偏移

卛_通用了。仍?|文"中的例子Z:"|文"中提到的在其崩溃E序的对应map文g中,崩溃函数的编译结果ؓ

0001:00000020 ?Crash@@YAXXZ 00401020 f CrashDemo。obj 

对与上述l果Q在使用我的公式?Q?崩溃函数l对地址"?0401020Q?函数相对偏移?00000020Q?当崩溃地址= 0x0040104aӞ ?崩溃行偏U?= 崩溃地址 - 崩溃函数起始地址+ 函数相对偏移 = 0x0040104a - 0x00401020 + 0x00000020= 0x4aQ结果与"|文"计算l果相同 。但q个公式更通用?br>

四、更好的定位崩溃语句位置的方法?/strong>
  其实除了依靠map文g中的Line numbers信息最l定位出错语句行外,在vc6中我们还可以通过~译E序产生的对应的汇编语句Q二q制码,以及对应c/c++语句Z体的"cod"文g来定位出错语句行 。先介绍一下生这U包含了三种信息?cod"文g的设|方?先点击菜?Project"->"Settings。。?Q弹出的属性页中选中"C/C++"?Q然后在"Category"中选则"Listing Files"Q再?Listing file type"的组合框中选择"AssemblyQMachine codeQ?and source"。接下去再通过一个具体的例子来说明这U方法的具体操作?


图三 讄产生"cod"文g

准备步骤1)产生崩溃的程序如?

01 //****************************************************************
02 //文g名称Qcrash。cpp
03 //作用:    演示通过崩溃地址扑և源代码的出错行新Ҏ
04 //作者:   伟功通信 roc
05 //日期Q?  2005-5-16
06//****************************************************************
07 void Crash1();
08 int main(int argc,char* argv[])
09 {
10 Crash1();
11 return 0;
12 }
13
14 void Crash1()
15 {
16  char * p =(char*)100;
17  *p=100;
18 }

准备步骤2)按本文所q设|生map文g(不需要生Line numbers信息)?br>准备步骤3)按本文所q设|生cod文g?br>准备步骤4)~译。这里以debug版本Z(若是release版本需要将~译选项改ؓ不进行Q何优化的选项Q否则上qC码会因ؓ优化时看作废代码而不被编译,从而看不到崩溃的结?Q编译后产生一?exe"文g Q一?map"文gQ一?cod"文g?
q行此程序,产生如下如下崩溃提示:


囑֛ 上面例子q行l果

排错步骤1)定位崩溃函数。可以查询map文g获得。我的机器编译生的map文g的部分如?

 Crash
Timestamp is 42881a01 (Mon May 16 11:56:49 2005)
Preferred load address is 00400000
Start Length Name Class
0001:00000000 0000ddf1H .text CODE
0001:0000ddf1 0001000fH .textbss CODE
0002:00000000 00001346H .rdata DATA
0002:00001346 00000000H .edata DATA
0003:00000000 00000104H .CRT$XCA DATA
0003:00000104 00000104H .CRT$XCZ DATA
0003:00000208 00000104H .CRT$XIA DATA
0003:0000030c 00000109H .CRT$XIC DATA
0003:00000418 00000104H .CRT$XIZ DATA
0003:0000051c 00000104H .CRT$XPA DATA
0003:00000620 00000104H .CRT$XPX DATA
0003:00000724 00000104H .CRT$XPZ DATA
0003:00000828 00000104H .CRT$XTA DATA
0003:0000092c 00000104H .CRT$XTZ DATA
0003:00000a30 00000b93H .data DATA
0003:000015c4 00001974H .bss DATA
0004:00000000 00000014H .idata$2 DATA
0004:00000014 00000014H .idata$3 DATA
0004:00000028 00000110H .idata$4 DATA
0004:00000138 00000110H .idata$5 DATA
0004:00000248 000004afH .idata$6 DATA
Address Publics by Value Rva+Base Lib:Object
0001:00000020 _main 00401020 f Crash.obj
0001:00000060 ?Crash1@@YAXXZ 00401060 f Crash.obj
0001:000000a0 __chkesp 004010a0 f LIBCD:chkesp.obj
0001:000000e0 _mainCRTStartup 004010e0 f LIBCD:crt0.obj
0001:00000210 __amsg_exit 00401210 f LIBCD:crt0.obj
0001:00000270 __CrtDbgBreak 00401270 f LIBCD:dbgrpt.obj
...

对于崩溃地址0x00401082而言Q小于此地址中最接近的地址(Rva+Base中的地址)?0401060Q其对应的函数名?Crash1@@YAXXZQ由于所有以问号开头的函数名称都是 C++ 修饰的名U?Q?@@YAXXZ"则ؓ区别重蝲函数而加的后~Q所?Crash1@@YAXXZ是我们的源E序中,Crash1() q个函数?br>排错步骤2)定位出错行。打开~译生成?cod"文gQ我机器上生成的文g内容如下:

 TITLE E:\Crash\Crash。cpp
.386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT SEGMENT PARA USE32 PUBLIC ''CODE''
_TEXT ENDS
_DATA SEGMENT DWORD USE32 PUBLIC ''DATA''
_DATA ENDS
CONST SEGMENT DWORD USE32 PUBLIC ''CONST''
CONST ENDS
_BSS SEGMENT DWORD USE32 PUBLIC ''BSS''
_BSS ENDS
$$SYMBOLS SEGMENT BYTE USE32 ''DEBSYM''
$$SYMBOLS ENDS
$$TYPES SEGMENT BYTE USE32 ''DEBTYP''
$$TYPES ENDS
_TLS SEGMENT DWORD USE32 PUBLIC ''TLS''
_TLS ENDS
; COMDAT _main
_TEXT SEGMENT PARA USE32 PUBLIC ''CODE''
_TEXT ENDS
; COMDAT ?Crash1@@YAXXZ
_TEXT SEGMENT PARA USE32 PUBLIC ''CODE''
_TEXT ENDS
FLAT GROUP _DATAQ?CONST, _BSS
ASSUME CS: FLAT, DS: FLAT, SS: FLAT
endif
PUBLIC ?Crash1@@YAXXZ     ; Crash1
PUBLIC _main
EXTRN __chkesp:NEAR
; COMDAT _main
_TEXT SEGMENT
_main PROC NEAR     ; COMDAT
; 9    : {
00000 55   push  ebp
00001 8b ec   mov  ebpQ?esp
00003 83 ec 40  sub  esp, 64   ; 00000040H
00006 53   push  ebx
00007 56   push  esi
00008 57   push  edi
00009 8d 7d c0  lea  edi, DWORD PTR [ebp-64]
0000c b9 10 00 00 00  mov  ecxQ?16   ; 00000010H
00011 b8 cc cc cc cc  mov  eaxQ?-858993460  ; ccccccccH
00016 f3 ab   rep stosd
; 10   :  Crash1();
00018 e8 00 00 00 00  call  ?Crash1@@YAXXZ  ; Crash1
; 11   :  return 0;
0001d 33 c0   xor  eaxQ?eax
; 12   : }
0001f 5f   pop  edi
00020 5e   pop  esi
00021 5b   pop  ebx
00022 83 c4 40  add  esp, 64   ; 00000040H
00025 3b ec   cmp  ebp, esp
00027 e8 00 00 00 00  call  __chkesp
0002c 8b e5   mov  esp, ebp
0002e 5d   pop  ebp
0002f c3   ret  0
_main ENDP
_TEXT ENDS
; COMDAT ?Crash1@@YAXXZ
_TEXT SEGMENT
_p$ = -4
?Crash1@@YAXXZ PROC NEAR    ; Crash1, COMDAT
; 15   : {
00000 55   push  ebp
00001 8b ec   mov  ebp, esp
00003 83 ec 44  sub  esp, 68   ; 00000044H
00006 53   push  ebx
00007 56   push  esi
00008 57   push  edi
00009 8d 7d bc  lea  edi, DWORD PTR [ebp-68]
0000c b9 11 00 00 00  mov  ecx, 17   ; 00000011H
00011 b8 cc cc cc cc  mov  eax, -858993460  ; ccccccccH
00016 f3 ab   rep stosd
; 16   :  char * p =(char*)100;
00018 c7 45 fc 64 00
00 00   mov  DWORD PTR _p$[ebp], 100 ; 00000064H
; 17   :  *p=100;
0001f 8b 45 fc  mov  eax, DWORD PTR _p$[ebp]
00022 c6 00 64  mov  BYTE PTR [eax], 100 ; 00000064H
; 18   : }
00025 5f   pop  edi
00026 5e   pop  esi
00027 5b   pop  ebx
00028 8b e5   mov  esp, ebp
0002a 5d   pop  ebp
0002b c3   ret  0
?Crash1@@YAXXZ ENDP     ; Crash1
_TEXT ENDS
END

其中

?Crash1@@YAXXZ PROC NEAR    ; Crash1, COMDAT

为Crash1汇编代码的v始行。生崩溃的代码便在其后的某个位|。接下去的一行ؓ:

; 15   : {

冒号后的"{"表示源文件中的语句,冒号前的"15"表示该语句在源文件中的行数?q之后显C语句汇编后的偏移地址Q二q制码,汇编代码。如

00000 55   push  ebp

其中"0000"表示相对于函数开始地址后的偏移Q?55"为编译后的机器代码," push ebp"为汇~代码。从"cod"文g中我们可以看出,一?c/c++)语句通常需要编译成数条汇编语句 。此外有些汇~语句太长则会分两行昄?

00018 c7 45 fc 64 00
00 00   mov  DWORD PTR _p$[ebp], 100 ; 00000064H

其中"0018"表示相对偏移Q在debug版本中,q个数据为相对于函数起始地址的偏U?此时每个函数W一条语句相对偏UMؓ0000)Qrelease版本中ؓ相对于代码段W一条语句的偏移(即代码段W一条语句相对偏UMؓ0000Q而以后的每个函数W一条语句相对偏Ud不ؓ0000??c7 45 fc 64 00 00 00 "为编译后的机器代?Q?mov DWORD PTR _p$[ebp]Q?100"为汇~代码, 汇编语言?;"后的内容为注释,所?;00000064H"Q是个注释这里用来说?00转换?6q制时ؓ"00000064H"?br>接下去,我们开始来定位产生崩溃的语句?br>W一步,计算崩溃地址相对于崩溃函数的偏移Q在本例中已l知道了崩溃语句的地址(0x00401082)Q和对应函数的v始地址(0x00401060)Q所以崩溃地址相对函数起始地址的偏Ud很容易计了:

  崩溃偏移地址 = 崩溃语句地址 - 崩溃函数的v始地址 = 0x00401082 - 0x00401060 = 0x22?/pre>

W二步,计算出错的汇~语句在cod文g中的相对偏移。我们可以看到函数Crash1()在cod文g中的相对偏移地址?000Q则

崩溃语句在cod文g中的相对偏移 =  崩溃函数在cod文g中相对偏U?+ 崩溃偏移地址 = 0x0000 + 0x22 = 0x22

W三步,我们看Crash1函数偏移0x22除的代码是什?l果如下

 00022 c6 00 64  mov  BYTE PTR [eax], 100 ; 00000064H

q句汇编语句表示?00q个C存到寄存器eax所指的内存单元中去Q保存空间大ؓ1个字?byte)。程序正是执行这条命令时产生了崩溃,昄q里eax中的Z个非法地址 Q所以程序崩溃了!
W四步,再查看该汇编语句在其前面几行的其对应的源代码Q结果如?

; 17   :  *p=100;

其中17表示该语句位于源文g中第17行,?#8220;*p=100;”q正是源文g中生崩溃的语句?br>x我们仅从崩溃地址查扑և了造成崩溃的源代码语句和该语句所在源文g中的切位置Q甚x扑ֈ了造成崩溃的编译后的确切汇~代?
怎么P是不是感觉更爽啊?


五、小?/strong>

1、新Ҏ同样要注意可以适用的范_即程序由一条语句当卛_L崩溃。另外我不知道除了VC6外,是否q有其他的编译器能够产生cM?cod"文g?br>2、我们可以通过比较 新方法生的debug和releae版本?cod"文gQ查N些仅release版本(或debug版本)有另一个版本没有的bug(或其他性状)。例?|文"中所丄那个用例 Q只要打开release版本?cod"文gQ就明白了ؓ啥debug版本会生崩溃而release版本却没?原来release版本中生崩溃的语句其实Ҏ都没有编?。同h例中的release版本要看到崩溃的效果Q需要将~译选项改ؓZ优化的配|?/p>

kk 2007-04-10 11:27 发表评论
]]>DeinoMPIhttp://www.shnenglu.com/jacky2019/archive/2007/04/10/21578.htmlkkkkTue, 10 Apr 2007 02:57:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/04/10/21578.htmlhttp://www.shnenglu.com/jacky2019/comments/21578.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/04/10/21578.html#Feedback0http://www.shnenglu.com/jacky2019/comments/commentRss/21578.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/21578.htmlDeinoMPI is an implementation of MPI-2 for Microsoft Windows. 

DeinoMPI是微?/span>windows?/span>MPI-2的一个实现?/span>

注:MPI-2?/span>Message Passing Interface, http://www.mpi-forum.org/?/span>What is MPI? MPI is a library of functions and macros which is intended for use in programs that exploit the existence of multiple processors by message-passing. 也就是说Q?/span>MPI是一套规范,定义了一些函数和宏,它被用来在程序中通过消息传递来发挥多处理器的处理能力?/span>

DeinoMPI is an implementation of the MPI-2 standard for parallel computing or more generally it is system level middle-ware for high performance parallel computing on Microsoft Windows systems. It supports Win32 and Win64 machines.

DeinoMPI?/span>MPI-2的一个实玎ͼMPI-2?/span>forq行计算的。更通用地说Q?/span>DeinoMPI?/span>windowspȝ上的一个高性能q行计算的系l?/span>level中间件。它有两个版本,分别?/span>for win32?/span>for win64的?/span>

1) DeinoMPI provides the libraries necessary for software developers to write parallel applications that conform to the MPI-2 standard for parallel computing.  Software developers who wish to develop new parallel applications or wish to add parallel capabilities to existing software would benefit from using DeinoMPI.  The libraries provided support a wide range of C, C++ and Fortran compilers.

2) DeinoMPI also provides a process manager used to start processes on multiple machines in a cluster remotely.  Microsoft Windows does not provide native capability to start user applications on remote machines.  DeinoMPI provides a secure mechanism to do just that.  The primary purpose of the DeinoMPI process manager is to set up the environment and launch processes used in MPI jobs but it is not restricted to this functionality.  It can launch any application remotely on behalf of the user.

The following users will benefit from DeinoMPI: Businesses that develop software and wish to add parallel capabilities to increase the performance of their software.  Research institutions that have parallel software codes that they want to run on their Windows machines.  Universities or other educational institutions that teach courses on parallel computing.  University or research labs that run computationally intensive software and wish to use parallel versions of their software to better utilize their computer resources.  Students or hobbyists that wish to write parallel programs.

 



kk 2007-04-10 10:57 发表评论
]]>
可变参数研究http://www.shnenglu.com/jacky2019/archive/2007/04/10/21577.htmlkkkkTue, 10 Apr 2007 02:38:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/04/10/21577.htmlhttp://www.shnenglu.com/jacky2019/comments/21577.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/04/10/21577.html#Feedback0http://www.shnenglu.com/jacky2019/comments/commentRss/21577.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/21577.html一Q?/span> 何谓可变参数
int printf( const char* format, ...);
q是使用q?/span>C语言的h所再熟悉不q的printf函数原型Q它的参C有固定参数format和可变参敎ͼ?/span>”…”表示Q?/span>. 而我们又可以用各U方式来调用printf,?/span>:
printf("%d",value);
printf("%s",str);
printf("the number is %d ,string is:%s", value, str);
?/span>.实现原理
C 语言用宏来处理这些可变参数。这些宏看v来很复杂Q其实原理挺单,是Ҏ参数入栈的特点从最靠近W一个可变参数的固定参数开始,依次获取每个可变参数 的地址。下面我们来分析q些宏。在VC中的stdarg.h头文件中Q针对不同^台有不同的宏定义Q我们选取X86q_下的宏定义:
typedef char *va_list;
/*?/span>va_list被定义成char*Q这是因为在我们目前所用的PCZQ字W指针类型可以用来存储内存单元地址。而在有的机器?/span>va_list是被定义?/span>void*?/span>*/
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
/*_INTSIZEOF (n)宏是Z考虑那些内存地址需要对齐的pȝQ从宏的名字来应该是?/span>sizeof(int)寚w。一般的sizeof(int)=4Q也是参数在内?/span> 中的地址都ؓ4的倍数。比如,如果sizeof(n)?/span>1Q?/span>4之间Q那?/span>_INTSIZEOF(n)Q?/span>4Q如?/span>sizeof(n)?/span>5Q?/span>8之间Q那?/span> _INTSIZEOF(n)=8?/span>*/
#define va_start(ap,v)( ap = (va_list)&v + _INTSIZEOF(v) )
/*va_start 的定义ؓ &v+_INTSIZEOF(v) ,q里&v是最后一个固定参数的起始地址Q再加上其实际占用大后Q就得到了第一个可变参数的起始内存地址。所以我们运?/span>va_start (ap, v)以后,ap指向W一个可变参数在的内存地址*/
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
/*q个宏做了两个事情,
①用用户输入的类型名对参数地址q行强制cd转换Q得到用h需要的?/span>
②计出本参数的实际大小Q将指针调到本参数的l尾Q也是下一个参数的首地址Q以便后l处理?/span>*/
  #define va_end(ap) ( ap = (va_list)0 )
/*x86 q_定义?/span>ap=(char*)0;?/span>ap不再 指向堆栈,而是?/span>NULL一?/span>.有些直接定义?/span>((void*)0),q样~译器不会ؓva_end产生代码,例如gcc?/span>linux?/span>x86q_是q?/span> 样定义的. 在这里大家要注意一个问?/span>:׃参数的地址用于va_start?/span>,所以参C能声明ؓ寄存器变量或作ؓ函数或数l类?/span>. */

以下再用图来表示:

?/span>VC{绝大多?/span>C~译器中Q默认情况下Q参数进栈的序是由叛_左的Q因此,参数q栈以后的内存模型如下图所C:最后一个固定参数的地址位于W一个可变参C下,q且是连l存储的?/span>
|——————————————————————————|
|最后一个可变参?/span> | ->高内存地址?/span>
|——————————————————————————|
...................
|——————————————————————————|
|W?/span>N个可变参?/span> | ->va_arg(arg_ptr,int)?/span>arg_ptr所指的地方,
| | 即第N个可变参数的地址?/span>
|——————————————?|
………………………….
|——————————————————————————|
|W一个可变参?/span> | ->va_start(arg_ptr,start)?/span>arg_ptr所指的地方
| | 即第一个可变参数的地址
|——————————————?|
|———————————————————————?——|
| |
|最后一个固定参?/span> | -> start的v始地址
|—————————————?—| .................
|—————————————————————————?|
| |
|——————————————?|-> 低内存地址?/span>

?/span>.printf研究

下面是一个简单的printf函数的实玎ͼ参考了中的156늚例子Q读者可以结合书上的代码与本文参照?/span>
#include "stdio.h"
#include "stdlib.h"
void myprintf(char* fmt, ...) //一个简单的cM?/span>printf的实玎ͼ//参数必须都是int cd
{
char* pArg=NULL; //{h于原来的va_list
char c;

pArg = (char*) &fmt; //注意不要写成p = fmt !!因ؓq里要对//参数取址Q而不是取?/span>
pArg += sizeof(fmt); //{h于原来的va_start

do
{
c =*fmt;
if (c != '%')
{
putchar(c); //照原栯出字W?/span>
}
else
{
//按格式字W输出数?/span>
switch(*++fmt)
{
case 'd':
printf("%d",*((int*)pArg));
break;
case 'x':
printf("%#x",*((int*)pArg));
break;
default:
break;
}
pArg += sizeof(int); //{h于原来的va_arg
}
++fmt;
}while (*fmt != '\0');
pArg = NULL; //{h?/span>va_end
return;
}
int main(int argc, char* argv[])
{
int i = 1234;
int j = 5678;

myprintf("the first test:i=%d",i,j);
myprintf("the secend test:i=%d; %x;j=%d;",i,0xabcd,j);
system("pause");
return 0;
}
?/span>intel+win2k+vc6的机器执行结果如下:
the first test:i=1234
the secend test:i=1234; 0xabcd;j=5678;

?/span>.应用
求最大?/span>:
#include //不定数目参数需要的?/span>
int max(int n,int num,...)
{
va_list x;//说明变量x
va_start(x,num);//x被初始化为指?/span>num后的W一个参?/span>
int m=num;
for(int i=1;i {
//变?/span>x所指向?/span>intcd的Dl?/span>y,同时?/span>x指向下一个参?/span>
int y=va_arg(x,int);
if(y>m)m=y;
}
va_end(x);//清除变量x
return m;
}
main()
{
printf("%d,%d",max(3,5,56),max(6,0,4,32,45,533));
}

 

本文转蝲自网上,本来是要注明出处的,l果别h也都是{载的Q呵c不q此文讲的很不错Q很清楚Q特别是把可变参数实现的那几个宏Q偶也是冲着q几个宏ȝ?/span>

#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
q个宏,一开始我是想不明白Q不知道是老了Q还是笨了,或者是生锈了。想了好一会还是没搞明白,不过看了一下本文的分析Q一下子明白了Q那是相当的恍然大悟啊?/span>

#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

q个宏,一开始也是没有明白。多看了好几遍才发现了奥U所在啊Qؓ什么要加一个,然后再减一个呢Q因为第一个加直接加到ap上去了,而后一个减只是减了一下括号内的|也就是当前g?/span>

宏真是厉宛_Q或者说它应用真q!q不让我想起以前看q的宏,怎么判断?/span>winq是linuxq_的,怎么判断?/span>32位的q是64位的。宏是一门学问啊?/span>

本文的另一大优ҎQ有非常单的例子Q看了就懂。恩。看了保你׃用了。不q这q头指针也是个好东西啊,需要什么,传个指针是传了一切想要的东西啊,只要让指针指向你需要的东西Q可以是L多的参数Q不q这样子的话Q具体到哪个参数l束p我们自己来定了,不像q里Q所有的参数都已l压栈了Q编译器可以帮我们决定具体有多少个参敎ͼC么时候结束)?/span>

Have fun.



kk 2007-04-10 10:38 发表评论
]]>
Rational Rose 2003下蝲地址http://www.shnenglu.com/jacky2019/archive/2007/04/10/21573.htmlkkkkTue, 10 Apr 2007 01:22:00 GMThttp://www.shnenglu.com/jacky2019/archive/2007/04/10/21573.htmlhttp://www.shnenglu.com/jacky2019/comments/21573.htmlhttp://www.shnenglu.com/jacky2019/archive/2007/04/10/21573.html#Feedback16http://www.shnenglu.com/jacky2019/comments/commentRss/21573.htmlhttp://www.shnenglu.com/jacky2019/services/trackbacks/21573.htmlhttp://www.21php.com/Rational Rose 2003.rar

昨晚下的Q速度100K左右

kk 2007-04-10 09:22 发表评论
]]>
AVһȾþ| þۺϹapp| þþþAVר| þþþëƬ| ۲ӰԺþþƷ| ŷպþþƷ| ˾Ʒþö| ɫ8ŷ˾þۺϵ| þþһƷ99þþƷ66| 91ƷۺϾþ㽶| þþƷѹۿ| þþƷ69Ʒ| Ʒþþþþþ˿ | һaƬþëƬ| þþþAVվ| þ96Ʒþþ| 99þþƷѿһ | ҹ޾þþþþþþ| Ʒþþþþù| þһ| þþþþƷ66| 㽶þþþ| 91ɫۺϾþ| Ʒþþþù3d| ݺɫۺϾþȥ| þԭƷ| 99ȳ˾ƷȾþ| ҹƷþþþ9999| ƷһþþƷ| þ͵wcŮ| ھƷžžþþƷ| һ97ձ˾þۺӰԺ| Ʒ99þþþ | þüۺɫۺϰҲȥ| ɫۺϾþ| ޹˾þþƷ99 | žžþȻ㽶ͼƬ| 97þù¶Ʒ| þþþþþƵ| þˬˬAV| ۺϾþùһ鶹|