??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲欧美日韩中文久久,99re这里只有精品热久久,久久久久人妻精品一区三寸蜜桃 http://m.shnenglu.com/tdweng/category/14699.htmlzh-cnWed, 26 Jun 2013 14:40:43 GMTWed, 26 Jun 2013 14:40:43 GMT60Datatype misalignment http://m.shnenglu.com/tdweng/articles/145076.html心羽心羽Tue, 26 Apr 2011 11:26:00 GMThttp://m.shnenglu.com/tdweng/articles/145076.htmlhttp://m.shnenglu.com/tdweng/comments/145076.htmlhttp://m.shnenglu.com/tdweng/articles/145076.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/145076.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/145076.htmlhttp://blog.csdn.net/lqk1985/archive/2008/10/23/3129976.aspx

 

对于d数据时Q如|络或文Ӟ要特别注意?/p>

比如

PBYTE pData;

//指向接收到的数据?/p>

int * pi = pData + q次接收到数据流的大?- 4Q?/p>

//指向接收到数据流的最??可能客户端发q来的这个数据流最?位是intQ那样就是对齐好的了。也有可能不是int?/p>

if *pi = 4561321  endparse data;//判断作ؓ(f)数据的l束标志Q最?位的前面可能是全是char的?/p>

 

׃q最?位可能不是intQ那样就有可能不寚wQ这里就?x)出现Datatype misalignment错误。但是我们还是必通过最?位作为结束标志,而只有知道什么时候结束才能用int指针指向最?位才不会(x)出现寚w错误。这样Ş成了一个死循环Q难道没办法解决了么Q?/p>

 

PBYTE pData;

PBYTE * pi = pData + q次接收到数据流的大?- 4Q?/p>

int i;

memcpy(&i, pi, 4);

if i = 4561321  endparse data;

 

q样可以解决用int* pi指向未对齐的int错误了?/p>

q一招对所有碰到Datatype misalignment的数据的讉K应该都有效,是把Datatype misalignment的数据用memcpy拯到对齐的内存来访问?/p>

 

 

 

 

1Q解析数据流时应该时L意。如果需要把一个数据流QBUFFERQ{化成l构q行取|应该把q个l构定义为按字节存取.考虑如下l构Q?/p>

struct a{

char a;
short b;
long c;
};
如果某个数据中包含q样的结构,而且我们要直接将数据的指针转化成该l构的指针,然后直接取结构成员的|我们应该将q个l构定义成按字节讉KQ即其夹在语句
#pragma pack(push,1)//设ؓ(f)1字节寚w
...

#pragma pack(pop)//q原为原来的字节寚w方式
之中。如果我们不q样做,~译器会(x)成员b的地址寚w到short指针的地址Q即在a之后加上一个char?位的成员Q将C寚w到LONGQ即在B之后再加一个char成员。如此一来,成员B和成员C得不到正确的g?/p>

 

 

pragma pack 只作用于l构的定义,而不是分配内存空间。把一个结构定义ؓ(f)pack1后,q个l构在程序中׃直是1了?/p>

上面q个例子是客L(fng)发?个连l的数据不是发送结构体Q服务端接收l构体?/p>

 

如果客户端也发送结构体Q服务端也接收结构体׃需要这样了。但是前提是双方的对齐方式一致。所以在客户端发送前也要?pragma pack()一下,服务端也?pragma pack()一下?/p>

 

最好还是客L(fng)也单个数据发送,服务端也单个数据接收?/p>

 

如果我们定义一个普通的l构用来存放一些数据,则不用定义成按字节存取,~译器会(x)加上一些占位成员,但ƈ不会(x)影响E序的运行。从q个意义上讲Q在ARM中,结构成员定义成CHAR和SHORT来节U内存是没有意义的?/p>

一个典型的例子文件系l的驱动E序Q文件是以一些已l定义好的结构存攑֜存储介质上的Q它们被dC个BUFFER中,而具体取某个文g、目录结构时Q我们会(x)地址转化成结构而读取其中的倹{?/p>


2Q访问外设时?br>例如Q磁盘驱动通常?6BIT的方式存取数据,xơ存取两个字节,q样p求传l它的BUFFER是双字节寚w的,驱动E序应该至上层传来的指针做出正确的处理以保证数据的正性?/p>


3.有时Q我们没有将数据指针{化ؓ(f)l构指针取|但如果我们读取的是双字节或者是四字节的数据Q同样需要注意对齐的问题Q例如,如果从一个BUFFER的偏U?0处读取一个四字节|则实际得到的值是偏移8处的
地址上的DWORD倹{?/p>

 

本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/lqk1985/archive/2008/10/23/3129842.aspx



心羽 2011-04-26 19:26 发表评论
]]>
C++关键字:(x)mutable、volatile、explicit以及(qing)__based http://m.shnenglu.com/tdweng/articles/140928.html心羽心羽Tue, 01 Mar 2011 09:32:00 GMThttp://m.shnenglu.com/tdweng/articles/140928.htmlhttp://m.shnenglu.com/tdweng/comments/140928.htmlhttp://m.shnenglu.com/tdweng/articles/140928.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/140928.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/140928.html阅读全文

心羽 2011-03-01 17:32 发表评论
]]>
UM操作http://m.shnenglu.com/tdweng/articles/139160.html心羽心羽Sun, 23 Jan 2011 06:53:00 GMThttp://m.shnenglu.com/tdweng/articles/139160.htmlhttp://m.shnenglu.com/tdweng/comments/139160.htmlhttp://m.shnenglu.com/tdweng/articles/139160.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/139160.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/139160.html

最q笔者一直在做JPEG的解码工作,发现用完全用哈夫曼?wi)进行解码比较费Ӟ而用表l构存储~码和值的对应关系比较快捷Q但是也存在比较隑֤理的地方Q比如解码工作通常是以位ؓ(f)单位的操作,q里必然?x)涉及(qing)到UM操作Q而笔者之前对位的操作很少Q经验很Ơ缺Q经q这ơ历l终于发C一个自己曾l忽视的东西Q那是C/C++中的UM操作Ҏ(gu)出错的情c(din)?/p>

1、什么样的数据类型可以直接移?/strong>

char、short、int、long、unsigned char、unsigned short、unsigned int、unsigned long都可以进行移位操作,而double、float、bool、long double则不可以q行UM操作?/p>

2、有W号数据cd的移位操?/strong>

对于char、short、int、longq些有符L(fng)数据cdQ?/p>

  • 对负数进行左U:(x)W号位始lؓ(f)1Q其他位左移
  • Ҏ(gu)数进行左U:(x)所有位左移Q即 <<Q可能会(x)变成负数
  • 对负数进行右U:(x)取绝对|然后右移Q再取相反数
  • Ҏ(gu)数进行右U:(x)所有位右移Q即 >>

3、无W号数据cd的移位操?/strong>

对于unsigned char、unsigned short、unsigned int、unsigned longq些无符h据类型:(x)

没有Ҏ(gu)要说明的Q?lt;< ?>> 操作W就O(jin)K?/p>

l束?/p>

8086 中存在逻辑UM、算术移位,而C\C++中的UMg既不是逻辑UMQ也不是术UM?/p>

比如-1Q我们若对它右移1位,C的结果仍旧是-1Q事实上无论右移多少位始l是-1Q逻辑UM得到的结果(8位表C)应该?128Q所以这点要注意

例子Q?br>1.?13800138000  转ؓ(f)  91 68 31 08 10 83 00 F0  //91? 68国家?不够位长以F?/strong>

unsigned char *tt = new unsigned char[12];
        strcpy((char*)tt,"13800138000");
        tt[11] = 0xFF;
        unsigned char *ss = new unsigned char[6];
        cout << (tt[11]<<4) << endl;
        memset(ss,0xFF,6);
        int k=0;
        for(int i=0; i<12; i=i+2)
        {
                ss[k++] = (tt[i+1]<<4)+(tt[i]&0x0F);
        }
2. ?整Ş 转ؓ(f) 3位字节型16q制Q如?整型 888 转ؓ(f) 16q制  00 03 78(Debug下有效,Release下无?
   char param[4] = {0};
    int iParamLen = 888;
    param[0] = iParamLen >> 16;
    param[1] = ((iParamLen >> 8) << 32) >> 32;
    param[2] = (iParamLen << 32) >> 32;

反之

    char param[4] = {0x00,0x03,0x78};
    int ii1 = 0;
    ii1 = param[0];
    ii1 =ii1 << 8;
    ii1 = ii1 | param[1];
    ii1 =ii1 << 8;
    ii1 = ii1 | param[2];


心羽 2011-01-23 14:53 发表评论
]]>
BCD码、十六进制与十进制互?/title><link>http://m.shnenglu.com/tdweng/articles/139022.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Fri, 21 Jan 2011 06:04:00 GMT</pubDate><guid>http://m.shnenglu.com/tdweng/articles/139022.html</guid><wfw:comment>http://m.shnenglu.com/tdweng/comments/139022.html</wfw:comment><comments>http://m.shnenglu.com/tdweng/articles/139022.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.shnenglu.com/tdweng/comments/commentRss/139022.html</wfw:commentRss><trackback:ping>http://m.shnenglu.com/tdweng/services/trackbacks/139022.html</trackback:ping><description><![CDATA[<p><span onmouseup=NewHighlight(event) class=wenzhang_con id=articlecontent style="WIDTH: 740px"> <div>?font style="BACKGROUND-COLOR: #ffff00">做嵌入式软g的设计中Q经怼(x)遇到十六q制、BCD码与十进制之间的转换Q最q做M1卡的应用中,涉及(qing)了大量的十六q制、BCD码与十进制之间的转换。笔者通过对BCD码、十六进?权的理解Q轻杄实现了他们之间的互换?/font></div> <div><font style="BACKGROUND-COLOR: #ffff00">#include <stdio.h> <br>#include <string.h</font>> </div> <div>///////////////////////////////////////////////////// <br>// <br>//功能Q二q制取反 <br>// <br>//输入Qconst unsigned char *src  二进制数?<br>//      int length                待{换的二进制数据长?<br>// <br>//输出Qunsigned char *dst        取反后的二进制数?<br>// <br>//q回Q?    success <br>// <br>////////////////////////////////////////////////////// <br>int convert(unsigned char *dst, const unsigned char *src, int length) <br>{ <br>        int i; </div> <div>        for(i=0; i<length; i++) <br>        { <br>                dst[i] = src[i]^0xFF; <br>        } <br>        return 0; <br>} </div> <div>////////////////////////////////////////////////////////// <br>// <br>//功能Q十六进制{为十q制 <br>// <br>//输入Qconst unsigned char *hex         待{换的十六q制数据 <br>//      int length                       十六q制数据长度 <br>// <br>//输出Q?<br>// <br>//q回Qint  rslt                        转换后的十进制数?<br>// <br>//思\Q十六进制每个字W位所表示的十q制数的范围? ~255Q进制ؓ(f)256 <br>//      左移8?<<8){h(hun)乘以256 <br>// <br>///////////////////////////////////////////////////////// <br>unsigned long HextoDec(const unsigned char *hex, int length) <br>{ <br>    int i; <br>    unsigned long rslt = 0; </div> <div>    for(i=0; i<length; i++) <br>    { <br>        rslt += (unsigned long)(hex[i])<<(8*(length-1-i)); <br>                                                         <br>    } </div> <div>    return rslt; <br>} </div> <div><br>///////////////////////////////////////////////////////// <br>// <br>//功能Q十q制转十六进?<br>// <br>//输入Qint dec                     待{换的十进制数?<br>//      int length                  转换后的十六q制数据长度 <br>// <br>//输出Qunsigned char *hex          转换后的十六q制数据 <br>// <br>//q回Q?    success <br>// <br>//思\Q原理同十六q制转十q制 <br>////////////////////////////////////////////////////////// <br>int DectoHex(int dec, unsigned char *hex, int length) <br>{ <br>    int i; </div> <div>    for(i=length-1; i>=0; i--) <br>    { <br>        hex[i] = (dec%256)&0xFF; <br>        dec /= 256; <br>    } </div> <div>    return 0; <br>} </div> <div>///////////////////////////////////////////////////////// <br>// <br>//功能Q求?<br>// <br>//输入Qint base                    q制基数 <br>//      int times                   权?<br>// <br>//输出Q?<br>// <br>//q回Qunsigned long               当前数据位的?<br>// <br>////////////////////////////////////////////////////////// <br>unsigned long power(int base, int times) <br>{ <br>    int i; <br>    unsigned long rslt = 1; </div> <div>    for(i=0; i<times; i++) <br>        rslt *= base; </div> <div>    return rslt; <br>} </div> <div>///////////////////////////////////////////////////////// <br>// <br>//功能QBCD?0q制 <br>// <br>//输入Qconst unsigned char *bcd     待{换的BCD?<br>//      int length                   BCD码数据长?<br>// <br>//输出Q?<br>// <br>//q回Qunsigned long               当前数据位的?<br>// <br>//思\Q压~BCD码一个字W所表示的十q制数据范围? ~ 99,q制?00 <br>//      先求每个字符所表示的十q制|然后乘以?<br>////////////////////////////////////////////////////////// <br>unsigned long  BCDtoDec(const unsigned char *bcd, int length) <br>{ <br>     int i, tmp; <br>     unsigned long dec = 0; </div> <div>     for(i=0; i<length; i++) <br>     { <br>        tmp = ((bcd[i]>>4)&0x0F)*10 + (bcd[i]&0x0F);    <br>        dec += tmp * power(100, length-1-i);           <br>     } </div> <div>     return dec; <br>} </div> <div>///////////////////////////////////////////////////////// <br>// <br>//功能Q十q制转BCD?<br>// <br>//输入Qint Dec                      待{换的十进制数?<br>//      int length                   BCD码数据长?<br>// <br>//输出Qunsigned char *Bcd           转换后的BCD?<br>// <br>//q回Q?  success <br>// <br>//思\Q原理同BCD码{十进?<br>// <br>////////////////////////////////////////////////////////// <br>int DectoBCD(int Dec, unsigned char *Bcd, int length) <br>{ <br>     int i; <br>     int temp; </div> <div>     for(i=length-1; i>=0; i--) <br>     { <br>         temp = Dec%100; <br>         Bcd[i] = ((temp/10)<<4) + ((temp%10) & 0x0F); <br>         Dec /= 100; <br>     } </div> <div>     return 0; <br>} </div> <div>int main() <br>{ <br>    register int i; <br>    unsigned char tmp_bff[12] = ""; </div> <div>    //十六q制转十q制 <br>    unsigned char HEX[4] = {0x34, 0xFE, 0x3E, 0xFF}; <br>    unsigned long dec_hex = 0; </div> <div>    dec_hex = HextoDec(HEX, 4); <br>     <br>    printf("dec_hex = %d\n", dec_hex); </div> <div>    //十进制{十六q制 <br>    DectoHex(dec_hex, tmp_bff, 4); <br>    for(i=0; i<5; i++) <br>    { <br>        printf("tmp_bff[%d] = 0x%02X\n",i, tmp_bff[i]); <br>    } </div> <div>    //BCD码{十进?<br>    unsigned long dec_bcd = 0; <br>    unsigned char BCD[4] = {0x98, 0x23, 0x45, 0x78}; </div> <div>    dec_bcd = BCDtoDec(BCD, 4); <br>    printf("dec_bcd = %d\n", dec_bcd); </div> <div>    //十进制{BCD?<br>    DectoBCD(dec_bcd, tmp_bff, 4); <br>    for(i=0; i<5; i++) <br>    { <br>        printf("tmp_bff[%d] = 0x%02X\n", i, tmp_bff[i]); <br>    } </div> <div>    getchar(); <br>} </div> </span><br>BCD <p> </p> <p> </p> <div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> BCDToChar(</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000"> unsigned </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">src,unsigned </span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> srcLen, unsigned </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">dest)<br>{<br>    unsigned </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> temp[</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> {</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">};<br>    unsigned </span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> temp2[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> {</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">};<br>    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; i</span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">srcLen; i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)<br>    {<br>       temp2[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> src[i];<br><br>       temp[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> src[i]</span><span style="COLOR: #000000">>></span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">;<br>       temp[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> temp[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">]</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">0x0F</span><span style="COLOR: #000000">;<br>       temp[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> temp[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">]</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">0x30</span><span style="COLOR: #000000">;<br><br>       temp[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> temp2[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">]</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">0x0F</span><span style="COLOR: #000000">;<br>       temp[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> temp[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">]</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">0x30</span><span style="COLOR: #000000">;<br><br>       dest[i</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> temp[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">];<br>       dest[i</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">] </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> temp[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">];<br>    }<br>}</span></div> <img src ="http://m.shnenglu.com/tdweng/aggbug/139022.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.shnenglu.com/tdweng/" target="_blank">心羽</a> 2011-01-21 14:04 <a href="http://m.shnenglu.com/tdweng/articles/139022.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Visual C++~程命名规则 http://m.shnenglu.com/tdweng/articles/138643.html心羽心羽Mon, 17 Jan 2011 02:51:00 GMThttp://m.shnenglu.com/tdweng/articles/138643.htmlhttp://m.shnenglu.com/tdweng/comments/138643.htmlhttp://m.shnenglu.com/tdweng/articles/138643.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/138643.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/138643.html一、程序风|(x)    
    1、严格采用阶梯层ơ组l程序代码:(x)    
    各层ơ羃q的分格采用VC的缺省风|x层次~进?|括号位于下一行。要求相匚w的大括号在同一列,对行则要求再羃q?根{例如:(x)    
    2、提CZ息字W串的位|?/strong>    
    在程序中需要给出的提示字符ԌZ支持多种语言的开发,除了一些给调试用的临时信息外,其他所有的提示信息必须定义在资源中?nbsp;   
    3、对变量的定义,量位于函数的开始位|?/strong>    

二、命名规则:(x)    
    1、变量名的命名规?/strong>    
    ①、变量的命名规则要求?#8220;匈牙利法?#8221;。即开头字母用变量的类型,其余部分用变量的英文意思或其英文意思的~写,量避免用中文的拼音,要求单词的第一个字母应大写?nbsp;   
    卻I(x)     变量?变量cd+变量的英文意思(或羃写)    
    寚w通用的变量,在定义时加入注释说明Q变量定义尽量可能放在函数的开始处?nbsp;   
    见下表:(x)    
    bool(BOOL)     用b开?nbsp;    bIsParent    
    byte(BYTE)     用by开?nbsp;    byFlag    
    short(int)     用n开?nbsp;    nStepCount    
    long(LONG)     用l开?nbsp;    lSum    
    char(CHAR)     用c开?nbsp;    cCount    
    float(FLOAT)     用f开?nbsp;    fAvg    
    double(DOUBLE)     用d开?nbsp;    dDeta    
    void(VOID)     用v开?nbsp;    vVariant    
    unsigned     intQWORDQ?nbsp;    用w开?nbsp;    wCount    
    unsigned     long(DWORD)     用dw开?nbsp;    dwBroad    
    HANDLEQHINSTANCEQ?nbsp;    用h开?nbsp;    hHandle    
    DWORD     用dw开?nbsp;    dwWord    
    LPCSTR(LPCTSTR)     用str开?nbsp;    strString    
    ?l尾的字W串     用sz开?nbsp;    szFileName
    
   
    Ҏ(gu)l出的变量类型要求提出ƈl出命名l技术委员会(x)?nbsp;   
   
    ②、指针变量命名的基本原则为:(x)    
    对一重指针变量的基本原则为:(x)    
    “p”+变量cd前缀+命名    
    如一个float*型应该表CZؓ(f)pfStat    
    对多重指针变量的基本规则为:(x)    
    二重指针Q?nbsp;    “pp”+变量cd前缀+命名    
    三重指针Q?nbsp;    “ppp”+变量cd前缀+命名    
    ......    
    ③、全局变量用g_开?如一个全局的长型变量定义ؓ(f)g_lFailCount,卻I(x)变量?g_+变量cd+变量的英文意思(或羃写)    
    ④、静态变量用s_开?如一个静态的指针变量定义?span style="COLOR: #008000">s_plPerv_Inst,卻I(x)     变量?s_+变量cd+变量的英文意思(或羃写)    
    ⑤、成员变量用m_开?如一个长型成员变量定义ؓ(f)m_lCount;卻I(x)变量?m_+变量cd+变量的英文意思(或羃写)    
    ⑥、对枚DcdQenumQ中的变量,要求用枚丑֏量或其羃写做前缀。ƈ且要求用大写?nbsp;   
    如:(x)enum     cmEMDAYS    
    {    
    EMDAYS_MONDAY;    
    EMDAYS_TUESDAY;    
    ……    
    };
    
    ⑦、对struct、union、class变量的命名要求定义的cd用大写。ƈ要加上前~Q其内部变量的命名规则与变量命名规则一致?nbsp;   
    l构一般用S开?nbsp;   
    如:(x)struct     ScmNPoint    
    {    
    int     nX;//点的X位置    
    int     nY;     //点的Y位置    
    };
    
    联合体一般用U开?nbsp;   
    ?     union     UcmLPoint    
    {    
    long     lX;    
    long     lY;    
    }  
  
    cM般用C开?nbsp;   
    如:(x)    
    class     CcmFPoint    
    {    
    public:    
    float     fPoint;    
    };    
    对一般的l构应该定义为类模板Qؓ(f)以后的扩展性考虑    
    如:(x)    
    template    
    class     CcmTVector3d    
    {    
    public:    
    TYPE     x,y,z;    
    };    
    ⑧、对帔RQ包括错误的~码Q命名,要求帔R名用大写Q常量名用英文表辑օ意思?nbsp;   
    ?span style="COLOR: #008000">Q?define     CM_FILE_NOT_FOUND     CMMAKEHR(0X20B)     其中CM表示cd?nbsp;   
    ⑨、对const     的变量要求在变量的命名规则前加入c_,卻I(x)c_+变量命名规则Q例如:(x)    
    const     char*     c_szFileName;    
    2?nbsp;    函数的命名规范:(x)    
    函数的命名应该尽量用英文表达出函数完成的功能。遵循动宄构的命名法则Q函数名中动词在?q在命名前加入函数的前缀Q函数名的长度不得少?个字母?nbsp;   
    例如Q?nbsp;   
    long     cmGetDeviceCount(……);    
    3、函数参数规范:(x)    
    ①?nbsp;    参数名称的命名参照变量命名规范?nbsp;   
    ②?nbsp;    Z提高E序的运行效率,减少参数占用的堆栈,传递大l构的参敎ͼ一律采用指针或引用方式传递?nbsp;   
    ③?nbsp;    Z便于其他E序员识别某个指针参数是入口参数q是出口参数Q同时便于编译器查错误,应该在入口参数前加入const标志。如Q?nbsp;   
    ……cmCopyString(const     char     *     c_szSource,     char     *     szDest)    
    4、引出函数规范:(x)    
    对于从动态库引出作ؓ(f)二次开发函数公开的函敎ͼZ能与其他函数以及(qing)Windows的函数区分,采用cd前缀+基本命名规则的方法命名。例如:(x)在对动态库中引出的一个图象编辑的函数定义?nbsp;    imgFunctionname(其中img为image~写)?nbsp;   
    现给ZU库的命名前~Q?nbsp;   
    ①?nbsp;    寚w用函数库,采用cm为前~?nbsp;   
    ②?nbsp;    对三l函数库Q采用vr为前~?nbsp;   
    ③?nbsp;    对图象函数库Q采用img为前~?/span>    
    对宏定义Q结果代码用同样的前~?nbsp;   
    5、文件名(包括动态库、组件、控件、工E文件等)的命名规范:(x)    
    文g名的命名要求表达出文件的内容Q要求文件名的长度不得少?个字母,严禁使用象file1,myfile之类的文件名?nbsp;   

三、注释规范:(x)    
    1、函数头的注?/strong>    
    对于函数Q应该从“功能”Q?#8220;参数”Q?#8220;q回?#8221;?#8220;主要思\”?#8220;调用Ҏ(gu)”?#8220;日期”六个斚w用如下格式注释:(x)    
    //E序说明开?nbsp;   
    //================================================================//    
    //     功能Q?nbsp;    从一个String     中删除另一个String?nbsp;   
    //     参数Q?nbsp;    strByDelete,strToDelete    
    //     Q入口)     strByDelete:     被删除的字符Ԍ原来的字W串Q?nbsp;   
    //     Q出口)     strToDelete:     要从上个字符串中删除的字W串?nbsp;   
    //     q回Q?nbsp;    扑ֈq删除返?Q否则返?。(对返回值有错误~码的要//     求列出错误编码)?nbsp;   
    //     主要思\Q本法主要采用循环比较的方法来从strByDelete中找?nbsp;   
    //     与strToDelete相匹配的字符Ԍ对多匚wstrByDelete    
    //     中有多个strToDelete子串Q的情况没有处理。请参阅Q?nbsp;   
    //     书名......    
    //     调用Ҏ(gu)Q?.....    
    //     日期Qv始日期,如:(x)2000/8/21.9:40--2000/8/23.21:45    
    //================================================================//    
    函数?……)    
    //E序说明l束    
    ①?nbsp;    对于某些函数Q其部分参数Z入|而部分参Cؓ(f)传出|所以对参数要详l说明该参数是入口参敎ͼq是出口参数Q对于某些意义不明确的参数还要做详细说明Q例如:(x)以角度作为参数时Q要说明该角度参数是以弧度(PIQ?q是以度为单位),Ҏ(gu)是入口又是出口的变量应该在入口和出口处同时标明。等{?nbsp;   
    ②?nbsp;    函数的注释应该放|在函数的头文g中,在实现文件中的该函数的实现部分应该同时放|该注释?nbsp;   
    ③?nbsp;    在注释中应该详细说明函数的主要实现思\、特别要注明自己的一些想法,如果有必要则应该写明Ҏ(gu)法生的来由。对一些模仿的函数应该注释上函数的出处?nbsp;   
    ④?nbsp;    在注释中详细注明函数的适当调用Ҏ(gu)Q对于返回值的处理Ҏ(gu){。在注释中要调用时的危险斚wQ可能出错的地方?nbsp;   
    ⑤?nbsp;    Ҏ(gu)期的注释要求记录从开始写函数到结束函数的试之间的日期?nbsp;   
    ⑥?nbsp;    对函数注释开始到函数命名之间应该有一l用来标识的Ҏ(gu)字符丌Ӏ?nbsp;   
    如果法比较复杂Q或法中的变量定义与位|有养I则要求对变量的定义进行图解。对难以理解的算法能图解量图解?nbsp;   
    2、变量的注释Q?/strong>    
    对于变量的注释紧跟在变量的后面说明变量的作用。原则上对于每个变量应该注释Q但对于意义非常明显的变量,如:(x)i,j{@环变量可以不注释?nbsp;   
    例如Q?nbsp;    long     lLineCount     //U的Ҏ(gu)?nbsp;   
     3、文件的注释Q?/strong>    
    文g应该在文件开头加入以下注释:(x)    
    /////////////////////////////////////////////////////////////////////    
    //     工程:     文g所在的目名?nbsp;   
    //     作者:(x)**Q修改者:(x)**    
    //     描述:说明文g的功能?nbsp;   
    //     主要函数Q?#8230;………    
    //     版本:     说明文g的版本,完成日期?nbsp;   
    //     修改:     说明Ҏ(gu)件的修改内容、修改原因以?qing)修?gu)期?nbsp;   
    //     参考文献:(x)     ......    
    /////////////////////////////////////////////////////////////////////    
    Z头文件被重复包含要求对头文gq行定义如下:    
    #ifndef     __FILENAME_H__    
    #define     __FILENAME_H__
    
    其中FILENAME为头文g的名字?nbsp;   
       4、其他注释:(x)    
    在函数内我们不需要注释每一行语句。但必须在各功能模块的每一主要部分之前d块注释,注释每一l语句,在@环、流E的各分支等Q尽可能多加以注释?nbsp;   
    其中的@环、条件、选择{位|必L释?nbsp;   
    对于前后序不能颠倒的情况Q徏议在注释中增加序受?nbsp;   
    例如Q?nbsp;   
    在其他顺序执行的E序中,每隔3?行语句,必须加一个注释,注明q一D语句所l成的小模块的作用。对于自q一些比较独特的思想要求在注释中标明?nbsp;   

四、程序健壮性:(x)    
    1、函数的q回D范:(x)    
    对于函数的返回位|,量保持单一性,即一个函数尽量做到只有一个返回位|?单入口单出口)?nbsp;   
    要求大家l一函数的返回|所有的函数的返回值都以~码的方式返回?nbsp;   
    例如~码定义如下Q?nbsp;   
    #define     CM_POINT_IS_NULL     CMMAKEHR(0X200)    
    :    
    :    
    函数实现如下Q?nbsp;   
    long     函数?参数,……)    
    {    
    long     lResult;     //保持错误?nbsp;   
    lResult=CM_OK;
    
    //如果参数有错误则q回错误?nbsp;   
    if(参数==NULL)    
    {    
    lResult=CM_POINT_IS_NULL;    
    goto     END;    
    }    
    ……    
    END:    
    return     lResult;    
    }
    
    2、关于goto的应用:(x)    
    对goto语句的应用,我们要求量用goto语句。对一定要用的地方要求只能向后转移?nbsp;   
    3、资源变量的处理Q资源变量是指消耗系l资源的变量Q:(x)    
    对资源变量一定赋初倹{分配的资源在用完后必须马上释放Qƈ重新赋倹{?nbsp;   
    4、对复杂的条件判断,ZE序的可L,应该量使用括号?nbsp;   
    例:(x)if(((szFileName!=NULL)&&(lCount>=0)))||(bIsRead==TRUE))    
 
五、可UL性:(x)    
    1、高质量的代码要求能够跨q_Q所以我们的代码应该考虑到对不同的^台的支持Q特别是对windows98和windowsnt的支持?nbsp;   
    2、由于C语言的移植性比较好Q所以对法函数要求用C代码Q不能用C++代码?nbsp;   
    3、对不同的硬件与软g的函数要做不同的处理
匈牙利命名法


MFC、句柄、控件及(qing)l构的命名规?  Windowscd   h变量   MFCc?  h变量  
HWND   hWndQ?  CWnd*   pWndQ? 
HDLG   hDlgQ?  CDialog*   pDlgQ? 
HDC   hDCQ?  CDC*   pDCQ? 
HGDIOBJ   hGdiObjQ?  CGdiObject*   pGdiObjQ? 
HPEN   hPenQ?  CPen*   pPenQ? 
HBRUSH   hBrushQ?  CBrush*   pBrushQ? 
HFONT     hFontQ?    CFont*   pFontQ? 
HBITMAP     hBitmapQ?  CBitmap*   pBitmapQ? 
HPALETTE     hPaltteQ?  CPalette*   pPaletteQ? 
HRGN     hRgnQ?  CRgn*   pRgnQ? 
HMENU     hMenuQ?  CMenu*   pMenuQ? 
HWND     hCtlQ?  CState*     pStateQ? 
HWND     hCtlQ?  CButton*   pButtonQ? 
HWND     hCtlQ?  CEdit*   pEditQ? 
HWND     hCtlQ?  CListBox*   pListBoxQ? 
HWND     hCtlQ?  CComboBox*   pComboBoxQ? 
HWND     hCtlQ?  CScrollBar*   pScrollBarQ? 
HSZ     hszStrQ?  CString     pStrQ? 
POINT     ptQ?  CPoint     ptQ? 
SIZE     sizeQ?  CSize     sizeQ? 
RECT     rectQ?  CRect     rectQ? 


一般前~命名规范   前缀   cd   实例  
C   cLl构   CDocumentQCPrintInfo  
m_   成员变量   m_pDocQm_nCustomers  


变量命名规范   前缀   cd   描述   实例  
ch   char   8位字W?  chGrade  
ch     TCHAR   如果_UNICODE定义Q则?6位字W?  chName  
b   BOOL   布尔?  bEnable  
n     int   整型Q其大小依赖于操作系l)   nLength  
n     UINT     无符号|其大依赖于操作pȝQ?  nHeight  
w     WORD     16位无W号?  wPos  
l     LONG     32位有W号整型   lOffset  
dw     DWORD     32位无W号整型     dwRange  
p     *     指针   pDoc  
lp     FAR*     q指?    lpszName  
lpsz     LPSTR     32位字W串指针   lpszName  
lpsz     LPCSTR     32位常量字W串指针   lpszName  
lpsz     LPCTSTR     如果_UNICODE定义Q则?2位常量字W串指针   lpszName  
h     handle     Windows对象句柄   hWnd  
lpfn     callback   指向CALLBACK函数的远指针      


应用E序W号命名规范   前缀   W号cd   实例   范围  
IDR_     不同cd的多个资源共享标?  IDR_MAIINFRAME   1?x6FFF  
IDD_   对话框资?  IDD_SPELL_CHECK     1?x6FFF  
HIDD_   对话框资源的Help上下?  HIDD_SPELL_CHECK     0x20001?x26FF  
IDB_     位图资源   IDB_COMPANY_LOGO     1?x6FFF  
IDC_   光标资源   IDC_PENCIL     1?x6FFF  
IDI_   图标资源   IDI_NOTEPAD     1?x6FFF  
ID_   来自菜单Ҏ(gu)工具栏的命o(h)   ID_TOOLS_SPELLING     0x8000?xDFFF  
HID_   命o(h)Help上下?  HID_TOOLS_SPELLING     0x18000?x1DFFF  
IDP_   消息框提C?  IDP_INVALID_PARTNO     8?xDEEF  
HIDP_   消息框Help上下?  HIDP_INVALID_PARTNO     0x30008?x3DEFF  
IDS_   串资?  IDS_COPYRIGHT     1?x7EEF  
IDC_   对话框内的控?  IDC_RECALC     8?xDEEF  


Microsoft   MFC宏命名规?  名称   cd  
_AFXDLL   唯一的动态连接库QDynamic   Link   LibraryQDLLQ版? 
_ALPHA   仅编译DEC   Alpha处理? 
_DEBUG   包括诊断的调试版? 
_MBCS   ~译多字节字W集  
_UNICODE   在一个应用程序中打开Unicode  
AFXAPI     MFC提供的函? 
CALLBACK   通过指针回调的函?   


库标识符命名?  标识W?  值和含义  
u     ANSIQNQ或UnicodeQUQ? 
d     调试或发行:(x)D   =   调试Q忽略标识符为发行? 


静态库版本命名规范   ?  描述  
NAFXCWD.LIB   调试版本QMFC静态连接库  
NAFXCW.LIB   发行版本QMFC静态连接库  
UAFXCWD.LIB   调试版本Q具有Unicode支持的MFC静态连接库
 
UAFXCW.LIB   发行版本Q具有Unicode支持的MFC静态连接库  


动态连接库命名规范   名称   cd  
_AFXDLL   唯一的动态连接库QDLLQ版?
 
WINAPI     Windows所提供的函? 


Windows.h中新的命名规?  cd   定义描述  
WINAPI   使用在API声明中的FAR   PASCAL位置Q如果正在编写一个具有导出API人口点的DLLQ则可以在自qAPI中用该cd  
CALLBACK   使用在应用程序回叫例E,如窗口和对话框过E中的FAR   PASCAL的位|? 
LPCSTR   与LPSTR相同Q只是LPCSTR用于只读串指针,其定义类|const   char   FAR*Q? 
UINT   可移植的无符h型类型,其大由L环境军_Q对于Windows   NT和W(xu)indows   9x?2位)Q它是unsigned   int的同义词  
LRESULT   H口E序q回值的cd  
LPARAM   声明lParam所使用的类型,lParam是窗口程序的W四个参? 
WPARAM   声明wParam所使用的类型,wParam是窗口程序的W三个参? 
LPVOID   一般指针类型,与(void   *Q相同,可以用来代替LPSTR    



心羽 2011-01-17 10:51 发表评论
]]>
#ifdef __cplusplus 学习(fn) http://m.shnenglu.com/tdweng/articles/137094.html心羽心羽Tue, 21 Dec 2010 01:48:00 GMThttp://m.shnenglu.com/tdweng/articles/137094.htmlhttp://m.shnenglu.com/tdweng/comments/137094.htmlhttp://m.shnenglu.com/tdweng/articles/137094.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/137094.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/137094.html

时常在cpp的代码之中看到这L(fng)代码:

#ifdef __cplusplus

extern "C" {

#endif

//一D代?/p>

#ifdef __cplusplus

}

#endif

  q样的代码到底是什么意思呢Q首先,__cplusplus是cpp中的自定义宏Q那么定义了q个宏的话表C是一Dcpp的代码,也就是说Q上面的代码的含义是:如果q是一Dcpp的代码,那么加入extern "C"{和}处理其中的代?/span>?/p>

  要明白ؓ(f)何用extern "C"Q还得从cpp中对函数的重载处理开始说赗在c++中,Z支持重蝲机制Q在~译生成的汇~码中,要对函数的名字进行一些处理,加入比如函数的返回类型等{?而在C中,只是单的函数名字而已Q不?x)加入其他的信?也就是说:C++和C对生的函数名字的处理是不一L(fng).

  比如下面的一D늮单的函数Q我们看看加入和不加入extern "C"产生的汇~代码都有哪些变?

int f(void)

{

return 1;

}

  在加入extern "C"的时候生的汇编代码?

.file "test.cxx"

.text

.align 2

.globl _f

.def _f; .scl 2; .type 32; .endef

_f:

pushl %ebp

movl %espQ?%ebp

movl $1Q?%eax

popl %ebp

ret

  但是不加入了extern "C"之后

.file "test.cxx"

.text

.align 2

.globl __Z1fv

.def __Z1fv; .scl 2; .type 32; .endef

__Z1fv:

pushl %ebp

movl %espQ?%ebp

movl $1Q?%eax

popl %ebp

ret

  两段汇编代码同样都是使用gcc -S命o(h)产生的,所有的地方都是一L(fng)Q唯独是产生的函数名Q一个是_fQ一个是__Z1fv?/p>

  明白了加入与不加入extern "C"之后对函数名UC生的影响Q我们l我们的讨论:Z么需要用extern "C"呢?C++之父在设计C++之时Q考虑到当时已l存在了大量的C代码Qؓ(f)了支持原来的C代码和已l写好C库,需要在C++中尽可能的支持CQ而extern "C"是其中的一个策略?/p>

  试想q样的情?一个库文g已经用C写好了而且q行得很良好Q这个时候我们需要用这个库文gQ但是我们需要用C++来写q个新的代码。如果这个代码用的是C++的方式链接这个C库文件的话,那么׃(x)出现链接错误.我们来看一D代?首先Q我们用C的处理方式来写一个函敎ͼ也就是说假设q个函数当时是用C写成?

//f1.c

extern "C"

{

void f1()

{

return;

}

}

  ~译命o(h)?gcc -c f1.c -o f1.o 产生了一个叫f1.o的库文g。再写一D代码调用这个f1函数:

// test.cxx

//q个extern表示f1函数在别的地方定义,q样可以通过

//~译Q但是链接的时候还是需?/p>

//链接上原来的库文?

extern void f1();

int main()

{

f1();

return 0;

}

  通过gcc -c test.cxx -o test.o 产生一个叫test.o的文件。然后,我们使用gcc test.o f1.o来链接两个文Ӟ可是出错了,错误的提C是:

test.o(.text + 0x1f):test.cxx: undefine reference to 'f1()'

  也就是说Q在~译test.cxx的时候编译器是用C++的方式来处理f1()函数的,但是实际上链接的库文件却是用C的方式来处理函数的,所以就?x)出现链接过不去的错?因ؓ(f)链接器找不到函数?/p>

  因此Q?span style="COLOR: #ff0000">Z在C++代码中调用用C写成的库文gQ就需要用extern "C"来告诉编译器:q是一个用C写成的库文gQ请用C的方式来链接它们?/span>

  比如Q现在我们有了一个C库文Ӟ它的头文件是f.hQ生的lib文g是f.libQ那么我们如果要在C++中用这个库文gQ我们需要这样写:

extern "C"

{

#include "f.h"

}

  回到上面的问题,如果要改正链接错误,我们需要这样子改写test.cxx:

extern "C"

{

extern void f1();

}

int main()

{

f1();

return 0;

}

  重新~译q且链接可以过M.

ȝ

C和C++对函数的处理方式是不同的.extern "C"是C++能够调用C写作的库文g的一个手D,如果要对~译器提CZ用C的方式来处理函数的话Q那么就要用extern "C"来说?/span>?/p>

1.引言

C++语言的创建初h“a better C”Q但是这q不意味着C++中类似C语言的全局变量和函数所采用的编译和q接方式与C语言完全相同。作ZU欲与C兼容的语aQC++保留了一部分q程 式语a的特点(被世人称?#8220;不彻底地面向对象”Q,因而它可以定义不属于Q何类的全局变量和函数。但是,C++毕竟是一U面向对象的E序设计语言Qؓ(f)了支持函数的重蝲QC++对全局函数的处理方式与C有明昄不同?/p>

2.从标准头文g说v

某企业曾l给出如下的一道面试题Q?/p>

面试?/p>

Z么标准头文g都有cM以下的结构?

    #ifndef __INCvxWorksh

    #define __INCvxWorksh

    #ifdef __cplusplus

    extern "C" {

    #endif

    /*...*/

    #ifdef __cplusplus

    }

    #endif

    #endif /* __INCvxWorksh */

分析

昄Q头文g中的~译?#8220;#ifndef __INCvxWorksh?define __INCvxWorksh?endif” 的作用是防止该头文g被重复引?/span>?/p>

那么

    #ifdef __cplusplus

    extern "C" {

    #endif

   #ifdef __cplusplus

    }

    #endif

的作用又是什么呢Q我们将在下文一一道来?/p>

3.深层揭密extern "C"

extern "C" 包含双重含义Q从字面上即可得刎ͼ(x)首先Q被它修饰的目标?#8220;extern”的;其次Q被它修饰的目标?#8220;C”的。让我们来详l解读这两重含义?/p>

Q?Q?nbsp;       被extern "C"限定的函数或变量是externcd?/span>Q?/p>

extern是C/C++语言中表明函数和全局变量作用范围Q可见性)的关键字Q该关键字告诉编译器Q其声明的函数和变量可以在本模块或其它模块中使用。记住,下列语句Q?/p>

extern int a;

仅仅是一个变量的声明Q其q不是在定义变量aQƈ未ؓ(f)a分配内存I间。变量a在所有模块中作ؓ(f)一U全局变量只能被定义一ơ,否则?x)出现连接错误?/p>

通常Q在模块的头文g中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如,如果模块BƲ引用该模块A中定义的全局变量?函数时只需包含模块A的头文g卛_。这P模块B中调用模块A中的函数Ӟ在编译阶D,模块B虽然找不到该函数Q但是ƈ不会(x)报错Q它?x)在q接阶段中从模块 A~译生成的目标代码中扑ֈ此函数?/p>

与extern对应的关键字是staticQ被它修饰的全局变量和函数只能在本模块中使用。因此,一个函数或变量只可能被本模块用时Q其不可能被extern “C”修饰?/p>

Q?Q?nbsp;       被extern "C"修饰的变量和函数是按照C语言方式~译和连接的Q?/p>

未加extern “C”声明时的~译方式

首先看看C++中对cMC的函数是怎样~译的?/p>

作ؓ(f)一U面向对象的语言QC++支持函数重蝲Q而过E式语言C则不支持。函数被C++~译后在W号库中的名字与C语言的不同。例如,假设某个函数的原型ؓ(f)Q?/p>

void foo( int x, int y );

该函数被C~译器编译后在符号库中的名字?span style="COLOR: #008000">_fooQ?span style="COLOR: #008000">C++~译器则?x)生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机Ӟ生成的新名字UCؓ(f)“mangled name”Q。_foo_int_intq样的名字包含了函数名、函数参数数量及(qing)cd信息QC++是靠这U机制来实现函数重蝲的。例如,在C++中,?数void foo( int x, int y )与void foo( int x, float y )~译生成的符h不相同的Q后者ؓ(f)_foo_int_float?/p>

同样圎ͼC++中的变量除支持局部变量外Q还支持cL员变量和全局变量。用h~写E序的类成员变量可能与全局变量同名Q我们以"."来区分。而本 质上Q编译器在进行编译时Q与函数的处理相|也ؓ(f)cM的变量取了一个独一无二的名字,q个名字与用L(fng)序中同名的全局变量名字不同?/p>

未加extern "C"声明时的q接方式Q?/span>

假设在C++中,模块A的头文g如下Q?/p>

// 模块A头文件 moduleA.h

#ifndef MODULE_A_H

        #define MODULE_A_H

     int foo( int x, int y );

#endif

在模块B中引用该函数Q?/p>

// 模块B实现文g moduleB.cpp

Qi nclude "moduleA.h"

foo(2,3);

实际上,在连接阶D,q接器会(x)从模块A生成的目标文件moduleA.obj中寻找_foo_int_intq样的符P

加extern "C"声明后的~译和连接方式:(x)

加extern "C"声明后,模块A的头文g变ؓ(f)Q?/p>

// 模块A头文件 moduleA.h

#ifndef MODULE_A_H

        #define MODULE_A_H

     extern "C" int foo( int x, int y );

#endif

在模块B的实现文件中仍然调用foo( 2,3 )Q其l果是:(x)

Q?Q模块A~译生成foo的目标代码时Q没有对其名字进行特D处理,采用了C语言的方式;

Q?Q连接器在ؓ(f)模块B的目标代码寻找foo(2,3)调用ӞL的是未经修改的符号名_foo?/p>

如果在模块A中函数声明了foo为extern "C"cdQ而模块B中包含的是extern int foo( int x, int y ) Q则模块B找不到模块A中的函数Q反之亦然?/p>

所以,可以用一句话概括extern “C”q个声明的真实目的(M语言中的M语法Ҏ(gu)的诞生都不是随意而ؓ(f)的,来源于真实世界的需求驱动。我们在思考问题时Q不能只停留在这个语a是怎么做的Q还要问一问它Z么要q么做,动机是什么,q样我们可以更深入地理解许多问题Q:(x)

实现C++与C?qing)其它语a的؜合编E?/p>

明白了C++中extern "C"的设立动机,我们下面来具体分析extern "C"通常的用技巧?/p>

4.extern "C"的惯用法

Q?Q在C++中引用C语言中的函数和变量,在包含C语言头文Ӟ假设为cExample.hQ时Q需q行下列处理Q?/p>

extern "C"

{

Qi nclude "cExample.h"

}

而在C语言的头文g中,对其外部函数只能指定为externcdQC语言中不支持extern "C"声明Q在.c文g中包含了extern "C"时会(x)出现~译语法错误?/p>

W者编写的C++引用C函数例子工程中包含的三个文g的源代码如下Q?/p>

/* c语言头文Ӟ(x)cExample.h */

#ifndef C_EXAMPLE_H

#define C_EXAMPLE_H

extern int add(int x,int y);

#endif

/* c语言实现文gQcExample.c */

Qi nclude "cExample.h"

int add( int x, int y )

{

        return x + y;

}

// c++实现文gQ调用addQcppFile.cpp

extern "C"

{

Qi nclude "cExample.h"

}

int main(int argc, char* argv[])

{

        add(2,3);

        return 0;

}

如果C++调用一个C语言~写?DLLӞ当包?DLL的头文g或声明接口函数时Q应加extern "C" { }?/p>

Q?Q在C中引用C++语言中的函数和变量时QC++的头文g需dextern "C"Q但是在C语言中不能直接引用声明了extern "C"的该头文Ӟ应该仅将C文g中将C++中定义的extern "C"函数声明为externcd?span class=Apple-style-span style="WORD-SPACING: 0px; FONT: medium Simsun; TEXT-TRANSFORM: none; COLOR: #000000; TEXT-INDENT: 0px; WHITE-SPACE: normal; LETTER-SPACING: normal; BORDER-COLLAPSE: separate; orphans: 2; widows: 2">

W者编写的C引用C++函数例子工程中包含的三个文g的源代码如下Q?/p>

//C++头文?cppExample.h

#ifndef CPP_EXAMPLE_H

#define CPP_EXAMPLE_H

extern "C" int add( int x, int y );

#endif

//C++实现文g cppExample.cpp

Qi nclude "cppExample.h"

int add( int x, int y )

{

        return x + y;

}

/* C实现文g cFile.c

/* q样?x)编译出错?x)Qi nclude "cExample.h" */

extern int add( int x, int y );

int main( int argc, char* argv[] )

{

        add( 2, 3 );   

        return 0;

}

 



心羽 2010-12-21 09:48 发表评论
]]>
【{?深入分析C++中char * 和char []的区?/title><link>http://m.shnenglu.com/tdweng/articles/136732.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Fri, 17 Dec 2010 05:59:00 GMT</pubDate><guid>http://m.shnenglu.com/tdweng/articles/136732.html</guid><wfw:comment>http://m.shnenglu.com/tdweng/comments/136732.html</wfw:comment><comments>http://m.shnenglu.com/tdweng/articles/136732.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.shnenglu.com/tdweng/comments/commentRss/136732.html</wfw:commentRss><trackback:ping>http://m.shnenglu.com/tdweng/services/trackbacks/136732.html</trackback:ping><description><![CDATA[<p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS"><span id="7vz71jh" class=Title><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">问题引入Q?br></span></span>在实?fn)过E中发现了一个以前一直默认的错误Q同样char *c = "abc"和char c[]="abc",前者改变其?/span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">容程序是?x)崩溃的Q而后者完全正?br>E序演示Q?br>试环境Devc++<br>代码<br></span><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">q行l果<br>2293628 4199056 abc<br>2293624 2293624 abc<br>2293620 4199056 abc</span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">#include <iostream><br>using namespace std;</span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">main()<br>{<br>char *c1 = "abc";<br>char c2[] = "abc";<br>char *c3 = ( char* )malloc(3);<br>c3 = "abc";<br>printf("%d %d %s\n",&c1,c1,c1);<br>printf("%d %d %s\n",&c2,c2,c2);<br>printf("%d %d %s\n",&c3,c3,c3);<br>getchar();<br>}<br></span></p> <br> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">参考资料:(x)<br>首先要搞清楚~译E序占用的内存的分区形式Q?br>一、预备知?E序的内存分?br>一个由c/C++~译的程序占用的内存分ؓ(f)以下几个部分<br>1、栈区(stackQ?q译器自动分配释放Q存攑և数的参数|局部变量的值等。其操作方式cM?/span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">数据l构中的栈?br>2、堆区(heapQ?一般由E序员分配释放,若程序员不释放,E序l束时可能由O(jin)S回收。注意它与数?/span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">l构中的堆是两回事,分配方式倒是cM于链表,呵呵?br>3、全局区(静态区Q(staticQ?全局变量和静态变量的存储是放在一块的Q初始化的全局变量和静?/span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">变量在一块区域,未初始化的全局变量和未初始化的静态变量在盔R的另一块区域。程序结束后ql?/span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">释放?br>4、文字常量区-帔R字符串就是放在这里的。程序结束后ql释放?br>5、程序代码区<br>q是一个前辈写的,非常详细<br><span id="pppf7r9" class=Code><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">//main.cpp<br>int a=0; //全局初始化区<br>char *p1; //全局未初始化?br>main()<br>{<br>int b;?br>char s[]="abc"; //?br>char *p2; //?br>char *p3="123456"; //123456\0在常量区Qp3在栈上?br>static int c=0Q?//全局Q静态)初始化区<br>p1 = (char*)malloc(10);<br>p2 = (char*)malloc(20); //分配得来?0?0字节的区域就在堆区?br>strcpy(p1,"123456"); //123456\0攑֜帔R区,~译器可能会(x)它与p3所?123456"优化成一?/span></span></span><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">地方?br>}<br>二、堆和栈的理论知?br>2.1甌方式<br>stack:<br>ql自动分配。例如,声明在函C一个局部变量int b;pȝ自动在栈中ؓ(f)b开辟空?br>heap:<br>需要程序员自己甌Qƈ指明大小Q在c中malloc函数<br>如p1=(char*)malloc(10);<br>在C++中用newq算W?br>如p2=(char*)malloc(10);<br>但是注意p1、p2本n是在栈中的?br>2.2<br>甌后系l的响应<br>栈:(x)只要栈的剩余I间大于所甌I间Q系l将为程序提供内存,否则报异常提示栈溢出?br>堆:(x)首先应该知道操作pȝ有一个记录空闲内存地址的链表,当系l收到程序的甌Ӟ<br>?x)遍历该链表Q寻扄一个空间大于所甌I间的堆l点Q然后将该结点从I闲l点链表中删除,q将</span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">该结点的I间分配l程序,另外Q对于大多数pȝQ会(x)在这块内存空间中的首地址处记录本ơ分配的?/span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">,q样Q代码中的delete语句才能正确的释放本内存I间。另外,׃扑ֈ的堆l点的大不一定正</span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">好等于申L(fng)大小Q系l会(x)自动的将多余的那部分重新攑օI闲链表中?br>2.3甌大小的限?br>栈:(x)在Windows?栈是向低地址扩展的数据结构,是一块连l的内存的区域。这句话的意思是栈顶的地</span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">址和栈的最大容量是pȝ预先规定好的Q在WINDOWS下,栈的大小?MQ也有的说是1MQM是一个编?/span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">时就定的常敎ͼQ如果申L(fng)I间过栈的剩余I间Ӟ提Coverflow。因此,能从栈获得的I间</span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">较小?br>堆:(x)堆是向高地址扩展的数据结构,是不q箋的内存区域。这是由于系l是用链表来存储的空闲内存地</span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">址的,自然是不q箋的,而链表的遍历方向是由低地址向高地址。堆的大受限于计算机系l中有效?/span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">虚拟内存。由此可见,堆获得的I间比较灉|Q也比较大?br>2.4甌效率的比较:(x)<br>?ql自动分配,速度较快。但E序员是无法控制的?br>?是由new分配的内存,一般速度比较慢,而且Ҏ(gu)产生内存片,不过用v来最方便.<br>另外Q在WINDOWS下,最好的方式是用Virtual Alloc分配内存Q他不是在堆Q也不是在栈,而是直接在进</span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">E的地址I间中保留一块内存,虽然用v来最不方ѝ但是速度快,也最灉|?br>2.5堆和栈中的存储内?br>栈:(x)在函数调用时Q第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句Q的</span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">地址Q然后是函数的各个参敎ͼ在大多数的C~译器中Q参数是由右往左入栈的Q然后是函数中的局部变</span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">量。注意静态变量是不入栈的?br>当本ơ函数调用结束后Q局部变量先出栈Q然后是参数Q最后栈指针指向最开始存的地址Q也是?/span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">函数中的下一条指令,E序p点l运行?br>堆:(x)一般是在堆的头部用一个字节存攑֠的大。堆中的具体内容q序员安排?br>2.6存取效率的比?br>char s1[]="aaaaaaaaaaaaaaa";<br>char *s2="bbbbbbbbbbbbbbbbb";<br>aaaaaaaaaaa是在q行时刻赋值的Q?br>而bbbbbbbbbbb是在~译时就定的;<br>但是Q在以后的存取中Q在栈上的数l比指针所指向的字W串(例如?快?br>比如Q?br><span id="9fz9v99" class=Code>#include<br>voidmain()<br>{<br>char a=1;<br>char c[]="1234567890";<br>char *p="1234567890";<br>a = c[1];<br>a = p[1];<br>return;<br>}<br></span>对应的汇~代?br>10:a=c[1];<br>004010678A4DF1movcl,byteptr[ebp-0Fh]<br>0040106A884DFCmovbyteptr[ebp-4],cl<br>11:a=p[1];<br>0040106D8B55ECmovedx,dwordptr[ebp-14h]<br>004010708A4201moval,byteptr[edx+1]<br>004010738845FCmovbyteptr[ebp-4],al<br>W一U在d时直接就把字W串中的元素d寄存器cl中,而第二种则要先把指针D到edx中,在根?/span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">edxd字符Q显然慢了?br>2.7结Q?br>堆和栈的区别可以用如下的比喻来看出:(x)<br>使用栈就象我们去饭馆里吃饭,只管点菜Q发出申P、付钱、和吃(使用Q,吃饱了就赎ͼ不必理会(x)</span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">切菜、洗菜等准备工作和洗、刷锅等扫尾工作Q他的好处是快捷Q但是自由度?br>使用堆就象是自己动手做喜Ƣ吃的菜_(d)比较ȝQ但是比较符合自q口味Q而且自由度大?/span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">自我ȝQ?br>char *c1 = "abc";实际上先是在文字帔R区分配了一块内存放"abc",然后在栈上分配一地址lc1q指?/span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">q块地址Q然后改变常?abc"自然?x)崩?/span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">然而char c2[] = "abc",实际上abc分配内存的地方和上者ƈ不一P可以?br>4199056<br>2293624 看出Q完全是两块地方Q推?199056处于帔R区,?293624处于栈区</span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">2293628<br>2293624<br>2293620 q段输出看出三个指针分配的区域ؓ(f)栈区Q而且是从高地址C地址</span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">2293620 4199056 abc 看出~译器将c3优化指向帔R区的"abc"</span></p> <p><br><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">l箋思考:(x)<br>代码Q?br></span><br><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">输出Q?br>2293628 4199056 abc<br>2293624 2293624 abc<br>2293620 4012976 gbc<br>写成注释那样Q后面改动就?x)崩?br>可见strcpy(c3,"abc");abc是另一块地方分配的Q而且可以改变Q和上面的参考文说法有些不一定,</span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">#include <iostream><br>using namespace std;</span></p> <p><span style="FONT-SIZE: 1em; COLOR: #003366; FONT-FAMILY: Comic Sans MS">main()<br>{<br>char *c1 = "abc";<br>char c2[] = "abc";<br>char *c3 = ( char* )malloc(3);<br>// *c3 = "abc" //error<br>strcpy(c3,"abc");<br>c3[0] = 'g';<br>printf("%d %d %s\n",&c1,c1,c1);<br>printf("%d %d %s\n",&c2,c2,c2);<br>printf("%d %d %s\n",&c3,c3,c3);<br>getchar();<br>}</span></p> <img src ="http://m.shnenglu.com/tdweng/aggbug/136732.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.shnenglu.com/tdweng/" target="_blank">心羽</a> 2010-12-17 13:59 <a href="http://m.shnenglu.com/tdweng/articles/136732.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>EVCUL到VCȝhttp://m.shnenglu.com/tdweng/articles/134141.html心羽心羽Sat, 20 Nov 2010 02:42:00 GMThttp://m.shnenglu.com/tdweng/articles/134141.htmlhttp://m.shnenglu.com/tdweng/comments/134141.htmlhttp://m.shnenglu.com/tdweng/articles/134141.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/134141.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/134141.html2.link -->output Entry-point symbol:wWinMainCRTStartup (支持双字?
3.资源可以直接拯?用VC打开eVC的资源文?rc),然后eVC的资源就?x)出现VC
在右?用鼠标拖到VC的资源中可?
4.其他是一些细节问题了.可以用宏判断,是不是eVC的程?如果是怎么处理,不是的话,qVC的处理方?br>#ifdef _WIN32_WCE
#endif


心羽 2010-11-20 10:42 发表评论
]]>
基本数据cdQ字W型Q上Q?http://m.shnenglu.com/tdweng/articles/133122.html心羽心羽Tue, 09 Nov 2010 13:23:00 GMThttp://m.shnenglu.com/tdweng/articles/133122.htmlhttp://m.shnenglu.com/tdweng/comments/133122.htmlhttp://m.shnenglu.com/tdweng/articles/133122.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/133122.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/133122.html阅读全文

心羽 2010-11-09 21:23 发表评论
]]>
_cdecl,_fastcall和_stdcall的区?http://m.shnenglu.com/tdweng/articles/130207.html心羽心羽Sun, 17 Oct 2010 11:37:00 GMThttp://m.shnenglu.com/tdweng/articles/130207.htmlhttp://m.shnenglu.com/tdweng/comments/130207.htmlhttp://m.shnenglu.com/tdweng/articles/130207.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/130207.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/130207.htmlC++ Calling Convention调用U定Q?/span>
__cdecl __fastcall
?/span> __stdcallQ三者都是调用约?/span>(Calling convention)Q它军_以下内容Q?/span>

1)函数参数的压栈顺序,2)p用者还是被调用者把参数弹出栈,3)以及(qing)产生函数修饰名的Ҏ(gu)?/span>

1?/span>__stdcall调用U定Q函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的内存栈,

2?/span>_cdecl?/span>C?/span>CQ+E序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以生的可执行文件大会(x)比调?/span>_stdcall函数的大。函数采用从叛_左的压栈方式。注意:(x)对于可变参数的成员函敎ͼ始终使用__cdecl的{换方式?/span>

3?/span>__fastcall调用U定Q它是通过寄存器来传送参数的Q实际上Q它?/span>ECX?/span>EDX传送前两个双字Q?/span>DWORDQ或更小的参敎ͼ剩下的参C旧自叛_左压栈传送,被调用的函数在返回前清理传送参数的内存栈)?/span>

4?/span>thiscall仅仅应用?/span>"C++"成员函数?/span>this指针存放?/span>CX寄存器,参数从右到左压?/span>thiscall不是关键词,因此不能被程序员指定?/span>

5?/span>naked call采用1-4的调用约定时Q如果必要的话,q入函数时编译器?x)生代码来保?/span>ESIQ?/span>EDIQ?/span>EBXQ?/span>EBP寄存器,退出函数时则生代码恢复这些寄存器的内宏V?/span>naked call不生这L(fng)代码?/span>naked call不是cd修饰W,故必d_declspec共同使用?/span>

调用U定可以通过工程讄Q?/span>Setting...\C/C++ \Code Generation进行选择Q缺省状态ؓ(f)__cdecl?/span>

名字修饰U定Q?/span>

1、修饰名(Decoration name)Q?/span>"C"或?/span>"C++"函数在内部(~译和链接)通过修饰名识?/span>
2
?/span>C~译时函数名修饰U定规则Q?/span>
__stdcall
调用U定在输出函数名前加上一个下划线前缀Q后面加上一?/span>"@"W号和其参数的字节数Q格式ؓ(f)_functionname@number,例如Q?/span>function(int a, int b)Q其修饰名ؓ(f)Q?/span>_function@8
__cdecl调用U定仅在输出函数名前加上一个下划线前缀Q格式ؓ(f)_functionname?/span>
__fastcall
调用U定在输出函数名前加上一?/span>"@"W号Q后面也是一?/span>"@"W号和其参数的字节数Q格式ؓ(f)@functionname@number?/span>

3?/span>C++~译时函数名修饰U定规则Q?/span>
__stdcall
调用U定Q?/span>
1)
、以"?"标识函数名的开始,后跟函数名;
2)
、函数名后面?/span>"@@YG"标识参数表的开始,后跟参数表;
3)
、参数表以代可C:(x)
X--void
Q?/span>
D--char
Q?/span>
E--unsigned char
Q?/span>
F--short
Q?/span>
H--int
Q?/span>
I--unsigned int
Q?/span>
J--long
Q?/span>
K--unsigned long
Q?/span>
M--float
Q?/span>
N--double
Q?/span>
_N--bool
Q?/span>
PA--
表示指针Q后面的代号表明指针cdQ如果相同类型的指针q箋出现Q以"0"代替Q一?/span>"0"代表一ơ重复;
4)
、参数表的第一ؓ(f)该函数的q回值类型,其后依次为参数的数据cd,指针标识在其所指数据类型前Q?/span>
5)
、参数表后以"@Z"标识整个名字的结束,如果该函数无参数Q则?/span>"Z"标识l束?/span>
其格式ؓ(f)"?functionname@@YG*****@Z"?/span>"?functionname@@YG*XZ"Q例?/span>
  int Test1(char *var1,unsigned long)----"?Test1@@YGHPADK@Z"

  void Test2()-----“?Test2@@YGXXZ

__cdecl调用U定Q?/span>
规则同上面的_stdcall调用U定Q只是参数表的开始标识由上面?/span>"@@YG"变ؓ(f)"@@YA"?/span>
__fastcall
调用U定Q?/span>
规则同上面的_stdcall调用U定Q只是参数表的开始标识由上面?/span>"@@YG"变ؓ(f)"@@YI"?/span>
VC++
对函数的省缺声明?/span>"__cedcl",只能被C/C++调用.


注意Q?/span>
1
?/span>_beginthread需?/span>__cdecl的线E函数地址Q?/span>_beginthreadex?/span>CreateThread需?/span>__stdcall的线E函数地址?/span>

2、一?/span>WIN32的函数都?/span>__stdcall。而且?/span>Windef.h中有如下的定义:(x)
 #define CALLBACK __stdcall
 #define WINAPI
  __stdcall

3?/span>extern "C" _declspec(dllexport) int __cdecl Add(int a, int b);
   typedef int (__cdecl*FunPointer)(int a, int b);
  
修饰W的书写序如上?/span>

4?/span>extern "C"的作用:(x)如果Add(int a, int b)是在c语言~译器编译,而在c++文g使用Q则需要在c++文g中声明:(x)extern "C" Add(int a, int b)Q因?/span>c~译器和c++~译器对函数名的解释不一Pc++~译器解释函数名的时候要考虑函数参数Q这h了方便函数重载,而在c语言中不存在函数重蝲的问题)Q?/span>extern "C"Q实质就是告?/span>c++~译器,该函数是c库里面的函数。如果不使用extern "C"则会(x)出现链接错误?/span>
一般象如下使用Q?/span>
#ifdef _cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C extern
#endif

#ifdef _cplusplus
extern "C"{
#endif
 EXTERN_C int func(int a, int b);
#ifdef _cplusplus
}
#endif

5?/span>MFC提供了一些宏Q可以?/span>AFX_EXT_CLASS来代?/span>__declspec(DLLexport)Qƈ修饰cdQ从而导出类Q?/span>AFX_API_EXPORT来修饰函敎ͼAFX_DATA_EXPORT来修饰变?/span>
AFX_CLASS_IMPORT
Q?/span>__declspec(DLLexport)
AFX_API_IMPORT
Q?/span>__declspec(DLLexport)
AFX_DATA_IMPORT
Q?/span>__declspec(DLLexport)
AFX_CLASS_EXPORT
Q?/span>__declspec(DLLexport)
AFX_API_EXPORT
Q?/span>__declspec(DLLexport)
AFX_DATA_EXPORT
Q?/span>__declspec(DLLexport)
AFX_EXT_CLASS
Q?/span>#ifdef _AFXEXT
   AFX_CLASS_EXPORT
        #else
   AFX_CLASS_IMPORT

6?/span>DLLMain负责初始?/span>(Initialization)和结?/span>(Termination)工作Q每当一个新的进E或者该q程的新的线E访?/span>DLLӞ或者访?/span>DLL的每一个进E或者线E不再?/span>DLL或者结束时Q都?x)调?/span>DLLMain。但是,使用TerminateProcess?/span>TerminateThreadl束q程或者线E,不会(x)调用DLLMain?/span>

7、一?/span>DLL在内存中只有一个实?/span>
DLL
E序和调用其输出函数的程序的关系Q?/span>
1)
?/span>DLL与进E、线E之间的关系
DLL
模块被映到调用它的q程的虚拟地址I间?/span>
DLL
使用的内存从调用q程的虚拟地址I间分配Q只能被该进E的U程所讉K?/span>
DLL
的句柄可以被调用q程使用Q调用进E的句柄可以?/span>DLL使用?/span>
DLLDLL
可以有自q数据D,但没有自q堆栈Q用调用进E的栈,与调用它的应用程序相同的堆栈模式?/span>

2)、关于共享数据段
DLL
定义的全局变量可以被调用进E访问;DLL可以讉K调用q程的全局数据。用同一DLL的每一个进E都有自qDLL全局变量实例。如果多个线Eƈ发访问同一变量Q则需要用同步机Ӟ对一?/span>DLL的变量,如果希望每个使用DLL的线E都有自q|则应该用线E局部存?/span>(TLSQ?/span>Thread Local Strorage)?/span>

 Visual C++ Compiler Options可以指定?span>Calling Convention?/span> 3U:(x)
    /Gd /Gr /Gz

    q三个参数决定了Q?span>

    1.函数参数以何U顺序入栈,叛_左还是左到右?span>
    2.在函数运行完后,是调用函数还是被调用函数清理入栈的参数?span>
    3.在编译时函数名字是如何{换的?span>

    下面我们分别详细介绍Q?span>

    1./Gd
        q是~译器默认的转换模式Q对一般函C?/span> C的函数调用{换方?span>__cdeclQ?span>
        但是对于C++ 成员函数和前面修C__stdcall __fastcall的函数除外?span>

    2./Gr
        对于一般函C?span>__fastcall函数调用转换方式Q所有?span>__fastcall的函?span>
        必须要有函数原Ş。但对于C++ 成员函数和前面修C__cdecl __stdcall 的函数除外?span>

    3./Gz
        对于所?/span> C函数使用__stdcall函数调用转换方式Q但对于可变参数?/span> C函数?span>
        ?qing)?span>__cdecl
 __fastcall修饰q的函数?span>C++ 成员函数除外。所有用__stdcall
        修饰的函数必L函数原Ş?span>

        事实上,对于x86pȝQ?span>C++ 成员函数的调用方式有点特别,成员函数的this
        指针攑օECXQ所有函数参C叛_左入栈,被调用的成员函数负责清理入栈?span>
        参数。对于可变参数的成员函数Q始l?span>__cdecl的{换方式?span>

    下面该进入主题,分别讲一下这三种函数调用转换方式有什么区别:(x)

    1.__cdecl
        q是~译器默认的函数调用转换方式Q它可以处理可变参数的函数调用。参?span>
        的入栈顺序是从右向左。在函数q行l束后,p用函数负责清理入栈的参数?span>
        在编译时Q在每个函数前面加上下划U?span>(_)Q没有函数名大小写的转换。即
                  _functionname

    2.__fastcall
        有一些函数调用的参数被放?span>ECXQ?span>EDX中,而其它参C叛_左入栈。被调用
        函数在它?yu)要q回时负责清理入栈的参数。在内嵌汇编语言的时候,需要注?span>
        寄存器的使用Q以免与~译器用的产生冲突。函数名字的转换是:(x)
                  @functionname@number
        没有函数名大写的{换,number表示函数参数的字节数。由于有一些参C
        需要入栈,所以这U{换方式会(x)在一定程度上提高函数调用的速度?span>

    3.__stdcall
      函数参数从右向左入栈Q被调用函数负责入栈参数的清理工作。函数名转换?span>
      式如下:(x)
                _functionname@number

    下面我们亲自写一个程序,看看各种不同的调用在~译后有什么区别,我们的被?span>
    用函数如下:(x)

    int function(int a, int b)
    {
        return a + b;
    }

    void main()
    {
        function(10, 20);
    }

    1.__cdecl

        _function
                 push    ebp
                 mov     ebp, esp
                 mov     eax, [ebp+8]       ;参数1
                 add     eax, [ebp+C]       ;加上参数2
                 pop     ebp
                 retn
        _main
                 push    ebp
                 mov     ebp, esp
                 push    14h                ;参数 2入栈
                 push    0Ah                ;参数 1入栈
                 call    _function          ;调用函数
                 add     esp, 8             ;修正?span>
                 xor     eax, eax
                 pop     ebp
                 retn

    2.__fastcall

        @function@8
                 push    ebp
                 mov     ebp, esp           ;保存栈指?span>
                 sub     esp, 8             ;多了两个局部变?span>
                 mov     [ebp-8], edx       ;保存参数 2
                 mov     [ebp-4], ecx       ;保存参数 1
                 mov     eax, [ebp-4]       ;参数 1
                 add     eax, [ebp-8]       ;加上参数 2
                 mov     esp, ebp           ;修正?span>
                 pop     ebp
                 retn
        _main
                 push    ebp
                 mov     ebp, esp
                 mov     edx, 14h           ;参数 2l?span>EDX
                 mov     ecx, 0Ah           ;参数 1l?span>ECX
                 call    @function@8        ;调用函数
                 xor     eax, eax
                 pop     ebp
                 retn

    3.__stdcall

        _function@8
                 push    ebp
                 mov     ebp, esp
                 mov     eax, [ebp]         ;参数 1
                 add     eax, [ebp+C]       ;加上参数 2
                 pop     ebp
                 retn    8                  ;修复?span>
        _main
                 push    ebp
                 mov     ebp, esp
                 push    14h                ;参数 2入栈
                 push    0Ah                ;参数 1入栈
 
               call    _function@8    ;函数调用
                 xor     eax, eax
                 pop     ebp
                 retn

    可见上述三种Ҏ(gu)各有各的特点Q而且_main必须?span>__cdeclQ一?span>WIN32的函数都?span>
    __stdcall。而且?span>Windef.h中有如下的定义:(x)

    #define CALLBACK __stdcall
    #define WINAPI  __stdcall



心羽 2010-10-17 19:37 发表评论
]]>
【分享】C数组与指针学?fn)笔?http://m.shnenglu.com/tdweng/articles/129721.html心羽心羽Wed, 13 Oct 2010 01:58:00 GMThttp://m.shnenglu.com/tdweng/articles/129721.htmlhttp://m.shnenglu.com/tdweng/comments/129721.htmlhttp://m.shnenglu.com/tdweng/articles/129721.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/129721.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/129721.html文章标题? c数组与指针学?fn)笔?br>【文章作者? evilkis
--------------------------------------------------------------------------------------------------------
1.数组的定?br>int a[5];定义了一个数la,它可以存?个整型数据,注意Q在定义了一个数l时Q编译系l会(x)按照数组cd和数l元素个数来分配一D连l的存储I间来存储数l元素。则数组存放数组a的空间大ؓ(f)5*sizeof(int)= 20字节?br>
2 数组的引?br>当我们引用数l元素时下标?开始,于元素的个敎ͼ且只能逐个引用数组元素Q而不能直接引用整个数l。如Qint a[2]={1,2};int b[2]=a;q句是错误的!原因是引用了整个数组?br>
3数组在内存中的存?br>数组在内存中式按照下标的序来一ơ存攄可以理解为线性存放,多维数组也是按照q个序存放
4 数组的初始化
数组的初始化可以在定义的时候用{}全部赋?nbsp;如int a[2]={1,2};如果把定义和赋值分开那就错了如:(x)int a[2];a[2]={1,2};其中W二句本意是?,2赋值给数组a,但是此时a[2]的意义变了,他不在代表一个数l,而是下标引用数组元素Q即数组a的第1个元素。所以数l初始化的赋值方式只能在数组定义时用,定义之后在赋|只能一个元素一个元素的赋?br>
5 多维数组
多维数组单的如二l数l,他其实可以看成一个特D的一位数l,他的元素是一个一l数l,例如Qint a[2][3]可以看做?个一l数la[0]和a[1]l成?br>好了单的了解了下数组的基本知识,现在我么开始讨Z些常见的问题

数组名是什么?{h(hun)于指针?
数组名是一个地址Q而且是一个不可被修改的常量。这一点类gW号帔RQ数l名q个W号代表了容Uxl的那块内存的首地址Q注意:(x)不是数组名的值是那块内存的首地址Q数l名本n没有地址Q只是代表了那块地址Q他是一个右|而指针是一个左|所以数l名与指针不同。例如:(x)int a[3];虽然数组名a没有地址Q但是对其取地址&a,得到的依然是数组首地址。把数组名想象成一个符号常量即可,xl名没有地址Q只是代表了q个数组的首地址。又因ؓ(f)数组名是个地址帔R所以不能修改它的|即a++Qa--是错误的Q只有两U情冉|l名不表C地址帔R
即sizeofQaQ和&aQ前者表C数l的整个长度Q后者是数组地址Q但q不意味着a有地址,数组名是数组元素的首地址Q不是数l的首地址

一l数l的d公式
如int a[6];
则a[n]的地址?int)a+sizeof(int)*n(当然n<=6),其原理即Q首地址+偏移地址其中a一定要做强制类型{换因为a是有cd的,必须把其转换成整敎ͼsizeof(int)x一个元素的大小
推而广?br>对于TYPE array[m];
则array[n]的地址?(int)array+sizeof(TYPE)*n(n<=m)//做逆向的时候很有用
二维数组的寻址公式
?int a[4][5]
则a[2][3]的地址?(int)a+sizeof(int[5])*2+sizeof(int)*3
                  |           |            |
                  |           |            | 
             数组首地址    行偏U?nbsp;     列偏U?br>卻I(x)先算定在第几行Q在定在第几列最后加上首地址
或者第二种方式Q?br>a[2][3]的地址?(int)a+sizeof(int)*(2*5+3)    
                          |
                          | 
       直接定位元素看跨了多少个元素然后乘以他们的数据cd大小
因ؓ(f)数组a每一行有5个元素故2*5,3是目标行的元素偏U?br>故推而光?br>对于TYPE array[x][y]二维数组
则array[m][n]的地址?(int)a+sizeof(int[y])*m+sizeof(TYPE)*n
或array[m][n]的地址?(int)a+sizeof(TYPE)*(m*y+n)
q些d公式在逆向q程中很有用Q至看到这L(fng)d方式我们应该能想到是个数l,其实把数l在内存中的存放xU性的很好理解这些寻址Ҏ(gu)?br>
实践一下:(x)
        int a[5]={0,1,2,3,4};
        int b;
        b=*((int)a+sizeof(int)*2);
   问b是否能取到a[2]的?
如果你说不能Q恭喜你Q你很理解地址与数值的概念Q如果你说能Q也不能怪你Q下面我们就分析一下地址和数值的关系Q由上面的讲q我们知?(int)a+sizeof(int)*2)q里得到的确实实是a[2]的地址Q然后对地址取内容理所当然取的是a[2]的值啊Q呵呵,初学者可能都?x)这么想Q但是那都是我们一厢情愿所造成的,其实((int)a+sizeof(int)*2)只是一个整敎ͼ不是地址的含义,没有M指向意义Q也是a[2]的地址值等?(int)a+sizeof(int)*2)Q但是ƈ不意味着((int)a+sizeof(int)*2)是地址Q实际上地址本来是一个基本数据类型,也就是说地址是有指向意义有类型这是地址和地址值的区别Q如果没有类型,操作pȝ从这首地址取值根本不知道要取多少字节Q?br>所以我们要加上强制cd转换Q他有cd有指向意义即若改?(int*)((int)a+sizeof(int)*2)卛_取到a[2]的?br>

4 数组名作函数参数
当数l名作函数参数时Q传递的是数l首地址的一份拷贝,虽然数组名不可以自加Q但是Ş参可以这里注意,因ؓ(f)形参是变量,存放的只是数l首地址的一份拷贝?br>
6指针
指针的定义:(x)
通俗的讲Q指针就是一个变量,他存攑֏一个变量的地址Q特D就Ҏ(gu)在它存放的是地址?br>弄清关于指针?个方面的内容Q指针的cd 指针所指向的类?nbsp;指针的?nbsp;指针本n所占的内存?br>如:(x)
1指针的类?br>把指针的名字L剩下的就是指针的cdQ?br>int *p                  //指针的类型ؓ(f) int*
char **p               //指针的类型ؓ(f)char**
int (*p)[5]              //指针得到cd为int(*)[5]
?2位^C里所有指针类型的大小均ؓ(f)4字节
2 指针所指向的类?br>当我们通过指针来访问指针所指向的内存区Ӟ指针的所指向的类型决定了~译器将那块内存里的内容当做什么来看待
把指针的名字和指针声明符*LQ剩下的x针所指向的类?br>int *p           //指针所指向的类型ؓ(f)int
char **p         //指针所指向的类型ؓ(f)int*即p指向一个指?br>int (*p)[5]        //指针所指向的类型ؓ(f)int()[5]
3指针的?br>指针的值指针变量存攄地址|他指向首地址Z的一片内存区Q大ؓ(f)sizeof(指针所指向的类?
4 指针本n所占的内存?br>因ؓ(f)指针也是一个变量,所以指针本w也占内存,?2q_下大ؓ(f)4字节
q算W?amp;?
&a的结果是产生了一个指针,*p的结果是p所指向的东?br>
指针的运?br>指针加减一个整型数据得到的q是一个指针,指针加减一个指针得到的是一个整型数据?br>
关于复杂的指针声?br>指针数组:?nbsp;int *ptr[10],首先它是一个含有是个元素的数组Q其ơ元素类型ؓ(f)int*,卛_素ؓ(f)指针Q?br>数组指针Qint (*p)[10]Q首先他是一个指针,其次他指向一个int[10]的数l?br>如果实在弄؜的话想想牛奶和奶牛的区别,牛奶是奶Q而奶牛是?即中国h说话主语都在后面Q说堆栈Q其实说的是?
函数指针:
int (*p) (int x,int y)因ؓ(f)指针指向函数而函数名的类型ؓ(f)int(int x,int y)Q所以定义的时候相当于 int (int x,int y) (*p)
如果?p两边的括号去掉则int *p(int x,int y)表示函数pq回值是个指?br>9 二维数组与指?br>
int ptr[2][3]={1,2,3,4,5,6};
关于二维数组主要是要搞清楚 数组的指?nbsp;某一行的指针 某一行某一列的指针之间的区?br>单纯的数l名ptr则是数组W?行的指针 Ҏ(gu)向第0行,同理ptr+1指向W?行,q两个均指针Q问题来?nbsp;*(ptr+1)可能有很多h认ؓ(f)它的gؓ(f)4Q即ptr[1][0]的|因ؓ(f)ptr+1是第1行的首地址Q所以对其取内容应该为ptr[1][0]的|实际上是错的因ؓ(f) ptr+1是一个行指针 而我们要取元素的话要使用列指针,所以要做个强制cd转换 ?(ptr+1)为列指针其gptr+1的值相{但意义不同如果不理解请接着?br>例如Qint a[i]
q样数组名加下标的Ş式,被编译器理解?br>*(a+i)
同理Qa[i][j]被理解ؓ(f)Q?br>         *(a[i] + j)
            Q?nbsp;*(*(a + i) + j)  
a+1表示a[1]的地址Qa[1]表示a[1][0]的地址,管他们的值是一L(fng)Q?br>
其实数组与指针ƈ不难Q只要^时多l习(fn)多用久而久之就?x)了。笔记就到这里了写的比较乱,希望对初学者有所帮助Q有不对的地方请指正

心羽 2010-10-13 09:58 发表评论
]]>
函数成员变量http://m.shnenglu.com/tdweng/articles/129094.html心羽心羽Fri, 08 Oct 2010 14:20:00 GMThttp://m.shnenglu.com/tdweng/articles/129094.htmlhttp://m.shnenglu.com/tdweng/comments/129094.htmlhttp://m.shnenglu.com/tdweng/articles/129094.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/129094.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/129094.html 

class base
{
public:
 
base(int i):m_j(i),m_i(m_j)
 
{
  
 }

 
int get_i()
 
{
  
return m_i;
 }

 
int get_j()
 
{
  
return m_j;
 }

protected:
private:
 
int m_i;
 
int m_j;
}
;

int main(int argc, char* argv[])
{
 
base obj(98);
 cout 
<< obj.get_i() << endl
  
<< obj.get_j() << endl;
 
return 0;
}


在带参数的构造函CQ初始化列表的初始化变量序是根据成员变量的声明序来执行的Q因此m_i?x)?br>赋予一个随机|输出?br>-858993460
98
如果在声明变量ؓ(f)
 int m_j;

int m_i;
׃(x)输出正常?
98
98
class A
{
   
const int Size = 0;
}

是错误的Q常量必d构造函数的初始化列表里面初始化
?br>
class A
{
   A()
  
{
  
const int Size = 10;
}

}


心羽 2010-10-08 22:20 发表评论
]]>
static用法ȝhttp://m.shnenglu.com/tdweng/articles/124767.html心羽心羽Thu, 26 Aug 2010 01:07:00 GMThttp://m.shnenglu.com/tdweng/articles/124767.htmlhttp://m.shnenglu.com/tdweng/comments/124767.htmlhttp://m.shnenglu.com/tdweng/articles/124767.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/124767.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/124767.html用static声明的函数和变量结

 static 声明的变量在C语言中有两方面的特征Q?br>  1)、变量会(x)被放在程序的全局存储ZQ这样可以在下一ơ调用的时候还可以保持原来的赋倹{这一Ҏ(gu)它与堆栈变量和堆变量的区别?br>  2)、变量用static告知~译器,自己仅仅在变量的作用范围内可见。这一Ҏ(gu)它与全局变量的区别?br>Tips:
  A.若全局变量仅在单个C文g中访问,则可以将q个变量修改为静态全局变量Q以降低模块间的耦合度;
  B.若全局变量仅由单个函数讉KQ则可以这个变量改函数的静态局部变量,以降低模块间的耦合度;
  C.设计和用访问动态全局变量、静态全局变量、静态局部变量的函数Ӟ需要考虑重入问题Q?br>        D.如果我们需要一个可重入的函敎ͼ那么Q我们一定要避免函数中用static变量(q样的函数被UCؓ(f)Q带“内部存储?#8221;功能的的函数)
        E.函数中必要使用static变量情况:比如当某函数的返回gؓ(f)指针cdӞ则必Lstatic的局部变量的地址作ؓ(f)q回|若ؓ(f)autocdQ则q回为错指针?o:p>

函数前加static使得函数成ؓ(f)静态函数。但此处“static”的含义不是指存储方式Q而是指对函数的作用域仅局限于本文?所以又U内部函?。用内部函数的好处是:(x)不同的h~写不同的函数时Q不用担心自己定义的函数Q是否会(x)与其它文件中的函数同名?o:p>

扩展分析:术语static有着不寻常的历史.起初Q在C中引入关键字static是ؓ(f)了表C退Z个块后仍然存在的局部变量。随后,static在C中有了第二种含义Q用来表CZ能被其它文g讉K的全局变量和函数。ؓ(f)了避免引入新的关键字Q所以仍使用static关键字来表示q第二种含义。最后,C++重用了这个关键字Qƈ赋予它与前面不同的第三种含义Q表C属于一个类而不是属于此cȝM特定对象的变量和函数(与Java中此关键字的含义相同)?o:p>

全局变量、静态全局变量、静态局部变量和局部变量的区别

变量可以分ؓ(f)Q全局变量、静态全局变量、静态局部变量和局部变量?br>          按存储区域分Q全局变量、静态全局变量和静态局部变量都存放在内存的静态存储区域,局部变量存攑֜内存的栈区?br>          按作用域分,全局变量在整个工E文件内都有效;静态全局变量只在定义它的文g内有效;静态局部变量只在定义它的函数内有效Q只是程序仅分配一ơ内存,函数q回后,该变量不?x)消失;局部变量在定义它的函数内有效,但是函数q回后失效?o:p>

全局变量(外部变量)的说明之前再冠以static 构成了静态的全局变量。全局变量本n是静态存储方式, 静态全局变量当然也是静态存储方式?q两者在存储方式上ƈ无不同。这两者的区别虽在于非静态全局变量的作用域是整个源E序Q?当一个源E序由多个源文gl成Ӟ非静态的全局变量在各个源文g中都是有效的?而静态全局变量则限制了其作用域Q?卛_在定义该变量的源文g内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文g内,只能源文件内的函数公用, 因此可以避免在其它源文g中引起错误?

  从以上分析可以看出, 把局部变量改变ؓ(f)静态变量后是改变了它的存储方式x变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的用范围?o:p>

  static函数与普通函C用域不同。仅在本文g。只在当前源文g中用的函数应该说明为内部函?static)Q内部函数应该在当前源文件中说明和定义。对于可在当前源文g以外使用的函敎ͼ应该在一个头文g中说明,要用这些函数的源文件要包含q个头文?o:p>

  static全局变量与普通的全局变量有什么区别:(x)static全局变量只初始化一ơ,防止在其他文件单元中被引?
  static局部变量和普通局部变量有什么区别:(x)static局部变量只被初始化一ơ,下一ơ依据上一ơ结果|
       static函数与普通函数有什么区别:(x)static函数在内存中只有一份,普通函数在每个被调用中l持一份拷?br>       全局变量和静态变量如果没有手工初始化Q则q译器初始化ؓ(f)0。局部变量的g可知?o:p>

 

 

.先来介绍它的W一条也是最重要的一条:(x)隐藏?

当我们同时编译多个文件时Q所有未加static前缀的全局变量和函数都h全局可见性。ؓ(f)理解q句话,我D例来说明。我们要同时~译两个源文Ӟ一个是a.cQ另一个是main.c.

下面是a.c的内容:(x)

 char a = 'A'; // global variable
            void msg()
            {
            printf("Hello\n");
            }
            

下面是main.c的内容:(x)

 int main(void)
            {
            extern char a; // extern variable must be declared before use
            printf("%c ", a);
            (void)msg();
            return 0;
            }
            

E序的运行结果是Q?/p>

A Hello

你可能会(x)问:(x)Z么在a.c中定义的全局变量a和函数msg能在main.c中用?前面说过Q所有未加static前缀的全局变量和函数都h全局可见性,其它的源文g也能讉K。此例中Qa是全局变量Qmsg是函敎ͼq且都没有加static前缀Q因此对于另外的源文件main.c是可见的?/p>

如果加了staticQ就?x)对其它源文仉藏。例如在a和msg的定义前加上staticQmain.cq不到它们了。利用这一Ҏ(gu)可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲H。Static可以用作函数和变量的前缀Q对于函数来Ԍstatic的作用仅限于隐藏Q而对于变量,staticq有下面两个作用?/p>

2.static的第二个作用是保持变量内容的持久?/p>

存储在静态数据区的变量会(x)在程序刚开始运行时完成初始化Q也是唯一的一ơ初始化。共有两U变量存储在静态存储区Q全局变量和static变量Q只不过和全局变量比v来,static可以控制变量的可见范_(d)说到底staticq是用来隐藏的。虽然这U用法不常见Q但我还是D一个例子?/p>
 #include Qstdio.hQ?
            int fun(void){
            static int count = 10; // 事实上此赋D句从来没有执行过
            return count--;
            }
            int count = 1;
            int main(void)
            {
            printf("global\t\tlocal static\n");
            for(; count Q? 10; ++count)
            printf("%d\t\t%d\n", count, fun());
            return 0;
            }

E序的运行结果是Q?br>

global local static
1  10
2   9
3   8
4   7
5   6
6   5
7   4
8   3
9   2
10  1

3.static的第三个作用是默认初始化?.其实全局变量也具备这一属性,因ؓ(f)全局变量也存储在静态数据区?/p>

在静态数据区Q内存中所有的字节默认值都?x00Q某些时候这一特点可以减少E序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都|?Q然后把不是0的几个元素赋倹{如果定义成静态的Q就省去了一开始置0的操作。再比如要把一个字W数l当字符串来用,但又觉得每次在字W数l末֊‘\0’太麻烦。如果把字符串定义成静态的Q就省去了这个麻烦,因ؓ(f)那里本来是‘\0’。不妨做个小实验验证一下?/p>
#include Qstdio.hQ?
            int a;
            int main(void)
            {
            int i;
            static char str[10];
            printf("integer: %d; string: (begin)%s(end)", a, str);
            return 0;
            }
            

E序的运行结果如下integerQ?0Q?stringQ?QbeginQ(endQ?/p>

最后对static的三条作用做一句话ȝ。首先static的最主要功能是隐藏,其次因ؓ(f)static变量存放在静态存储区Q所以它具备持久性和默认?.



心羽 2010-08-26 09:07 发表评论
]]>
零值比?-BOOLQintQfloatQ指针变量与零值比较的if语句http://m.shnenglu.com/tdweng/articles/124762.html心羽心羽Thu, 26 Aug 2010 00:36:00 GMThttp://m.shnenglu.com/tdweng/articles/124762.htmlhttp://m.shnenglu.com/tdweng/comments/124762.htmlhttp://m.shnenglu.com/tdweng/articles/124762.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/124762.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/124762.htmlq是E序员面试的一道常见题Q也是个C++基础问题。若只在大学里看q几本基的编E入门书Q看见这道题可能?x)觉得奇怪,不就是和0比较吗,直接拿出来比是了,其实非也。下文引自google搜烦l果Q出处不详,高手可以无视Q菜菜留下,记得做好W记?br>首先l个提示Q题目中要求的是零值比较,而非?q行比较Q在C++?#8220;零?#8221;的范围可大了,可以?Q?0.0 Q?FALSE或?#8220;I指?#8221;?br>int型变?n ?#8220;零?#8221;比较?if 语句是Q?/strong>

if ( n == 0 )

if ( n != 0 )

如下写法均属不良风格.?br>
if ( n )               // ?x)让?n 是布?yu)(dng)变?br>
if ( !n   )

 BOOL flag ?#8220;零?#8221;比较?if 语句:

?据布?yu)(dng)类型的语义Q零gؓ(f)“?#8221;Q记为FALSEQ,M非零值都?#8220;?#8221;Q记为TRUEQ。TRUE 的值究竟是什么ƈ没有l一的标准。例如Visual C++ TRUE 定义?Q而Visual Basic 则将TRUE 定义?1。所以我们不可以布?yu)(dng)变量直接与TRUE、FALSE 或?? q行比较?br>
标准{案Q?br>
if ( flag )

if ( !flag )

如下写法均属不良风格?br>
if (flag == TRUE)

if (flag == 1 )

if (flag == FALSE)

if (flag == 0)

float x ?#8220;零?#8221;比较?if 语句:
千万要留意,无论是float q是double cd的变量,都有_ֺ限制Q都不可以用“==”?#8220;Q?”与Q何数字比较,应该设法转化?#8220;>=”?#8220;<=”形式?Z么?文章之后有详l的讨论Q可参?

假设点变量的名字ؓ(f)xQ应当将

if (x == 0.0)         // 隐含错误的比?br>
转化?br>
if ((x>=-EPSINON) && (x<=EPSINON))

其中EPSINON 是允许的误差Q即_ֺQ?br>
标准{案CZQ?br>
const float EPSINON = 0.00001;

if ((x >= - EPSINON) && (x <= EPSINON)

如下是错误的写法?br>
if (x == 0.0)

if (x != 0.0) 

char *p ?#8220;零?#8221;比较?if 语句:

标准{案Q?br>
if (p == NULL)

if (p != NULL)

如下写法均属不良风格?br>
if (p == 0)         // Ҏ(gu)让h误解p是整型变?br>
if (p != 0)

if (p)                 // Ҏ(gu)让h误解p是bool型变?br>
if (!p)

?上的不良风格很多都能通过~译Q但是语句ƈ不能很好的表达与零D行比较的逻辑依据。一般的Q如果想?if 语句判断一个变量的真假Q应该直接用ifQvarQ、ifQ!varQ,表明?if 语句的功能ؓ(f)“逻辑”判断Q如果想?if 语句判断一个数值型变量Qshort、int、long{)Q应该用ifQvar==0Q,表明?if 语句是将变量?q行“数?#8221;上的比较Q而检视指针是否ؓ(f)I则适宜用ifQvar==NULLQ,q是一U很好的~程?fn)惯?br>
点型变量ƈ不精,所以不可将float变量?#8220;==”?#8220;Q?”与数字比较,应该设法转化?#8220;>=”?#8220;<=”形式。如果写成if Qx == 0.0Q,则判为错Q得0分。以下给l原因:(x)
点数在内存中的存贮机制和整型数不同Q有舍入误差Q在计算Z用以q似表示L某个实数。具体的_(d)q个实数׃个整数或定点敎ͼ卛_敎ͼ乘以某个基数Q计机中通常?Q的整数ơ幂得到Q这U表C方法类g基数?0的科学记数法?
所以QҎ(gu)在运过成功q算通常伴随着因ؓ(f)无法_表示而进行的q似或舍入。但是这U设计的好处是可以在固定的长度上存储更大范围的数?
例如Q一个指数范围ؓ(f)±4?位十q制点数可以用来表C?3210Q?.321?.0004321Q但是没有够的_ֺ来表C?32.123?3212.3Q必近gؓ(f)432.1?3210Q。当Ӟ实际使用的位数通常q大??
所以QҎ(gu)不能够判断相{,?if(x==0)的这L(fng)~码是不L正确的,我们在判断QҎ(gu)相等Ӟ推荐用范围来定Q若x在某一范围内,我们p为相{,至于范围怎么定义Q要看实际情况而已了,floatQ和double 各有不同
所以const float EPSINON = 0.00001;
if ((x >= - EPSINON) && (x <= EPSINON) q样判断是可取的
至于Z么取0.00001Q可以自己按实际情况定义

再看下面CSDN上的回答

引用
#define   E   1.0E-6  

float   x   ?#8220;零?#8221;比较的if  
-----------------------  

点数是不可以直接比较大的Q因为是非精存储,只能讄一个精度,然后在允许误差内的就认ؓ(f)是相{的Q对点型数比较的时候用==是不对的  

#define   E   0.000001      

fabs((a+b)+c)   -   ((b+a)+c))


心羽 2010-08-26 08:36 发表评论
]]>
C++高效~程忠告 http://m.shnenglu.com/tdweng/articles/124633.html心羽心羽Wed, 25 Aug 2010 02:26:00 GMThttp://m.shnenglu.com/tdweng/articles/124633.htmlhttp://m.shnenglu.com/tdweng/comments/124633.htmlhttp://m.shnenglu.com/tdweng/articles/124633.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/124633.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/124633.html
一?include “filename.h”?include <filename.h>的区?/span>
#include “filename.h”是指~译器将从当前工作目录上开始查找此文g
#include <filename.h>是指~译器将从标准库目录中开始查找此文g

二、头文g的作?/span>
加强安全?br>通过头文件可能方便地调用库功能,而不必关心其实现方式

三? , &修饰W的位置
int *i,j; // better for read
 i = new int(0);
 j = 0;
 int *&y = i; // pointer's reference
对于*?amp;修饰W,Z避免误解Q最好将修饰W紧靠变量名
四、if语句
不要布?yu)(dng)变量与MD行比较,那会(x)很容易出错的?br>整Ş变量必须要有cd相同的D行比?br>点变量最好少比相{,可以通过求差与较?yu)的数比?br>指针变量要和NULLq行比较Q不要和布尔型和整Ş比较

五、const?define的比?/span>
const有数据类型,#define没有数据cd
个别~译器中const可以q行调试Q?define不可以进行调?br>在类中定义常量有两种方式
1?在类在声明常量,但不赋|在构造函数初始化表中q行赋|Q常量和引用cd的成员变量必通过初始化列表来初始化赋|
2?用枚举代替const帔R?br>
六、C++函数中值的传递方?/span>
有三U方式:(x)g?Pass by value)、指针传?Pass by pointer)、引用传?Pass by reference)
void fun(char c) //pass by value
void fun(char *str) //pass by pointer
void fun(char &str) //pass by reference
如果输入参数是以g递的话,最好用引用传递代替,因ؓ(f)引用传递省M临时对象的构造和析构
函数的返回类型不能省略,q没有也要加个void
七、函C中的指针或引用常量不能被q回
Char *func(void)
{
 char str[]=”Hello Word”;
 //q个是不能被q回的,因ؓ(f)str是个指定变量Q不是一般的|函数l束后会(x)被注销?br>//它是存放在栈中,函数l束后被注销?br>//可以改ؓ(f) char *str = "HelloWorld",因ؓ(f)指针存放在全局作用域中Q函数结束后不会(x)被注销
 return str;
}
函数体内的指针变量ƈ不会(x)随着函数的消亡而自动释?br>
八、一个内存拷贝函数的实现?/span>
void *memcpy(void *pvTo,const void *pvFrom,size_t size)

{

 assert((pvTo!=NULL)&&(pvFrom!=NULL));

 byte *pbTo=(byte*)pvTo; //防止地址被改?br>
 byte *pbFrom=(byte*)pvFrom;

 while (size-- >0)

 pbTo++ = pbForm++;

 return pvTo;

}
?ji)、内存的分配方式
分配方式有三U,误住,说不定那天去面试的时候就?x)有人问你这问?br>1?静态存储区Q是在程序编译时已l分配好的,在整个运行期间都存在Q如全局变量、常量。(E序~译后运行时包含code和data两部分,其中data即ؓ(f)静态存储区分配Q程序一开始运行便分配整个data的东东)
2?栈上分配Q函数内的局部变量就是从q分配的Q但分配的内存容易有限?br>3?堆上分配Q也U动态分配,如我们用new,malloc分配内存Q用delete,free来释攄内存?br>
十、内存分配的注意事项
用new或malloc分配内存Ӟ必须要对此指针赋初倹{?br>用delete 或free释放内存后,必须要将指针指向NULL
不能修改指向帔R的指针数?br>十一、内容复制与比较
//数组……
char a[]=”Hello Word!”;
char b[10];
strcpy(b,a);
if (strcmp(a,b)==0)
{}
//指针……
char a[]=”Hello Word!”;
char *p;
p=new char[strlen(a)+1];
strcpy(p,a);
if (strcmp(p,a)==0)
{}

十二、sizeof的问?/span>
C一点,C++无法知道指针所指对象的大小Q指针的大小永远?字节
char a[]=”Hello World!”
char *p=a;
count<<sizeof(a)<<end; //12字节
count<<sizeof(p)<<endl; //4字节
而且Q在函数中,数组参数退化ؓ(f)指针Q所以下面的内容永远输出?
void fun(char a[1000])
{
count<<sizeof(a)<<endl; //输出4而不?000
}

十三、关于指?/span>
1?指针创徏时必被初始?br>2?指针在free 或delete后必ȝ为NULL
3?指针的长度都?字节
4、释攑ֆ存时Q如果是数组指针Q必要释放掉所有的内存Q如
char *p=new char[100];
strcpy(p,”Hello World”);
delete []p; //注意前面的EQ号
p=NULL;
5、数l指针的内容不能过数组指针的最大容易?br>?
char *p=new char[5];
strcpy(p,”Hello World”); //报错 目标Ҏ(gu)不够?br>delete []p; //注意前面的EQ号
p=NULL;
十四、关于malloc/free 和new /delete
malloc/free 是C/C+的内存分配符Qnew /delete是C++的内存分配符?br>注意Qmalloc/free是库函数Qnew/delete是运符
malloc/free不能执行构造函C析构函数Q而new/delete可以
new/delete不能在C上运行,所以malloc/free不能被淘?br>两者都必须要成对?br>C++中可以用_set_new_hander函数来定义内存分配异常的处理


十五、E++的特?/span>
Q?+新增加有重蝲(overload)Q内联(inlineQ,ConstQVirtual四种机制
重蝲和内联:(x)卛_用于全局函数Q也可用于类的成员函敎ͼ
Const和VirtualQ只可用于类的成员函敎ͼ
重蝲Q在同一cMQ函数名相同的函数。由不同的参数决定调用那个函数。函数可要不可要Virtual关键字。和全局函数同名的函C叫重载。如果在cM调用同名的全局函数Q必ȝ全局引用W号::引用?br>覆盖是指zcd数覆盖基cd敎ͼ(x)函数名相同;参数相同Q基cd数必LVirtual关键字;不同的范?zcd基类)?br>隐藏是指zcd蔽了基类的同名函数相?br>1?函数名相同,但参C同,此时不论基类有无Virtual关键字,基类函数被隐藏?br>2?函数名相同,参数也相同,但基cLVirtual关键?有就是覆?Q基cd数将被隐藏?br>内联Qinline关键字必M定义体放在一P而不是单单放在声明中?br>ConstQconst是constant的羃写,“恒定不变”的意思。被const修饰的东襉K受到强制保护Q可以预防意外的变动Q能提高E序的健壮性?br>1?参数做输入用的指针型参数Q加上const可防止被意外改动?br>2?按值引用的用户cd做输入参数时Q最好将按g递的改ؓ(f)引用传递,q加上const关键字,目的是ؓ(f)了提高效率。数据类型ؓ(f)内部cd的就没必要做qg事情Q如Q?br>void Func(A a) 改ؓ(f)void Func(const A &a)?br>而void func(int a)没必要Ҏ(gu)void func(const int &a);
3?l返回gؓ(f)指针cd的函数加上constQ会(x)使函数返回g能被修改Q赋l的变量也只能是const型变量。如Q函数const char*GetString(void); char *str=GetString()会(x)出错。而const char *str=GetString()是正确的?br>4?Const成员函数是指此函C内只能调用Const成员变量Q提高程序的键壮性。如声明函数 int GetCount(void) const;此函C内就只能调用Const成员变量?br>VirtualQ虚函数Q派生类可以覆盖掉的函数Q纯虚函敎ͼ(x)只是个空函数Q没有函数实CQ?br>十六、extern“C”有什么作用?
Extern “C”是由Q+Q提供的一个连接交换指定符P用于告诉Q+Q这D代码是Q函数。这是因为C++~译后库中函数名?x)变得很长,与C生成的不一_(d)造成Q+Q不能直接调用C函数Q加上extren “c”后,C++p直接调用C函数了?br>Extern “C”主要使用正规DLL函数的引用和导出 ?在C++包含C函数或C头文件时使用。用时在前面加上extern “c” 关键字即可?br>十七、构造函C析构函数
zcȝ构造函数应在初始化表里调用基类的构造函敎ͼ
zcd基类的析构函数应加Virtual关键字?br>不要看构造函数和析构函数Q其实编hq是不容易?
#include <iostream.h>
class Base
{
public:
virtual ~Base() { cout<< "~Base" << endl ; }
};

class Derived : public Base
{
public:
virtual ~Derived() { cout<< "~Derived" << endl ; }
};

void main(void)
{
Base * pB = new Derived; // upcast
delete pB;
}
输出l果为:(x)
~Derived
~Base

如果析构函数不ؓ(f)虚,那么输出l果?br>~Base
十八?IFNDEF/#DEFINE/#ENDIF有什么作?/span>
仿止该头文g被重复引?nbsp;
十九(ji)、三l数l一ơ输?br> int b[2][3][4]={{{0,1,2,3,},{4,5,6,7},{8,9,10,11}},{{12,13,14,15},{16,17,18,19},{20,21,22,23}}};
    int i,j;
    for(i=0,j=1;i<24;i++,j++)
    {
        printf("%3d",b[i/12][i%12/4][i%12%4]);
        if(j%4==0)
            printf("\n");
    }


心羽 2010-08-25 10:26 发表评论
]]>
VC _T的用?/title><link>http://m.shnenglu.com/tdweng/articles/124436.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Mon, 23 Aug 2010 08:46:00 GMT</pubDate><guid>http://m.shnenglu.com/tdweng/articles/124436.html</guid><wfw:comment>http://m.shnenglu.com/tdweng/comments/124436.html</wfw:comment><comments>http://m.shnenglu.com/tdweng/articles/124436.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.shnenglu.com/tdweng/comments/commentRss/124436.html</wfw:commentRss><trackback:ping>http://m.shnenglu.com/tdweng/services/trackbacks/124436.html</trackback:ping><description><![CDATA[<p>VC++里面定义字符串的时候,用_T来保证兼Ҏ(gu)。VC++支持ascii和unicode两种字符cdQ用_T可以保证从ascii~码cd转换到unicode~码cd的时候,E序不需要修攏V?/p> <p>如果来你不打算升到unicodeQ那么也不需要_T?/p> <p>_t("hello world")</p> <p>在ansi的环境下Q它是ansi的,如果在unicode下,那么它将自动解释为双字节字符Ԍ既unicode~码?/p> <p>q样做的好处Q不是ansi环境Q还是unicode环境Q都适用?/p> <p>那么在VC++中,字符串_T("ABC")和一个普通的字符?ABC"有什么区别呢Q?/p> <p>_T("ABC")</p> <p>如果定义了unicodeQ它?yu)表CZؓ(f)L"ABC"Q每个字Wؓ(f)16位,宽字W串?/p> <p>如果没有定义unicodeQ它?yu)是ascii?ABC"Q每个字Wؓ(f)8位?/p> <p>相当?/p> <p>#ifdef _UNICODE</p> <p>#define _T("ABC") L"ABC"</p> <p>#else</p> <p>#define _T("ABC") "ABC"</p> <p>#endif</p> <p>_T("ABC")中的一个字W和汉字一P占两个字节,而在"ABC"中,英文字符占一个字节,汉字占两个字节?/p> <p>一?在字W串前加一个L作用:</p> <p>   ?L"我的字符?   表示ANSI字符串{换成unicode的字W串Q就是每个字W占用两个字节?/p> <p>strlen("asd") =   3;</p> <p>strlen(L"asd") =   6;</p> <p>   二?nbsp;  _T宏可以把一个引号引h的字W串Q根据你的环境设|,使得~译器会(x)Ҏ(gu)~译目标环境选择合适的QUnicodeq是ANSIQ字W处理方?/p> <p>   如果你定义了UNICODEQ那么_T宏会(x)把字W串前面加一个L。这?_T("ABCD") 相当?L"ABCD" Q这是宽字符丌Ӏ?/p> <p>   如果没有定义Q那么_T宏不?x)在字符串前面加那个LQ_T("ABCD") q价于 "ABCD"</p> <p>三、TEXT,_TEXT 和_T 一L(fng)</p> <p>如下面三语句Q?/p> <p>TCHAR szStr1[] = TEXT("str1");</p> <p>char szStr2[] = "str2";</p> <p>WCHAR szStr3[] = L("str3");</p> <p>那么W一句话在定义了UNICODE时会(x)解释为第三句话,没有定义时就{于W二句话?nbsp; </p> <p>但二句话无论是否定义了UNICODE都是生成一个ANSI字符Ԍ而第三句话L生成UNICODE字符丌Ӏ?/p> <p>ZE序的可UL性,都用W一U表C方法?/p> <p>但在某些情况下,某个字符必须为ANSI或UNICODEQ那q后两U方?br><br></p> <p>      char :单字节变量类型,最多表C?56个字W?/p> <p>      wchar_t :宽字节变量类型,用于表示Unicode字符</p> <p>      它实际定义在<string.h>里:(x)typedef unsigned short wchar_t?/p> <p>      Z让编译器识别Unicode字符Ԍ必须以在前面加一?#8220;L”,定义宽字节类型方法如下:(x)</p> <p>     wchar_t c = `A' ; <br>     wchar_t * p = L"Hello!" ; <br>     wchar_t a[] = L"Hello!" ; </p> <p>     其中Q宽字节cd每个变量占用2个字节,故上q数la的sizeof(a) = 14</p> <p>     TCHAR / _T( ) : <br>      如果在程序中既包括ANSI又包括Unicode~码Q需要包括头文gtchar.h。TCHAR是定义在该头文g中的宏,它视你是否定义了   <br>     NICODE宏而定义成Q?<br>定义了_UNICODEQ?nbsp;   typedef wchar_t TCHAR ; <br>没有定义_UNICODEQ?typedef char TCHAR ; </p> <p>#ifdef UNICODE <br>typedef char TCHAR; <br>#else <br>typede wchar_t TCHAR; <br>#endif <br>_T( )也是定义在该头文件中的宏Q视是否定义了_UNICODE宏而定义成Q?<br>定义了_UNICODEQ?nbsp;   #define _T(x) L##x <br>没有定义_UNICODEQ?#define _T(x) x <br>注意Q如果在E序中用了TCHARQ那么就不应该用ANSI的strXXX函数或者Unicode的wcsXXX函数了,而必M用tchar.h中定义的_tcsXXX函数?/p> <p>以strcpy函数Z子,ȝ一下:(x)<br> </p> <div><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif">//如果你想使用ANSI字符Ԍ那么请用这一套写法:(x) <br><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif">char szString[100]; <br><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif">strcpy(szString,"test"); <br><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif">//如果你想使用Unicode字符Ԍ那么请用这一套:(x) <br><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif">wchar_t szString[100]; <br><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif">wcscpy(szString,L"test"); <br><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif">//如果你想通过定义_UNICODE宏,而编译ANSI或者Unicode字符串代码:(x) <br><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif">TCHAR szString[100]; <br><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif">_tcscpy(szString,_TEXT("test"));</div> <p> <br><font size=2>char是C语言标准数据cdQ字W型Q至于由几个字节l成通常q译器军_Q一般一个字节。WindowsZ消除?~译器的差别Q重新定义了一些数据类型,你提C另外几个cd都是q样?br>CHAR为单字节字符?br>q有个WCHAR为Unicode字符Q即不论中英文,?个字有两个字节组成?br>如果当前~译方式为ANSI(默认)方式QTCHAR{h(hun)于CHARQ?br>如果为Unicode方式QTCHAR{h(hun)于WCHAR?br>在当 前版本LPCSTR和LPSTR没区别,即以零结字符串指针,相当于CHAR *?br></font></p> <p style="COLOR: red"><br></p> <p>char :单字节变量类型,最多表C?56个字W,</p> <p>wchar_t :宽字节变量类型,用于表示Unicode字符Q?/p> <p>它实际定义在<string.h>里:(x)typedef unsigned short wchar_t?/p> <p>Z让编译器识别Unicode字符Ԍ必须以在前面加一?#8220;L”,定义宽字节类型方法如下:(x)</p> <p>    wchar_t c = `A' ; <br>wchar_t * p = L"Hello!" ; <br>wchar_t a[] = L"Hello!" ; </p> <p>其中Q宽字节cd每个变量占用2个字节,故上q数la的sizeof(a) = 14</p> <p>TCHAR / _T( ) : <br>如果在程序中既包括ANSI又包括Unicode~码Q需要包括头文gtchar.h。TCHAR是定义在该头文g中的宏,它视你是否定义了_UNICODE宏而定义成Q?<br>定义了_UNICODEQ?nbsp;   typedef wchar_t TCHAR ; <br>没有定义_UNICODEQ?typedef char TCHAR ; </p> <p>#ifdef UNICODE <br>typedef char TCHAR; <br>#else <br>typede wchar_t TCHAR; <br>#endif <br>_T( )也是定义在该头文件中的宏Q视是否定义了_UNICODE宏而定义成Q?<br>定义了_UNICODEQ?nbsp;   #define _T(x) L##x <br>没有定义_UNICODEQ?#define _T(x) x <br>注意Q如果在E序中用了TCHARQ那么就不应该用ANSI的strXXX函数或者Unicode的wcsXXX函数了,而必M用tchar.h中定义的_tcsXXX函数?/p> <p>以strcpy函数Z子,ȝ一下:(x)<br> </p> <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"><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif"><span style="COLOR: #008000">//</span><span style="COLOR: #008000">如果你想使用ANSI字符Ԍ那么请用这一套写法:(x) </span><span style="COLOR: #008000"><br><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000"> szString[</span><span style="COLOR: #000000">100</span><span style="COLOR: #000000">]; <br><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif">strcpy(szString,</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">test</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">); <br><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">如果你想使用Unicode字符Ԍ那么请用这一套:(x) </span><span style="COLOR: #008000"><br><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">wchar_t szString[</span><span style="COLOR: #000000">100</span><span style="COLOR: #000000">]; <br><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif">wcscpy(szString,L</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">test</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">); <br><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">如果你想通过定义_UNICODE宏,而编译ANSI或者Unicode字符串代码:(x) </span><span style="COLOR: #008000"><br><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif"></span><span style="COLOR: #000000">TCHAR szString[</span><span style="COLOR: #000000">100</span><span style="COLOR: #000000">]; <br><img align=top src="http://m.shnenglu.com/Images/OutliningIndicators/None.gif">_tcscpy(szString,_TEXT(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">test</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">));</span></div> <p> </p> <p>CSDN:superarhow_(d)(x) 不要再用TCHAR和_T了!他分析了原因后ȝQ如 果?zhn)正开始一个新的项目,h论如何也要顶住压力,直接使用UNICODE~码Q切讎ͼ(zhn)只需要对(zhn)的l员q行10分钟的培训,Cstrcpy?wcscpyQsprintf用swprintf代替Q常数前加LQ就可以了!它不?x)花?zhn)很多时间的Q带l?zhn)的是E_和安全!怿Ӟ没错的!Q?/p> <p>一?在字W串前加一个L作用: <br>   ?nbsp; L"我的字符?    表示ANSI字符串{换成unicode的字W串Q就是每个字W占用两个字节?<br>  strlen("asd")   =   3;   <br>  strlen(L"asd")   =   6; <br>  二?nbsp; _T宏可以把一个引号引h的字W串Q根据你的环境设|,使得~译器会(x)Ҏ(gu)~译目标环境选择合适的QUnicodeq是ANSIQ字W处理方?<br>   如果你定义了UNICODEQ那么_T宏会(x)把字W串前面加一个L。这?_T("ABCD") 相当?L"ABCD" Q这是宽字符丌Ӏ?<br>   如果没有定义Q那么_T宏不?x)在字符串前面加那个LQ_T("ABCD") q价于 "ABCD" <br>三、TEXT,_TEXT 和_T 一L(fng) <br>如下面三语句Q?nbsp;  <br>  TCHAR   szStr1[]   =   TEXT("str1");   <br>  char   szStr2[]   =   "str2";   <br>  WCHAR   szStr3[]   =   L("str3");   <br>  那么W一句话在定义了UNICODE时会(x)解释为第三句话,没有定义时就{于W二句话?nbsp;  <br>  但二句话无论是否定义了UNICODE都是生成一个ANSI字符Ԍ而第三句话L生成UNICODE字符丌Ӏ?nbsp;  <br>  ZE序的可UL性,都用W一U表C方法?nbsp;  <br>  但在某些情况下,某个字符必须为ANSI或UNICODEQ那q后两U方法?/p> <p style="COLOR: red">CSDN:superarhow_(d)(x) 不要再用TCHAR和_T了!他分析了原因后ȝQ如 果?zhn)正开始一个新的项目,h论如何也要顶住压力,直接使用UNICODE~码Q切讎ͼ(zhn)只需要对(zhn)的l员q行10分钟的培训,Cstrcpy?wcscpyQsprintf用swprintf代替Q常数前加LQ就可以了!它不?x)花?zhn)很多时间的Q带l?zhn)的是E_和安全!怿Ӟ没错的!Q?/p> <img src ="http://m.shnenglu.com/tdweng/aggbug/124436.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.shnenglu.com/tdweng/" target="_blank">心羽</a> 2010-08-23 16:46 <a href="http://m.shnenglu.com/tdweng/articles/124436.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>#ifndef#define#endif的用?整理) (转发)http://m.shnenglu.com/tdweng/articles/124387.html心羽心羽Mon, 23 Aug 2010 02:47:00 GMThttp://m.shnenglu.com/tdweng/articles/124387.htmlhttp://m.shnenglu.com/tdweng/comments/124387.htmlhttp://m.shnenglu.com/tdweng/articles/124387.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/124387.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/124387.html
[转] #ifndef#define#endif的用?整理)    ?span class=addtime>作者:(x)icwk 

文g中的#ifndef

头g的中?ifndefQ这是一个很关键的东ѝ比如你有两个C文gQ这两个C文g都include了同一个头文g。而编译时Q这两个C文g要一同编译成一个可q行文gQ于是问题来了,大量的声明冲H?

q是把头文g的内定w攑֜#ifndef?endif中吧。不你的头文g?x)不会(x)被多个文g引用Q你都要加上q个。一般格式是q样的:(x)

#ifndef <标识>
#define <标识>

......
......

#endif

<标识>在理Z来说可以是自由命名的Q但每个头文件的q个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线Qƈ把文件名中的“.”也变成下划线Q如Qstdio.h

#ifndef _STDIO_H_
#define _STDIO_H_

......

#endif

2.?ifndef中定义变量出现的问题Q一般不定义?ifndef中)?/p>

#ifndef AAA
#define AAA
...
int i;
...
#endif
里面有一个变量定?br>在vc中链接时出Ci重复定义的错误,而在c中成功编译?/p>

l论Q?/p>

(1).当你W一个用这个头?cpp文g生成.obj的时候,int i 在里面定义了当另外一个用这个的.cpp再次[单独]生成.obj的时候,int i 又被定义然后两个obj被另外一?cpp也include q个头的Q连接在一P׃(x)出现重复定义.

(2).把源E序文g扩展名改?c后,VC按照C语言的语法对源程序进行编译,而不是C++。在C语言中,若是遇到多个int iQ则自动认ؓ(f)其中一个是定义Q其他的是声明?/p>

(3).C语言和C++语言q接l果不同Q可能(猜测Q时在进行编译的时候,C++语言全局
变量默认为强W号Q所以连接出错。C语言则依照是否初始化q行强弱的判断的。(参考)

解决Ҏ(gu)Q?/p>

(1).把源E序文g扩展名改?c?/p>

(2).推荐解决Ҏ(gu)Q?br>.h中只声明 extern int i;?cpp中定?/p>

<x.h>
#ifndef __X_H__
#define __X_H__
extern int i;
#endif //__X_H__
<x.c>
int i;

注意问题Q?/p>

(1).变量一般不要定义在.h文g中?/p>

 

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

一般情况下Q源E序中所有的行都参加~译。但是有时希望对其中一部分内容只在满一定条件才q行~译Q也是对一部分内容指定~译的条Ӟq就?#8220;条g~译”。有Ӟ希望当满x条g时对一l语句进行编译,而当条g不满x则编译另一l语句?
条g~译命o(h)最常见的Ş式ؓ(f)Q?
    #ifdef 标识W?
    E序D?
    #else
    E序D?
    #endif
    
    它的作用是:(x)当标识符已经被定义过(一般是?define命o(h)定义)Q则对程序段1q行~译Q否则编译程序段2?
    其中#else部分也可以没有,卻I(x)
    #ifdef
    E序D?
    #denif
    
    q里?#8220;E序D?#8221;可以是语句组Q也可以是命令行。这U条件编译可以提高C源程序的通用性。如果一个C源程序在不同计算机系l上pȝ上运行,而不同的计算机又有一定的差异。例如,我们有一个数据类型,在Windowsq_中,应该使用longcd表示Q而在其他q_应该使用float表示Q这样往往需要对源程序作必要的修改,q就降低了程序的通用性。可以用以下的条件编译:(x)
    #ifdef WINDOWS
    #define MYTYPE long
    #else
    #define MYTYPE float
    #endif
    
    如果在Windows上编译程序,则可以在E序的开始加?
    #define WINDOWS
    
    q样则编译下面的命o(h)行:(x)
    #define MYTYPE long
    
    如果在这l条件编译命令之前曾出现以下命o(h)行:(x)
    #define WINDOWS 0
    
    则预~译后程序中的MYTYPE都用float代替。这P源程序可以不必作M修改可以用于不同类型的计算机系l。当然以上介l的只是一U简单的情况Q可以根据此思\设计出其它的条g~译?
    例如Q在调试E序Ӟ常常希望输出一些所需的信息,而在调试完成后不再输些信息。可以在源程序中插入以下的条件编译段Q?
    #ifdef DEBUG
    print ("device_open(%p) ", file);
    #endif
    
    如果在它的前面有以下命o(h)行:(x)
    #define DEBUG
    
    则在E序q行时输出file指针的|以便调试分析。调试完成后只需这个define命o(h)行删除即可。有人可能觉得不用条件编译也可达此目的,卛_调试时加一批printf语句Q调试后一一printf语句删除厅R的,q是可以的。但是,当调试时加的printf语句比较多时Q修改的工作量是很大的。用条g~译Q则不必一一删改printf语句Q只需删除前面的一?#8220;#define DEBUG”命o(h)卛_Q这时所有的用DEBUG作标识符的条件编译段都其中的printf语句不v作用Q即L(fng)一控制的作用,如同一?#8220;开?#8221;一栗?
    有时也采用下面的形式Q?
    #ifndef 标识W?
    E序D?
    #else
    E序D?
    #endif
    
    只是W一行与W一UŞ式不同:(x)?#8220;ifdef”改ؓ(f)“ifndef”。它的作用是Q若标识W未被定义则~译E序D?Q否则编译程序段2。这UŞ式与W一UŞ式的作用相反?
    以上两种形式用法差不多,Ҏ(gu)需要Q选一U,视方便而定?
    q有一UŞ式,是#if后面的是一个表辑ּQ而不是一个简单的标识W:(x)
    #if 表达?
    E序D?
    #else
    E序D?
    #endif
    
    它的作用是:(x)当指定的表达式gؓ(f)真(非零Q时q译程序段1Q否则编译程序段2。可以事先给定一定条Ӟ使程序在不同的条件下执行不同的功能?/p>

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

作用范围是当前文g啊。因为编译是以cpp或c文g位单位的嘛。还以这个ؓ(f)例:(x)

//正常代码
#ifdef _DEBUG
     TRACE("Some infomation");
#else
     //Now is release version,so do nothing
#endif
//正常代码

~译时是先把所有的预编译处理展开Q比如宏Q再~译Q所以Debug模式下,~译时的代码是:(x)
//正常代码
TRACE("Some infomation");
//正常代码

Release模式下的代码是:(x)
//正常代码
//正常代码

Z避免同一个文件被include多次

1   #ifndef方式
2   #pragma once方式

在能够支持这两种方式的编译器上,二者ƈ没有太大的区别,但是两者仍然还是有一些细微的区别?br>    方式一Q?/span>

    #ifndef __SOMEFILE_H__
    #define __SOMEFILE_H__
    ... ... // 一些声明语?br>    #endif

    方式二:(x)

    #pragma once
    ... ... // 一些声明语?/p>


    #ifndef的方式依赖于宏名字不能冲H,q不光可以保证同一个文件不?x)被包含多次Q也能保证内容完全相同的两个文g不会(x)被不心同时包含。当Ӟ~点是如果不同头文件的宏名不小?#8220;撞R”Q可能就?x)导致头文g明明存在Q编译器却硬说找不到声明的状?br>
    #pragma once则由~译器提供保证:(x)同一个文件不?x)被包含多次。注意这里所说的“同一个文?#8221;是指物理上的一个文Ӟ而不是指内容相同的两个文件。带来的好处是,你不必再费劲想个宏名了,当然也就不会(x)出现宏名撞引发的奇怪问题。对应的~点是如果某个头文件有多䆾拯Q本Ҏ(gu)不能保证他们不被重复包含。当Ӟ相比宏名撞引发?#8220;找不到声?#8221;的问题,重复包含更容易被发现q修正?br>
   方式一pa支持所以移植性好Q方式二 可以避免名字冲突



心羽 2010-08-23 10:47 发表评论
]]>
C++中const用法ȝ(转发)http://m.shnenglu.com/tdweng/articles/124385.html心羽心羽Mon, 23 Aug 2010 02:42:00 GMThttp://m.shnenglu.com/tdweng/articles/124385.htmlhttp://m.shnenglu.com/tdweng/comments/124385.htmlhttp://m.shnenglu.com/tdweng/articles/124385.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/124385.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/124385.html作者JuKevin

1. const修饰普通变量和指针

const修饰变量Q一般有两种写法Q?

const TYPE value;

TYPE const value;

q两U写法在本质上是一L(fng)。它的含义是Qconst修饰的类型ؓ(f)TYPE的变量value是不可变的?

对于一个非指针的类型TYPEQ无论怎么写,都是一个含义,即value只不可变?

例如Q?

const int nValueQ?        //nValue是const

int const nValueQ?nbsp;   // nValue是const

但是对于指针cd的TYPEQ不同的写法?x)有不同情况Q例如:(x)

A. const char *pContent;

B. char * const pContent;

C. char const *pContent;

D. const char* const pContent;

 

对于前三U写法,我们可以换个方式Q给其加上括?

A. const (char) *pContent;

B. (char*) const pContent;

C. (char) const *pContent;

q样׃目了然。根据对于const修饰非指针变量的规则Q很明显QA=C.

 

- 对于A,C, const修饰的类型ؓ(f)char的变?pContent为常量,因此QpContent的内容ؓ(f)帔R不可?

- 对于B, const修饰的类型ؓ(f)char*的变量pContent为常量,因此QpContent指针本n为常量不可变.

- 对于D, 其实是A和B的؜合体Q表C指针本w和指针内容两者皆为常量不可变

 

ȝ:

(1)  指针本n是常量不可变

(char*) const pContent;

 

(2)  指针所指向的内Ҏ(gu)帔R不可?

const (char) *pContent;

(char) const *pContent;

 

(3)  两者都不可?

const char* const pContent;

 

q有其中区别Ҏ(gu)Q?

沿着*号划一条线Q?

如果const位于*的左侧,则const是用来修饰指针所指向的内容变量,x针指向ؓ(f)帔RQ物帔RQ;

如果const位于*的右侧,const是修饰指针本nQ即指针本n是常量(指针帔RQ?/span>

例子:(x)
char ch[5] = "lisi";
const char* pStr = ch;
*pStr = 'w';  //errorQ物帔RQ不可更改内?br>pStr ="wangwu"; //OKQ物帔RQ可更改指针

cha ch[5] = "lisi";
char * const pStr = "lisi";
pStr = "zhangsan"; //errorQ指针常量,不可更改指针
*pStr = "w"; //OK Q指针常量,可更改内?

2. const修饰函数参数

const修饰函数参数是它最q泛的一U用途,它表C函C中不能修改参数的?包括参数本n的值或者参数其中包含的?。它可以很好

void function(const int Var); //传递过来的参数在函数内不可以改?无意义,因ؓ(f)Var本n是形参)

void function(const char* Var); //参数指针所指内容ؓ(f)帔R不可?

void function(char* const Var); //参数指针本n为常量不可变(也无意义Q?因ؓ(f)char* Var也是形参)

 

参数为引用,Z增加效率同时防止修改?

修饰引用参数Ӟ(x)

void function(const Class& Var);//引用参数在函数内不可以改?

void function(const TYPE& Var); //引用参数在函数内为常量不可变

 

3. const 修饰函数q回?/p>

const修饰函数q回值其实用的ƈ不是很多Q它的含义和const修饰普通变量以?qing)指针的含义基本相同?

(1) const int fun1() q个其实无意义,因ؓ(f)参数q回本n是赋倹{?

(2) const int * fun2()

调用?const int *pValue = fun2();

我们可以把fun2()看作成一个变量,那么是我们上面所说的1.(1)的写法,x针内容不可变?

(3) int* const fun3()

调用?int * const pValue = fun2();

我们可以把fun2()看作成一个变量,那么是我们上面所说的1.(2)的写法,x针本w不可变?

4. const修饰cd?对象指针/对象引用

const修饰cd象表C对象为常量对象,其中的Q何成员都不能被修攏V对于对象指针和对象引用也是一栗?

const修饰的对象,该对象的M非const成员函数都不能被调用Q因ZQ何非const成员函数?x)有修改成员变量的企图?

例如Q?

class AAA

{
   void func1();

void func2() const;

}

const AAA aObj;

aObj.func1(); ×

aObj.func2(); 正确

 

const AAA* aObj = new AAA();

aObj->func1(); ×

aObj->func2(); 正确

 

5. const修饰成员变量

const修饰cȝ成员函数Q表C成员常量,不能被修改,同时它只能在初始化列表中赋倹{?

 

class A

{

   …

   const int nValue;       //成员帔R不能被修?

   …

   A(int x): nValue(x) {}; //只能在初始化列表中赋?

}

 

6. const修饰成员函数

const修饰cȝ成员函数Q则该成员函C能修改类中Q何非const成员函数。一般写在函数的最后来修饰?

 

class A

{

   …

void function()const; //常成员函? 它不改变对象的成员变? 也不能调用类中Q何非const成员函数?

}

对于constcd?指针/引用Q只能调用类的const成员函数Q因此,const修饰成员函数的最重要作用是限制对于const对象的用?

 

7. const帔R与define宏定义的区别

(1) ~译器处理方式不?

define宏是在预处理阶段展开?

const帔R是编译运行阶D用?

(2) cd和安全检查不?

define宏没有类型,不做Mcd查,仅仅是展开?

const帔R有具体的cdQ在~译阶段?x)执行类型检查?

(3) 存储方式不同

define宏仅仅是展开Q有多少地方使用Q就展开多少ơ,不会(x)分配内存?

const帔R?x)在内存中分?可以是堆中也可以是栈??/p>

心羽 2010-08-23 10:42 发表评论
]]>
C++ extern例?/title><link>http://m.shnenglu.com/tdweng/articles/124375.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Mon, 23 Aug 2010 02:17:00 GMT</pubDate><guid>http://m.shnenglu.com/tdweng/articles/124375.html</guid><wfw:comment>http://m.shnenglu.com/tdweng/comments/124375.html</wfw:comment><comments>http://m.shnenglu.com/tdweng/articles/124375.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.shnenglu.com/tdweng/comments/commentRss/124375.html</wfw:commentRss><trackback:ping>http://m.shnenglu.com/tdweng/services/trackbacks/124375.html</trackback:ping><description><![CDATA[<span style="COLOR: red">用例子给你示?<br>// 1.cpp <br>int x = 10; <br>// 2.cpp 注意没有包含1.cpp <br>#include <iostream> <br>using namespace std; <br>extern int x;<br>int main () <br>{ cout << x << endl; } <br>//则输?0 <br>两个文g同在一个项目(projectQ中Q你不包含某个文ӞcppQ而可以用它内部定义的变量Q?q里?cpp不是.h, 因ؓ(f)?h中定义的数据不能?cpp中用除非q个.cpp包含q个.h文gQ?/span> <br>例:(x) <br>// 1.h <br>#include <iostream> <br>void print() <br>{ <br>std::cout << "hello!" << std::endl; <br>} <br>// 2.cpp <br>#include <iostream> <br>using namespace std; <br>// 以上两句在这个例子中可以不要 <br>extern void print(); <br>int main () <br>{ <br>print(); <br>} <br>׃(x)出错因ؓ(f)1.h中的void print()Q在不包含它的文件中是不可调用的Q即使在声明了extern 也于事无补,如果你将q个例子中的1.h名字换成1.cpp对了! <br><span style="COLOR: red">从这些可以看出来Qextern在这里v的作用是告诉~译器,你这个print()已经在某?cpp中已l定义了Q这里只不过是声明一下有q个东西Q然后拿来用一下。定义只能出Cơ,声明却可出现多次Q也是说extern声明可在多个文g中用Q包?h) <br>q有Q你q可以屏蔽extern声明Q如W二个例子中的第二个.cpp文g可以Ҏ(gu) <br></span>#include <iostream> <br>using namespace std; <br>// q里以上两句不能省略Q因为,q里extern void print();函数已经不v作用了,在这里调用的而是本文件中定义的void print()函数Q其中用Ccout,endl;他们来源于std::<iostream> <br>extern void print(); <br>void print() <br>{ <br>cout << "world!" << endl; <br>} <br><br>int main () <br>{ <br>print(); <br>} <br>// 输出l果为world! <br>q有一个extern "C"׃用说了,用这个可以允许C++E序中调用C的函敎ͼ <img src ="http://m.shnenglu.com/tdweng/aggbug/124375.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.shnenglu.com/tdweng/" target="_blank">心羽</a> 2010-08-23 10:17 <a href="http://m.shnenglu.com/tdweng/articles/124375.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C/C++/VC随机数ȝhttp://m.shnenglu.com/tdweng/articles/114159.html心羽心羽Sun, 02 May 2010 03:10:00 GMThttp://m.shnenglu.com/tdweng/articles/114159.htmlhttp://m.shnenglu.com/tdweng/comments/114159.htmlhttp://m.shnenglu.com/tdweng/articles/114159.html#Feedback1http://m.shnenglu.com/tdweng/comments/commentRss/114159.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/114159.html 

大家都知道C语言中的随机函数randomQ可是random函数q不是ANSI C标准Q所以说Qrandom函数不能在gcc,vc{编译器下编
译通过。那么怎么实现VC语言中的随机函数呢?

其实Q除了random函数Q还有一个rand函数Q这个函C是一个随机函敎ͼ他可以生从0到rand_max(32767)的随机数?/p>

 

#include<stdio.h>
#include
<stdlib.h>

int main()

   
int k; 
   k 
= rand();
   printf(
"%d\\n", k);
   
return 0;
}
//main

大家可以把以上的代码~译q行一下,发现他的生随机数了,但是你会(x)发现Q每ơ运行程序生的随机数都是一L(fng)Q不q你在程序里加上for循环Q每ơ生的C一P但是Q如果再q行q个E序Q它产生的数据却都是相同的?/p>

那么如何写一个程序,让它每次q行时生的随机数都不一样呢Q?L(fng)下面的例子:(x)

#include <stdlib.h>
#include 
<stdio.h>
#include 
<time.h>
#include
<iostream>
using namespace std;
int main(void)
{
   
int i;
   time_t t;
   srand((unsigned) time(
&t));
  cout
<<"Ten random numbers from 0 to 99\n\n";
   
for(i=0; i<10; i++)
       printf(
"%d\n", rand() % 100);
   
return 0;
}

q时q行E序Q会(x)发现每次产生的随机数都不一栗?/p>

那么Z么第一个程序一栯第二个E序一样呢Q?/p>

W二个程序用C一个新的函数srand

q个函数是给随机C生一个随机种?seed)Q函数原型是srand( (unsigned)time( NULL ) );


time的值每时每刻都不同。所以种子不同,所以,产生的随机数也不同?/p>

所以说Q要想生不同的随机敎ͼ在用rand之前需要先调用srand

srand和rand函数都包含在stdlib.h的头文g里?/p>

׃rand产生的随机数是从0到rand_max的,而rand_maxQ?2767Q是一个很大的敎ͼ那么如何产生从X~Y的数呢?

从X到YQ有YQXQ?个数Q所以要产生从X到Y的数Q只需要这样写Q?/p>

k = rand() % (Y - X + 1) +X;

q样Q就可以产生你想要的M范围内的随机C?
问题Q如何生成K个小于Nq且互不重复的整?/span>

一.首先对于c++的随机函数我们要有所了解Q这里就不篏赘了Q请读者自行google之,
我们要用到的?br>1. void srand(unsigned int_seed)函数产生一个以当前旉开始的随机U子
  srand(unsigned(time(NULL))),必须攑֜生成随机数前
2.int rand()函数Q随Z生一整数
   rand()%MAX 产生[0,MAX)的整?br>   a+rand()%(b-a+1) 产生[a,b]之间的整?br>3.需要头文g#include<time.h>

#include<iostream>
using namespace std;
#include
<time.h>
#define N 100
#define K 20

int x[N];
void swap(int i,int j)
{
  
int temp=x[i];
  x[i]
=x[j];
  x[j]
=temp;
}

int main()
{
    
int i;
    
for(i=0;i<N;i++)
        x[i]
=i;
    srand(unsigned(time(NULL)));
    
for(i=0;i<K;i++){
        swap(i,i
+rand()%(N-i));
        cout
<<x[i]<<" ";
    }

    
    
return 0;
}


?考虑如何让数据不重复 
  看代码吧。。学?fn)下?gu)
首先搞个一l没有重复数据的数组Q就是x[i]=i;
此时注意那个swap函数Q每ơ生成的随机C为数l下标去取数Q然后交换,q就保证了xq个数组l不?x)有重复的数出现?br>l了Q!



心羽 2010-05-02 11:10 发表评论
]]>
C语言全dW串函数 http://m.shnenglu.com/tdweng/articles/113484.html心羽心羽Sat, 24 Apr 2010 18:07:00 GMThttp://m.shnenglu.com/tdweng/articles/113484.htmlhttp://m.shnenglu.com/tdweng/comments/113484.htmlhttp://m.shnenglu.com/tdweng/articles/113484.html#Feedback0http://m.shnenglu.com/tdweng/comments/commentRss/113484.htmlhttp://m.shnenglu.com/tdweng/services/trackbacks/113484.html
看到q样一个改错题Q?br>
char p[5]; 
char* s="12345"
strcpy(p,s);
   cout << p << endl;
错误之处是很昄的,作ؓ(f)字符串字面值的"12345"?x)在l尾处自动加上空字符nullQ从而长度是6Q上面的strcpy是会(x)界的,从而是个越界错误?br>问题是我以ؓ(f)q样的程序编译的时候会(x)出错?但是我在vc上运行时是可以输出正结果的Q这让我很是U闷Q后来找Cstrcpy的源代码才知原因Qstrcpy函数是不q行界处理? 又因为strcpyqnull一起复Ӟ从而p能输出正的l果"12345"
/*The strcpy function copies strSource, including the terminating null character, to the location specified by strDestination. No overflow checking is performed when strings are copied or appended. The behavior of strcpy is undefined if the source and destination strings overlap.*/
char * __cdecl strcpy(char * dst, const char * src) 

char * cp = dst; 

while*cp++ = *src++ ) 
/* Copy src over dst */ 

return( dst ); 
}
 
貌似strcpy虽然不进行越界处理,仍然是个挺好的函数呢Q但是注意了Q下面的代码p暴露出strcpy 的缺点了.
char p[5];
char *= "12345678";
strcpy(p,s);
cout 
<< p <<endl; //输出12345678Q而不是我们所设想?2345
Z不因不知s的长度而犯下错误,推荐使用strncpy。但是是不是用了strncpy׃无一׃呢?看下面的代码Q?br>
char p[5];
char* s = "12345";
strncpy(p,s,
5);
cout 
<< p <<endl; //12345*&^(后面表示q)
不是都限制个C么?Z么后面又有ؕ码?
问题来自在上q情形strncpy是不?x)复制字W串s后面的null的,不是以nulll束的p不会(x)输出正确l果的?br>仍然l出strncpy的源代码Q?br>
/*The strncpy function copies the initial count characters of strSource to strDest and returns strDest. If count is less than or equal to the length of strSource, a null character is not appended automatically to the copied string. If count is greater than the length of strSource, the destination string is padded with null characters up to length count. The behavior of strncpy is undefined if the source and destination strings overlap.*/
char * __cdecl strncpy ( char * dest, const char * source, size_t count ) 

char *start = dest; 

while (count && (*dest++ = *source++)) /* copy string */ 
count
--

if (count) /* pad out with zeroes */ 
while (--count) 
*dest++ = '\0'

return(start); 
}
 
那strncpyq么不稳定,Z用它Qstrncpyl常用于修改一个长字符串中间的一部分Q看Z复制null的原因了吧!Q,如果实在要用Cq的代码上,在代码最后加上p[5] = '\0'; 吧!

函数? stpcpy
?nbsp; ? 拯一个字W串到另一?
?nbsp; ? char *stpcpy(char *destin, char *source);

E序?
#include <stdio.h>
#include <string.h>
int main(void)
{
   char string[10];
   char *str1 = "abcdefghi";
   stpcpy(string, str1);
   printf("%sn", string);
   return 0;
}
 
 
 
函数? strcat
?nbsp; ? 字符串拼接函?
?nbsp; ? char *strcat(char *destin, char *source);
E序?
#include <string.h>
#include <stdio.h>
int main(void)
{
   char destination[25];
   char *blank = " ", *c = "C++", *Borland = "Borland";
   strcpy(destination, Borland);
   strcat(destination, blank);
   strcat(destination, c);
   printf("%sn", destination);
   return 0;
}
 
 
 
函数? strchr
?nbsp; ? 在一个串中查扄定字W的W一个匹配之?
?nbsp; ? char *strchr(char *str, char c);

E序?
#include <string.h>
#include <stdio.h>
int main(void)
{
    char string[15];
    char *ptr, c = 'r';
    strcpy(string, "This is a string");
    ptr = strchr(string, c);
    if (ptr)
       printf("The character %c is at position: %d\n", c, ptr-string);// 不明?nbsp;
    else
       printf("The character was not foundn");
    return 0;
}
 
 
 
函数? strcmp
?nbsp; ? 串比?
?nbsp; ? int strcmp(char *str1, char *str2);
看Asic码,str1>str2Q返回?> 0Q两串相{,q回0

E序?
#include <string.h>
#include <stdio.h>
int main(void)
{
    char *buf1 = "aaa", *buf2 = "bbb", *buf3 = "ccc";
    int ptr;
    ptr = strcmp(buf2, buf1);
    if (ptr > 0)
       printf("buffer 2 is greater than buffer 1n");
    else
       printf("buffer 2 is less than buffer 1n");
    ptr = strcmp(buf2, buf3);
    if (ptr > 0)
       printf("buffer 2 is greater than buffer 3n");
    else
       printf("buffer 2 is less than buffer 3n");
    return 0;
}
 
 
 
函数? strncmpi
?nbsp; ? 一个串中的一部分与另一个串比较, 不管大小?
?nbsp; ? int strncmpi(char *str1, char *str2, unsigned maxlen);

E序?
#include <string.h>
#include <stdio.h>
int main(void)
{
   char *buf1 = "BBB", *buf2 = "bbb";
   int ptr;
   ptr = strcmpi(buf2, buf1);
   if (ptr > 0)
      printf("buffer 2 is greater than buffer 1n");
   if (ptr < 0)
      printf("buffer 2 is less than buffer 1n");
   if (ptr == 0)
      printf("buffer 2 equals buffer 1n");
   return 0;
}
 
 
 
函数? strcpy
?nbsp; ? 串拷?
?nbsp; ? char *strcpy(char *str1, char *str2);

E序?
#include <stdio.h>
#include <string.h>
int main(void)
{
    char string[10];
    char *str1 = "abcdefghi";
    strcpy(string, str1);
    printf("%sn", string);
    return 0;
}
 
 
 
函数? strcspn
?nbsp; ? 在串中查扄一个给定字W集内容的段
?nbsp; ? int strcspn(char *str1, char *str2);

E序?
#include <stdio.h>
#include <string.h>
#include <alloc.h>
int main(void)
{
    char *string1 = "1234567890";
    char *string2 = "747DC8";
    int length;
    length = strcspn(string1, string2);
    printf("Character where strings intersect is at position %dn", length);
    return 0;
}
 
 
 
函数? strdup
?nbsp; ? 串拯到新建的位置?
?nbsp; ? char *strdup(char *str);

E序?
#include <stdio.h>
#include <string.h>
#include <alloc.h>
int main(void)
{
    char *dup_str, *string = "abcde";
    dup_str = strdup(string);
    printf("%sn", dup_str);
    free(dup_str);
    return 0;
}
 
 
 
函数? stricmp
?nbsp; ? 以大写不敏感方式比较两个串
?nbsp; ? int stricmp(char *str1, char *str2);

E序?
#include <string.h>
#include <stdio.h>
int main(void)
{
   char *buf1 = "BBB", *buf2 = "bbb";
   int ptr;
   ptr = stricmp(buf2, buf1);
   if (ptr > 0)
      printf("buffer 2 is greater than buffer 1n");
   if (ptr < 0)
      printf("buffer 2 is less than buffer 1n");
   if (ptr == 0)
      printf("buffer 2 equals buffer 1n");
   return 0;
}
 
 
函数? strerror
?nbsp; ? q回指向错误信息字符串的指针
?nbsp; ? char *strerror(int errnum);

E序?
#include <stdio.h>
#include <errno.h>
int main(void)
{
   char *buffer;
   buffer = strerror(errno);
   printf("Error: %sn", buffer);
   return 0;
}
 
 
 
函数? strcmpi
?nbsp; ? 一个串与另一个比? 不管大小?
?nbsp; ? int strcmpi(char *str1, char *str2);

E序?
#include <string.h>
#include <stdio.h>
int main(void)
{
   char *buf1 = "BBB", *buf2 = "bbb";
   int ptr;
   ptr = strcmpi(buf2, buf1);
   if (ptr > 0)
      printf("buffer 2 is greater than buffer 1n");
   if (ptr < 0)
      printf("buffer 2 is less than buffer 1n");
   if (ptr == 0)
      printf("buffer 2 equals buffer 1n");
   return 0;
}
 
 
 
函数? strncmp
?nbsp; ? 串比?
?nbsp; ? int strncmp(char *str1, char *str2, int maxlen);

E序?
#include <string.h>
#include <stdio.h>
int  main(void)
{
   char *buf1 = "aaabbb", *buf2 = "bbbccc", *buf3 = "ccc";
   int ptr;
   ptr = strncmp(buf2,buf1,3);
   if (ptr > 0)
      printf("buffer 2 is greater than buffer 1n");
   else
      printf("buffer 2 is less than buffer 1n");
   ptr = strncmp(buf2,buf3,3);
   if (ptr > 0)
      printf("buffer 2 is greater than buffer 3n");
   else
      printf("buffer 2 is less than buffer 3n");
   return(0);
}
 
 
函数? strncmpi
?nbsp; ? 把串中的一部分与另一串中的一部分比较, 不管大小?
?nbsp; ? int strncmpi(char *str1, char *str2);

E序?
#include <string.h>
#include <stdio.h>
int main(void)
{
   char *buf1 = "BBBccc", *buf2 = "bbbccc";
   int ptr;
   ptr = strncmpi(buf2,buf1,3);
   if (ptr > 0)
      printf("buffer 2 is greater than buffer 1n");
   if (ptr < 0)
      printf("buffer 2 is less than buffer 1n");
   if (ptr == 0)
      printf("buffer 2 equals buffer 1n");
   return 0;
}
 
 
函数? strncpy
?nbsp; ? 串拷?
?nbsp; ? char *strncpy(char *destin, char *source, int maxlen);

E序?
#include <stdio.h>
#include <string.h>
int main(void)
{
   char string[10];
   char *str1 = "abcdefghi";
   strncpy(string, str1, 3);
   string[3] = '';
   printf("%sn", string);
   return 0;
}
 
 
函数? strnicmp
?nbsp; ? 不注重大写地比较两个串
?nbsp; ? int strnicmp(char *str1, char *str2, unsigned maxlen);

E序?
#include <string.h>
#include <stdio.h>
int main(void)
{
   char *buf1 = "BBBccc", *buf2 = "bbbccc";
   int ptr;
   ptr = strnicmp(buf2, buf1, 3);
   if (ptr > 0)
      printf("buffer 2 is greater than buffer 1n");
   if (ptr < 0)
      printf("buffer 2 is less than buffer 1n");
   if (ptr == 0)
      printf("buffer 2 equals buffer 1n");
   return 0;
}
 
 
 
函数? strnset
?nbsp; ? 一个串中的所有字W都设ؓ(f)指定字符
?nbsp; ? char *strnset(char *str, char ch, unsigned n);

E序?
#include <stdio.h>
#include <string.h>
int main(void)
{
   char *string = "abcdefghijklmnopqrstuvwxyz";
   char letter = 'x';
   printf("string before strnset: %sn", string);
   strnset(string, letter, 13);
   printf("string after  strnset: %sn", string);
   return 0;
}
 
 
函数? strpbrk
?nbsp; ? 在串中查扄定字W集中的字符
?nbsp; ? char *strpbrk(char *str1, char *str2);

E序?
#include <stdio.h>
#include <string.h>
int main(void)
{
   char *string1 = "abcdefghijklmnopqrstuvwxyz";
   char *string2 = "onm";
   char *ptr;
   ptr = strpbrk(string1, string2);
   if (ptr)
      printf("strpbrk found first character: %cn", *ptr);
   else
      printf("strpbrk didn't find character in setn");
   return 0;
}
 
 
 
函数? strrchr
?nbsp; ? 在串中查找指定字W的最后一个出?
?nbsp; ? char *strrchr(char *str, char c);

E序?
#include <string.h>
#include <stdio.h>
int main(void)
{
   char string[15];
   char *ptr, c = 'r';
   strcpy(string, "This is a string");
   ptr = strrchr(string, c);
   if (ptr)
      printf("The character %c is at position: %dn", c, ptr-string);
   else
      printf("The character was not foundn");
   return 0;
}
 
 
 
函数? strrev
?nbsp; ? 串倒{
?nbsp; ? char *strrev(char *str);

E序?
#include <string.h>
#include <stdio.h>
int main(void)
{
   char *forward = "string";
   printf("Before strrev(): %sn", forward);
   strrev(forward);
   printf("After strrev():  %sn", forward);
   return 0;
}
 
函数? strset
?nbsp; ? 一个串中的所有字W都设ؓ(f)指定字符
?nbsp; ? char *strset(char *str, char c);

E序?
#include <stdio.h>
#include <string.h>
int main(void)
{
   char string[10] = "123456789";
   char symbol = 'c';
   printf("Before strset(): %sn", string);
   strset(string, symbol);
   printf("After strset():  %sn", string);
   return 0;
}
 
 
 
函数? strspn
?nbsp; ? 在串中查找指定字W集的子集的W一ơ出?
?nbsp; ? int strspn(char *str1, char *str2);

E序?
#include <stdio.h>
#include <string.h>
#include <alloc.h>
int main(void)
{
   char *string1 = "1234567890";
   char *string2 = "123DC8";
   int length;
   length = strspn(string1, string2);
   printf("Character where strings differ is at position %dn", length);
   return 0;
}
 
 
函数? strstr
?nbsp; ? 在串中查找指定字W串的第一ơ出?
?nbsp; ? char *strstr(char *str1, char *str2);

E序?
#include <stdio.h>
#include <string.h>
int main(void)
{
   char *str1 = "Borland International", *str2 = "nation", *ptr;
   ptr = strstr(str1, str2);
   printf("The substring is: %sn", ptr);
   return 0;
}
 
 
函数? strtod
?nbsp; ? 字W串转换为double型?
?nbsp; ? double strtod(char *str, char **endptr);
E序?
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
   char input[80], *endptr;
   double value;
   printf("Enter a floating point number:");
   gets(input);
   value = strtod(input, &endptr);
   printf("The string is %s the number is %lfn", input, value);
   return 0;
}
 
 
 
函数? strtok
?nbsp; ? 查找由在W二个串中指定的分界W分隔开的单?
?nbsp; ? char *strtok(char *str1, char *str2);

E序?
#include <string.h>
#include <stdio.h>
int main(void)
{
   char input[16] = "abc,d";
   char *p;
   /* strtok places a NULL terminator
   in front of the token, if found */
   p = strtok(input, ",");
   if (p)   printf("%sn", p);
   /* A second call to strtok using a NULL
   as the first parameter returns a pointer
   to the character following the token  */
   p = strtok(NULL, ",");
   if (p)   printf("%sn", p);
   return 0;
}
 
 
 
函数? strtol
?nbsp; ? 串转换为长整数
?nbsp; ? long strtol(char *str, char **endptr, int base);

E序?
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
   char *string = "87654321", *endptr;
   long lnumber;
   /* strtol converts string to long integer  */
   lnumber = strtol(string, &endptr, 10);
   printf("string = %s  long = %ldn", string, lnumber);
   return 0;
}
 
函数? strupr
?nbsp; ? 串中的写字母转换为大写字?
?nbsp; ? char *strupr(char *str);

E序?
#include <stdio.h>
#include <string.h>
int main(void)
{
   char *string = "abcdefghijklmnopqrstuvwxyz", *ptr;
   /* converts string to upper case characters */
   ptr = strupr(string);
   printf("%sn", ptr);
   return 0;
}
 
 
 
函数? swab
?nbsp; ? 交换字节
?nbsp; ? void swab (char *from, char *to, int nbytes);

E序?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char source[15] = "rFna koBlrna d";
char target[15];
int main(void)
{
   swab(source, target, strlen(source));
   printf("This is target: %sn", target);
   return 0;
}



PS:isalpha()是字W函敎ͼ不是字符串函敎ͼ

isalpha
 


  原型Qextern int isalpha(int c);
 
  用法Q?include <ctype.h>
 
  功能Q判断字Wc是否文字?br> 
  说明Q当c文字母a-z或A-ZӞq回非零|否则q回?/span>?br> 
  举例Q?br>
      // isalpha.c
     
      #include <syslib.h>
      #include <ctype.h>
      #include <stdio.h>

      main()
      {
        int c;
       
        clrscr();        // clear screen
        printf("Press a key");
        for(;;)
        {
          c=getchar();
          clrscr();
          printf("%c: %s letter",c,isalpha(c)?"is":"not");
        }
        return 0; // just to avoid warnings by compiler
      }



心羽 2010-04-25 02:07 发表评论
]]>
þþþþAv뾫Ʒר| þþþþþþŮ| ٸ߳ҽоþþþþ| þó˹Ʒ| Ʒþþþþ³| þˬˬƬAV鷳| ޾ƷĻþò| 91þþƷһ| þ91ᆱƷ2020| ɫۺϾþ88ɫۺ | ޺ݺۺϾþѿ| þþƷAV鶹 | Ʒ˾þþþӰԺ| ۿþ| þþƷѹۿͬ| վþþ| ۺϾþһ | ƷһþþƷɬ| þŷƷ| һaƬþëƬ| Ӱ7777þþƷˬ| ƷŷþþӰ| ˾þô߽ۺ5g| ɫ꼤þۺ| ɫþþۺƷ | þAVij| 99Ʒþþþþþó| ŷҹAŴƬþ| þþþþþۺ| ޾Ʒþþþþ| ɫ͵͵91þۺ| ܻƺ۵վþmimiɫ| 99999þþþþ| ˳˳ۺþþ| ޹þþþþþ | ŷþ18| þþ99Ʒһ| ƷžžþþƷŮͬŷպۺ | ޹˾þһҳ| þþƷһ| Ʒ˿þþþþò|