﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Carrie--认清目标，坚持到底，永不放弃！-随笔分类-C语言</title><link>http://www.cppblog.com/Carriexiaxia/category/16388.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 03 Jan 2013 13:19:19 GMT</lastBuildDate><pubDate>Thu, 03 Jan 2013 13:19:19 GMT</pubDate><ttl>60</ttl><item><title>关于memset函数，按位与 操作函数</title><link>http://www.cppblog.com/Carriexiaxia/archive/2012/12/25/196622.html</link><dc:creator>Carrie</dc:creator><author>Carrie</author><pubDate>Tue, 25 Dec 2012 13:27:00 GMT</pubDate><guid>http://www.cppblog.com/Carriexiaxia/archive/2012/12/25/196622.html</guid><wfw:comment>http://www.cppblog.com/Carriexiaxia/comments/196622.html</wfw:comment><comments>http://www.cppblog.com/Carriexiaxia/archive/2012/12/25/196622.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Carriexiaxia/comments/commentRss/196622.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Carriexiaxia/services/trackbacks/196622.html</trackback:ping><description><![CDATA[memset第二个参数是字节<img src ="http://www.cppblog.com/Carriexiaxia/aggbug/196622.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Carriexiaxia/" target="_blank">Carrie</a> 2012-12-25 21:27 <a href="http://www.cppblog.com/Carriexiaxia/archive/2012/12/25/196622.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C语言编程（三）</title><link>http://www.cppblog.com/Carriexiaxia/archive/2012/12/07/196092.html</link><dc:creator>Carrie</dc:creator><author>Carrie</author><pubDate>Fri, 07 Dec 2012 13:13:00 GMT</pubDate><guid>http://www.cppblog.com/Carriexiaxia/archive/2012/12/07/196092.html</guid><wfw:comment>http://www.cppblog.com/Carriexiaxia/comments/196092.html</wfw:comment><comments>http://www.cppblog.com/Carriexiaxia/archive/2012/12/07/196092.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Carriexiaxia/comments/commentRss/196092.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Carriexiaxia/services/trackbacks/196092.html</trackback:ping><description><![CDATA[今天做了这样一个实验
定义了一个结构体数组，居然编译不过，百思不得其解，百度后得释。

typedef struct tagTDefStruct
{
    int a[10];
}TDefStruct[10];

memset(TDefStruct, 0, 10*sizeof(TDefStruct));       -----这个到底要怎么初始化 memset(TDefStruct, 0, sizeof(TDefStruct));?????

编译出现错误:parse error before 。。。

这是为啥呢？我看人家代码就是这样写的呢，可以正常运行啊，为什么连编译都不过。

百度结果：
这证明你使用的编译器只支持C89标准。
这个C标准要求在一个块内的变量的声明放在所有非声明语句的前面。
C99及C++标准无此限制。

之后，
就把代码改成如下方式：
typedef struct tagTDefStruct
{
    int a[10];
}TDefStruct;

TDefStruct tDefStruct[10];
memset(tDefStruct, 0, 10*sizeof(TDefStruct));  

OK 编译通过。  <img src ="http://www.cppblog.com/Carriexiaxia/aggbug/196092.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Carriexiaxia/" target="_blank">Carrie</a> 2012-12-07 21:13 <a href="http://www.cppblog.com/Carriexiaxia/archive/2012/12/07/196092.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C语言编程（二）---1.关于指针，指针作为函数形参，实参；2.指针和数组的关系，相互赋值；3.memset用于结构体</title><link>http://www.cppblog.com/Carriexiaxia/archive/2012/12/06/196052.html</link><dc:creator>Carrie</dc:creator><author>Carrie</author><pubDate>Thu, 06 Dec 2012 12:16:00 GMT</pubDate><guid>http://www.cppblog.com/Carriexiaxia/archive/2012/12/06/196052.html</guid><wfw:comment>http://www.cppblog.com/Carriexiaxia/comments/196052.html</wfw:comment><comments>http://www.cppblog.com/Carriexiaxia/archive/2012/12/06/196052.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Carriexiaxia/comments/commentRss/196052.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Carriexiaxia/services/trackbacks/196052.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/Carriexiaxia/archive/2012/12/06/196052.html'>阅读全文</a><img src ="http://www.cppblog.com/Carriexiaxia/aggbug/196052.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Carriexiaxia/" target="_blank">Carrie</a> 2012-12-06 20:16 <a href="http://www.cppblog.com/Carriexiaxia/archive/2012/12/06/196052.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内存</title><link>http://www.cppblog.com/Carriexiaxia/archive/2012/12/05/196024.html</link><dc:creator>Carrie</dc:creator><author>Carrie</author><pubDate>Wed, 05 Dec 2012 14:32:00 GMT</pubDate><guid>http://www.cppblog.com/Carriexiaxia/archive/2012/12/05/196024.html</guid><wfw:comment>http://www.cppblog.com/Carriexiaxia/comments/196024.html</wfw:comment><comments>http://www.cppblog.com/Carriexiaxia/archive/2012/12/05/196024.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Carriexiaxia/comments/commentRss/196024.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Carriexiaxia/services/trackbacks/196024.html</trackback:ping><description><![CDATA[动态内存
静态内存

地址空间。<img src ="http://www.cppblog.com/Carriexiaxia/aggbug/196024.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Carriexiaxia/" target="_blank">Carrie</a> 2012-12-05 22:32 <a href="http://www.cppblog.com/Carriexiaxia/archive/2012/12/05/196024.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>大端模式 小端模式</title><link>http://www.cppblog.com/Carriexiaxia/archive/2012/12/05/196023.html</link><dc:creator>Carrie</dc:creator><author>Carrie</author><pubDate>Wed, 05 Dec 2012 14:31:00 GMT</pubDate><guid>http://www.cppblog.com/Carriexiaxia/archive/2012/12/05/196023.html</guid><wfw:comment>http://www.cppblog.com/Carriexiaxia/comments/196023.html</wfw:comment><comments>http://www.cppblog.com/Carriexiaxia/archive/2012/12/05/196023.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Carriexiaxia/comments/commentRss/196023.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Carriexiaxia/services/trackbacks/196023.html</trackback:ping><description><![CDATA[ 大端模式:
低地址放高字节
高地址放低字节<img src ="http://www.cppblog.com/Carriexiaxia/aggbug/196023.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Carriexiaxia/" target="_blank">Carrie</a> 2012-12-05 22:31 <a href="http://www.cppblog.com/Carriexiaxia/archive/2012/12/05/196023.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>常用的C函数原型 ---从清0函数，拷贝函数开始学（一）</title><link>http://www.cppblog.com/Carriexiaxia/archive/2012/12/05/196017.html</link><dc:creator>Carrie</dc:creator><author>Carrie</author><pubDate>Wed, 05 Dec 2012 14:19:00 GMT</pubDate><guid>http://www.cppblog.com/Carriexiaxia/archive/2012/12/05/196017.html</guid><description><![CDATA[1. memset
C需要的头文件 <string.h>
C++需要的头文件 <cstring>
原型：void memset(void *buffer, int c,  int count);
功能：把buffer所指向的内存区域的前count个字节都赋值为c
        它是对较大的一块指针或者数组进行清0最快的方法。
说明：返回指向buffer的地址。
注意：这里的count一定是字节大小；
memset是对字节进行操作的，对非字符型数组赋初值不可取，清0倒无所谓：
比如》》》不能正确赋值
count = sizeof(a) 指的是a的字节数
sizeof(char) = 1???

百度百科 http://baike.baidu.com/view/982208.htm


例子：
比如对一个结构体赋初值为0xff;
对一个动态获取的内存赋初值为0x0;
对指针赋初值，防止size错误；
对数组赋初值为0xff
对结构体清0
对结构体的数组清0



　第二： 过度使用memset，我想这些程序员可能有某种心理阴影，他们惧怕未经初始化的内存，所以他们会写出这样的代码： 　　char buffer[20]; 　　memset(buffer,0,sizeof((char)*20））； 　　strcpy(buffer,"123"); 　　这里的memset是多余的. 因为这块内存马上就被覆盖了，清零没有意义. ？？ buffer第四字节往后都会写成0吗？

2.memcpy
原型
功能
说明

3.strcpy


4.memmove
原型：memmove();

       <img src ="http://www.cppblog.com/Carriexiaxia/aggbug/196017.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Carriexiaxia/" target="_blank">Carrie</a> 2012-12-05 22:19 <a href="http://www.cppblog.com/Carriexiaxia/archive/2012/12/05/196017.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>函数的形参（非引用形参、指针形参、引用形参）</title><link>http://www.cppblog.com/Carriexiaxia/archive/2011/06/10/148469.html</link><dc:creator>Carrie</dc:creator><author>Carrie</author><pubDate>Fri, 10 Jun 2011 13:56:00 GMT</pubDate><guid>http://www.cppblog.com/Carriexiaxia/archive/2011/06/10/148469.html</guid><wfw:comment>http://www.cppblog.com/Carriexiaxia/comments/148469.html</wfw:comment><comments>http://www.cppblog.com/Carriexiaxia/archive/2011/06/10/148469.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Carriexiaxia/comments/commentRss/148469.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Carriexiaxia/services/trackbacks/148469.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 一、非引用形参<br><br>      void add1(int v1)<br>      {<br>          v1+=1;<br>      }<br><br>      这是最普通的形参方式，当函数被调用时，实参的副本初始化形参，函数并没有访问调用所传递的实参，因此v1+=1不会修改实参的值。对v1的操作只是修改了实参的一个副本。&nbsp;&nbsp;<a href='http://www.cppblog.com/Carriexiaxia/archive/2011/06/10/148469.html'>阅读全文</a><img src ="http://www.cppblog.com/Carriexiaxia/aggbug/148469.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Carriexiaxia/" target="_blank">Carrie</a> 2011-06-10 21:56 <a href="http://www.cppblog.com/Carriexiaxia/archive/2011/06/10/148469.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>引用 C 语言的位域结构应用说明</title><link>http://www.cppblog.com/Carriexiaxia/archive/2011/06/10/148468.html</link><dc:creator>Carrie</dc:creator><author>Carrie</author><pubDate>Fri, 10 Jun 2011 13:48:00 GMT</pubDate><guid>http://www.cppblog.com/Carriexiaxia/archive/2011/06/10/148468.html</guid><wfw:comment>http://www.cppblog.com/Carriexiaxia/comments/148468.html</wfw:comment><comments>http://www.cppblog.com/Carriexiaxia/archive/2011/06/10/148468.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Carriexiaxia/comments/commentRss/148468.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Carriexiaxia/services/trackbacks/148468.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 这个要不是看PIC的编程说明，还真不知道有这种结构，孤陋寡闻啊，网上查了一下，转载一些基础说明文档。<br><br>位域 <br><br>　　有些信息在存储时，并不需要占用一个完整的字节， 而只需占几个或一个二进制位。例如在存放一个开关量时，只有0和1 两种状态， 用一位二进位即可。为了节省存储空间，并使处理简便，C语言又提供了一种数据结构，称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域，并说明每个区域的位数。每个域有一个域名，允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿，其形式为： <br>&nbsp;&nbsp;<a href='http://www.cppblog.com/Carriexiaxia/archive/2011/06/10/148468.html'>阅读全文</a><img src ="http://www.cppblog.com/Carriexiaxia/aggbug/148468.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Carriexiaxia/" target="_blank">Carrie</a> 2011-06-10 21:48 <a href="http://www.cppblog.com/Carriexiaxia/archive/2011/06/10/148468.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>引用 C 语言结构体学习</title><link>http://www.cppblog.com/Carriexiaxia/archive/2011/06/10/148467.html</link><dc:creator>Carrie</dc:creator><author>Carrie</author><pubDate>Fri, 10 Jun 2011 13:46:00 GMT</pubDate><guid>http://www.cppblog.com/Carriexiaxia/archive/2011/06/10/148467.html</guid><wfw:comment>http://www.cppblog.com/Carriexiaxia/comments/148467.html</wfw:comment><comments>http://www.cppblog.com/Carriexiaxia/archive/2011/06/10/148467.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Carriexiaxia/comments/commentRss/148467.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Carriexiaxia/services/trackbacks/148467.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1.直接声明结构体变量：<br><br>struct{<br>int length;<br>int width;<br>}box1;<br><br>这样就声明了一个名为box1的结构体变量，但是同时要注意，如果在同一个程序中还存在如下的声明：<br><br>struct{<br>int length;<br>int width;<br>}box2;<br><br>请千万不要认为这个时候box1和box2是两个相同类型的变量，如果你尝试将box1赋值给box2，你将会发现编译器会给你一个错误提示：incompatible types in assignment ，说明两个两个变量的类型是不同的<br><br>&nbsp;&nbsp;<a href='http://www.cppblog.com/Carriexiaxia/archive/2011/06/10/148467.html'>阅读全文</a><img src ="http://www.cppblog.com/Carriexiaxia/aggbug/148467.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Carriexiaxia/" target="_blank">Carrie</a> 2011-06-10 21:46 <a href="http://www.cppblog.com/Carriexiaxia/archive/2011/06/10/148467.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 字符串 指针 数组 收藏</title><link>http://www.cppblog.com/Carriexiaxia/archive/2011/05/22/146940.html</link><dc:creator>Carrie</dc:creator><author>Carrie</author><pubDate>Sun, 22 May 2011 12:34:00 GMT</pubDate><guid>http://www.cppblog.com/Carriexiaxia/archive/2011/05/22/146940.html</guid><wfw:comment>http://www.cppblog.com/Carriexiaxia/comments/146940.html</wfw:comment><comments>http://www.cppblog.com/Carriexiaxia/archive/2011/05/22/146940.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Carriexiaxia/comments/commentRss/146940.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Carriexiaxia/services/trackbacks/146940.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.cppblog.com/Carriexiaxia/archive/2011/05/22/146940.html'>阅读全文</a><img src ="http://www.cppblog.com/Carriexiaxia/aggbug/146940.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Carriexiaxia/" target="_blank">Carrie</a> 2011-05-22 20:34 <a href="http://www.cppblog.com/Carriexiaxia/archive/2011/05/22/146940.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Struct 结构体疑惑（c语言）</title><link>http://www.cppblog.com/Carriexiaxia/archive/2011/05/22/146939.html</link><dc:creator>Carrie</dc:creator><author>Carrie</author><pubDate>Sun, 22 May 2011 12:29:00 GMT</pubDate><guid>http://www.cppblog.com/Carriexiaxia/archive/2011/05/22/146939.html</guid><wfw:comment>http://www.cppblog.com/Carriexiaxia/comments/146939.html</wfw:comment><comments>http://www.cppblog.com/Carriexiaxia/archive/2011/05/22/146939.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Carriexiaxia/comments/commentRss/146939.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Carriexiaxia/services/trackbacks/146939.html</trackback:ping><description><![CDATA[<span style="widows: 2; text-transform: none; text-indent: 0px; border-collapse: separate; font: medium Simsun; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(0,0,0); word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px"><span style="text-align: left; line-height: 18px; font-family: verdana, sans-serif; font-size: 12px"> 
<h1><img style="border-right-width: 0px; margin: 0px 5px 0px -20px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="原创" src="http://www.cppblog.com/images/authorship.gif" width="15" height="15" />&nbsp; Struct 结构体疑惑（c语言）&nbsp;<cite style="padding-bottom: 0px; font-style: normal; margin: 0px 0px 0px 5px; padding-left: 0px; padding-right: 0px; display: inline; text-decoration: none; padding-top: 0px"><a style="background-image: url(http://blog.csdn.net/images/share-add.gif); padding-bottom: 1px; padding-left: 10px; padding-right: 25px; background-repeat: no-repeat; font: 12px Tahoma, sans-serif; background-position: 0px 0px; color: rgb(51,102,153); text-decoration: none; padding-top: 1px; -webkit-background-clip: initial; -webkit-background-origin: initial" title="收藏到我的网摘中，并分享给我的朋友" href="javascript:d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(saveit=window.open('http://wz.csdn.net/storeit.aspx?t='+escape(d.title)+'&amp;u='+escape(d.location.href)+'&amp;c='+escape(t),'saveit','scrollbars=no,width=590,height=300,left=75,top=20,status=no,resizable=yes'));saveit.focus();">收藏</a></cite></h1>
<div style="line-height: 21px; width: 732px; float: left; font-size: 14px">&nbsp; 
<p style="padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 24px">Struct&nbsp;</span><span style="line-height: 24px; font-family: 宋体">结构体疑惑（</span><span style="line-height: 24px">c</span><span style="line-height: 24px; font-family: 宋体">语言）</span></p>
<p style="padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px">&nbsp;</span></p>
<p style="padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">&nbsp;</p>
<p style="padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px; font-family: 宋体">（如有错，请务必指正）</span></p>
<p style="padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">&nbsp;</p>
<p style="padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 24px; font-family: 宋体">本文主要介绍在</span><span style="line-height: 24px">struct&nbsp;</span><span style="line-height: 24px; font-family: 宋体">结构体中对数组和指针的操作细节。</span></p>
<p style="padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">&nbsp;</p>
<p style="padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px; font-family: 宋体">我们需要明确两个概念：</span></p>
<p style="padding-bottom: 0px; text-indent: -18pt; margin: 0cm 0cm 0pt 34.5pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px"><span style="line-height: 21px">a、<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;</span></span></span><span style="line-height: 21px; font-family: 宋体">初始化：分配内存并写入值。</span></p>
<p style="padding-bottom: 0px; text-indent: -18pt; margin: 0cm 0cm 0pt 34.5pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px"><span style="line-height: 21px">b、<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;</span></span></span><span style="line-height: 21px; font-family: 宋体">赋值：</span><span style="line-height: 21px"><span style="line-height: 21px">&nbsp;&nbsp;</span></span><span style="line-height: 21px; font-family: 宋体">查找内存并写入值。</span></p>
<p style="padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">&nbsp;</p>
<p style="padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 24px"><span style="line-height: 24px">&nbsp;&nbsp;&nbsp;</span></span><span style="line-height: 24px; font-family: 宋体">在上一篇文章有提到数组和指针的初始化和赋值问题，对于数组，可以初始化，但不能对整个数组赋值，而指针，可以初始化也可以赋值。</span></p>
<p style="padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px">&nbsp;</p>
<p style="padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 24px"><span style="line-height: 24px">&nbsp;&nbsp;&nbsp;</span></span><span style="line-height: 24px; font-family: 宋体">在结构体中，数组和指针最大的的区别为：数组将信息存在结构体所占有的内存中，而指针是将信息的首地址保存在结构体所占有的内存中，例如：</span></p>
<p style="padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px"><span style="line-height: 24px">&nbsp;&nbsp;&nbsp;</span>typedef<span style="line-height: 24px">&nbsp;&nbsp;</span>struct name{</span></p>
<p style="padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px"><span style="line-height: 24px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>char a[20];</span></p>
<p style="padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px"><span style="line-height: 24px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>char *p;</span></p>
<p style="padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px">}Name;</span></p>
<p style="padding-bottom: 0px; text-indent: 15.75pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 24px">Name A={&#8220;Llilonglin&#8221;,</span><span style="line-height: 24px; font-family: 宋体">&#8220;</span><span style="line-height: 24px">Llilonglin&#8221;}</span><span style="line-height: 24px; font-family: 宋体">；</span></p>
<p style="padding-bottom: 0px; text-indent: 15.75pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 24px; font-family: 宋体">结构体对象</span><span style="line-height: 24px">A</span><span style="line-height: 24px; font-family: 宋体">中的数组会将字符串常量&#8220;</span><span style="line-height: 24px">Lilonglin</span><span style="line-height: 24px; font-family: 宋体">&#8221;</span><span style="line-height: 24px">COPY</span><span style="line-height: 24px; font-family: 宋体">到</span><span style="line-height: 24px">A</span><span style="line-height: 24px; font-family: 宋体">的存储内存中，而</span><span style="line-height: 24px">A</span><span style="line-height: 24px; font-family: 宋体">中的指针只保存字符串常量在静态常量存储区中的首地址。</span></p>
<p style="padding-bottom: 0px; text-indent: 15.75pt; padding-left: 0px; padding-right: 0px; padding-top: 0px">&nbsp;</p>
<p style="padding-bottom: 0px; text-indent: 15.75pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px; font-family: 宋体">在结构体中对数组的初始化和赋值有以下需要注意：</span></p>
<p style="padding-bottom: 0px; text-indent: -21pt; margin: 0cm 0cm 0pt 36.75pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 24px"><span style="line-height: 24px">一、</span></span><span style="line-height: 24px; font-family: 宋体">赋值</span></p>
<p style="padding-bottom: 0px; margin: 0cm 0cm 0pt 36.75pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 24px; font-family: 宋体">例如</span>&nbsp;<span style="line-height: 24px; font-family: 宋体">定义结构体对象</span></p>
<p style="padding-bottom: 0px; margin: 0cm 0cm 0pt 36.75pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px"><span style="line-height: 24px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>Name A;</span></p>
<p style="padding-bottom: 0px; text-indent: 21pt; margin: 0cm 0cm 0pt 36.75pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 24px; font-family: 宋体">在使用时，编译器将会为该结构体分配内存空间，但为对结构对象</span><span style="line-height: 24px">A</span><span style="line-height: 24px; font-family: 宋体">的变量初始化。</span>&nbsp;<span style="line-height: 24px; font-family: 宋体">此时只能通过赋值操作来写入值。在对数组</span><span style="line-height: 24px">a[10]</span><span style="line-height: 24px; font-family: 宋体">的赋值时应谨慎，例如：</span></p>
<p style="padding-bottom: 0px; text-indent: -30.75pt; margin: 0cm 0cm 0pt 88.5pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px"><span style="line-height: 21px">A.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></span><span style="line-height: 24px">A.a[10]=&#8221;Lilonglin&#8221;, gcc</span><span style="line-height: 24px; font-family: 宋体">将给出警告</span>&nbsp;<span style="line-height: 21px; font-family: 宋体">：&#8220;赋值时将指针赋给整数，未作类型转换&#8221;，该警告主要由两个原因引起：</span><span style="line-height: 24px">1</span><span style="line-height: 24px; font-family: 宋体">、</span>&nbsp;<span style="line-height: 24px; font-family: 宋体">&#8220;</span><span style="line-height: 24px">.</span><span style="line-height: 21px; font-family: 宋体">&#8221;结构体成员运算符的作用是访问结构体中个成员，该处操作的是结构体变量</span><span style="line-height: 21px">A</span><span style="line-height: 21px; font-family: 宋体">中数组的第</span><span style="line-height: 21px">10</span><span style="line-height: 21px; font-family: 宋体">个元素，虽然该下标已经越界；</span><span style="line-height: 24px">2</span><span style="line-height: 24px; font-family: 宋体">、&#8220;</span><span style="line-height: 21px">Lilonglin</span><span style="line-height: 21px; font-family: 宋体">&#8221;在此处编译器理解为一个常指针，指针是不能直接赋值给字符变量的。</span></p>
<p style="padding-bottom: 0px; text-indent: -30.75pt; margin: 0cm 0cm 0pt 88.5pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px"><span style="line-height: 21px">B.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></span><span style="line-height: 24px">A.a=</span><span style="line-height: 24px; font-family: 宋体">&#8220;</span><span style="line-height: 24px">Lilonglin</span><span style="line-height: 24px; font-family: 宋体">&#8221;</span><span style="line-height: 24px">,gcc</span><span style="line-height: 24px; font-family: 宋体">将会提示错误：赋值时，类型不兼容。</span>&nbsp;<span style="line-height: 21px; font-family: 宋体">在定义申明完数组后数组名具有常量特性，表示数组存储空间的开始地址，而</span><span style="line-height: 21px">C</span><span style="line-height: 21px; font-family: 宋体">语言中不能对常量赋值。</span></p>
<p style="padding-bottom: 0px; text-indent: -30.75pt; margin: 0cm 0cm 0pt 88.5pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px"><span style="line-height: 21px">C.<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></span><span style="line-height: 21px; font-family: 宋体">根据数组的特性，如果需要得到对数组的正确赋值，则需要对数组的每个元素进行对应赋值。在此不再举例。</span></p>
<p style="padding-bottom: 0px; text-indent: -21pt; margin: 0cm 0cm 0pt 36.75pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 24px"><span style="line-height: 24px">二、</span></span><span style="line-height: 24px; font-family: 宋体">初始化</span></p>
<p style="padding-bottom: 0px; margin: 0cm 0cm 0pt 36.75pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px; font-family: 宋体">在结构体初始化时，用字符串对数组的初始化也需要有注意的地方，例如：</span></p>
<p style="padding-bottom: 0px; text-indent: -29.25pt; margin: 0cm 0cm 0pt 66pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px"><span style="line-height: 21px">A、<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></span><span style="line-height: 21px">Name A={.a=&#8221;Lilonglin&#8221;}<span style="line-height: 24px">&nbsp;&nbsp;</span>//OK</span></p>
<p style="padding-bottom: 0px; text-indent: -29.25pt; margin: 0cm 0cm 0pt 66pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px"><span style="line-height: 21px">B、<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span></span><span style="line-height: 24px">1</span><span style="line-height: 24px; font-family: 宋体">：</span><span style="line-height: 21px">Name A={.a[10]=&#8221;Lilonglin&#8221;}<span style="line-height: 24px">&nbsp;&nbsp;</span>//error<span style="line-height: 24px">&nbsp;&nbsp;</span>gcc</span><span style="line-height: 21px; font-family: 宋体">提示</span><span style="line-height: 21px">:</span><span style="line-height: 21px; font-family: 宋体">初始化数组索引越界。</span></p>
<p style="padding-bottom: 0px; margin: 0cm 0cm 0pt 66pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 24px">2</span><span style="line-height: 24px; font-family: 宋体">：</span><span style="line-height: 24px">Name A={.a[9]=&#8221;Lilonglin&#8221;}<span style="line-height: 24px">&nbsp;&nbsp;</span>//right<span style="line-height: 24px">&nbsp;&nbsp;</span>printf(&#8220;%s&#8221;,A.a)&nbsp;</span><span style="line-height: 24px; font-family: 宋体">得到&#8220;</span><span style="line-height: 24px">Lilonglin</span><span style="line-height: 24px; font-family: 宋体">&#8221;</span></p>
<p style="padding-bottom: 0px; margin: 0cm 0cm 0pt 66pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 24px">3</span><span style="line-height: 24px; font-family: 宋体">：</span><span style="line-height: 24px">Name A={.a[1]=&#8221;Lilonglin&#8221;}<span style="line-height: 24px">&nbsp;&nbsp;</span>// right<span style="line-height: 24px">&nbsp;&nbsp;</span>printf(&#8220;%s&#8221;,A.a)&nbsp;</span><span style="line-height: 24px; font-family: 宋体">得到&#8220;</span><span style="line-height: 24px">Lilonglin</span><span style="line-height: 24px; font-family: 宋体">&#8221;</span></p>
<p style="padding-bottom: 0px; text-indent: -42pt; margin: 0cm 0cm 0pt 42pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 24px"><span style="line-height: 24px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span><span style="line-height: 24px; font-family: 宋体">为什么在</span><span style="line-height: 24px">1</span><span style="line-height: 24px; font-family: 宋体">中，指定初始化用</span><span style="line-height: 24px">a</span><span style="line-height: 24px; font-family: 宋体">【</span><span style="line-height: 24px">10</span><span style="line-height: 24px; font-family: 宋体">】时，</span><span style="line-height: 24px">gcc</span><span style="line-height: 24px; font-family: 宋体">会提示越界呢。</span>&nbsp;<span style="line-height: 24px; font-family: 宋体">在编译的过程中，在语法扫错阶段</span><span style="line-height: 24px">GCC</span><span style="line-height: 24px; font-family: 宋体">的对数组边界检查时，发现了该错误，从而给出了提示，在</span><span style="line-height: 24px">VC</span><span style="line-height: 24px; font-family: 宋体">下则不会，在此不得不佩服</span><span style="line-height: 24px">GCC</span><span style="line-height: 24px; font-family: 宋体">的严谨。</span></p>
<p style="padding-bottom: 0px; margin: 0cm 0cm 0pt 66pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 24px; font-family: 宋体">从</span><span style="line-height: 24px">2</span><span style="line-height: 24px; font-family: 宋体">和</span><span style="line-height: 24px">3</span><span style="line-height: 24px; font-family: 宋体">我们可以看到当使用不同的下标时对数组的初始化完全没有影响，</span></p>
<p style="padding-bottom: 0px; margin: 0cm 0cm 0pt 36pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 21px; font-family: 宋体">这不得不怀疑在结构体中，用字符串对数组的初始化时只与数组名有关，因为数组名具有指针属性，之后数组的各个元素被初始化，读者可以打印某个数组元素试试。</span></p>
<p style="padding-bottom: 0px; margin: 0cm 0cm 0pt 36pt; padding-left: 0px; padding-right: 0px; padding-top: 0px"><span style="line-height: 24px"><span style="line-height: 24px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span><span style="line-height: 24px; font-family: 宋体">此处只讨论了用字符串初始化的情况，对非字符串时指定初始化时，下标将起作用，大家可以试一试。</span></p></div></span></span><img src ="http://www.cppblog.com/Carriexiaxia/aggbug/146939.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Carriexiaxia/" target="_blank">Carrie</a> 2011-05-22 20:29 <a href="http://www.cppblog.com/Carriexiaxia/archive/2011/05/22/146939.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>already defined in *.obj“符号已定义”问题原理及解决方案</title><link>http://www.cppblog.com/Carriexiaxia/archive/2011/05/22/146921.html</link><dc:creator>Carrie</dc:creator><author>Carrie</author><pubDate>Sun, 22 May 2011 05:47:00 GMT</pubDate><guid>http://www.cppblog.com/Carriexiaxia/archive/2011/05/22/146921.html</guid><wfw:comment>http://www.cppblog.com/Carriexiaxia/comments/146921.html</wfw:comment><comments>http://www.cppblog.com/Carriexiaxia/archive/2011/05/22/146921.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Carriexiaxia/comments/commentRss/146921.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Carriexiaxia/services/trackbacks/146921.html</trackback:ping><description><![CDATA[<font color="#00ffff"><span style="color: #000000">造成LNK2005错误主要有以下几种情况： </span><br /><span style="color: #000000">1．重复定义全局变量。可能存在两种情况： </span><br /><span style="color: #000000">A、对于一些初学编程的程序员，有时候会以为需要使用全局变量的地方就可以使用定义申明一下。其实这是错误的，全局变量是针对整个工程的。正确的应该是在一个CPP文件中定义如下：int g_Test;那么在使用的CPP文件中就应该使用：extern int g_Test即可，如果还是使用int g_Test，那么就会产生LNK2005错误，一般错误错误信息类似：AAA.obj error LNK2005 int book c？</span></font><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#98;&#111;&#111;&#107;&#64;&#64;&#51;&#72;&#65;"><font color="#00ffff"><span style="color: #000000">book@@3HA</span></font></a><font color="#00ffff"><span style="color: #000000"> already defined in BBB.obj。切记的就是不能给变量赋值否则还是会有LNK2005错误。 </span><br /><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这里需要的是&#8220;声明&#8221;，不是&#8220;定义&#8221;！根据C++标准的规定，一个变量是声明，必须同时满足两个条件，否则就是定义： </span><br /><span style="color: #000000">(1)声明必须使用extern关键字；(2)不能给变量赋初值 </span><br /><span style="color: #000000">所以，下面的是声明: </span><br /><span style="color: #000000">extern int a; </span><br /><span style="color: #000000">下面的是定义 </span><br /><span style="color: #000000">int a; int a = 0; extern int a =0; </span><br /><span style="color: #000000">B、对于那么编程不是那么严谨的程序员，总是在需要使用变量的文件中随意定义一个全局变量，并且对于变量名也不予考虑，这也往往容易造成变量名重复，而造成LNK2005错误。 </span><br /><span style="color: #000000">2．头文件的包含重复。往往需要包含的头文件中含有变量、函数、类的定义，在其它使用的地方又不得不多次包含之，如果头文件中没有相关的宏等防止重复链接的措施，那么就会产生LNK2005错误。解决办法是在需要包含的头文件中做类似的处理：#ifndef MY_H_FILE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //如果没有定义这个宏 </span><br /><span style="color: #000000">#define MY_H_FILE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //定义这个宏 </span><br /><span style="color: #000000">&#8230;&#8230;.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //头文件主体内容 </span><br /><span style="color: #000000">&#8230;&#8230;. </span><br /><span style="color: #000000">#endif </span><br /><span style="color: #000000">上面是使用宏来做的，也可以使用预编译来做，在头文件中加入： </span><br /><span style="color: #000000">#pragma once </span><br /><span style="color: #000000">//头文件主体 </span><br /><span style="color: #000000">3．使用第三方的库造成的。这种情况主要是C运行期函数库和MFC的库冲突造成的。具体的办法就是将那个提示出错的库放到另外一个库的前面。另外选择不同的C函数库，可能会引起这个错误。微软和C有两种C运行期函数库，一种是普通的函数库：LIBC.LIB，不支持多线程。另外一种是支持多线程的：msvcrt.lib。如果一个工程里，这两种函数库混合使用，可能会引起这个错误，一般情况下它需要MFC的库先于C运行期函数库被链接，因此建议使用支持多线程的msvcrt.lib。所以在使用第三方的库之前首先要知道它链接的是什么库，否则就可能造成LNK2005错误。如果不得不使用第三方的库，可以尝试按下面所说的方法修改，但不能保证一定能解决问题，前两种方法是微软提供的： </span><br /><span style="color: #000000">A、选择VC菜单Project-&gt;Settings-&gt;Link-&gt;Catagory选择Input，再在Ignore libraries 的Edit栏中填入你需要忽略的库，如：Nafxcwd.lib;Libcmtd.lib。然后在Object/library Modules的Edit栏中填入正确的库的顺序，这里需要你能确定什么是正确的顺序，呵呵，God bless you！ </span><br /><span style="color: #000000">B、选择VC菜单Project-&gt;Settings-&gt;Link页，然后在Project Options的Edit栏中输入/verbose:lib，这样就可以在编译链接程序过程中在输出窗口看到链接的顺序了。 </span><br /><span style="color: #000000">C、选择VC菜单Project-&gt;Settings-&gt;C/C++页，Catagory选择Code Generation后再在User Runtime libraray中选择MultiThread DLL等其他库，逐一尝试。 </span><br /><span style="color: #000000">关于编译器的相关处理过程，参考： </span><br /></font><a href="http://www.donews.net/xzwenlan/archive/2004/12/23/211668.aspx"><font color="#00ffff"><span style="color: #000000">http://www.donews.net/xzwenlan/archive/2004/12/23/211668.aspx</span></font></a><font color="#00ffff"> <br /><span style="color: #000000">这就是我所遇到过的LNK2005错误的几种情况，肯定还有其他的情况也可能造成这种错误，所以我不希望你在看完这篇文章以后，再遇到LNK2005错误时候，不动脑筋的想对号入座的排除错误。编程的过程就是一个思考的过程，所以还是多多开动你的头脑，那样收获会更多！ </span></font>
<p style="text-indent: 2em"><font color="#00ffff"><span style="color: #000000">附录:</span></font></p>
<p style="text-indent: 2em"><font color="#00ffff"><span style="color: #000000">编译器处理相关 </span><br /><span style="color: #000000">一.预处理器-编译器-汇编器-链接器</span><br /><span style="color: #000000">预处理器会处理相关的预处理指令，一般是以"#"开头的指令。如：#include "xx.h" #define等。</span><br /><span style="color: #000000">编译器把对应的*.cpp翻译成*.s文件(汇编语言)。</span><br /><span style="color: #000000">汇编器则处理*.s生成对应的*.o文件(obj目标文件)</span><br /><span style="color: #000000">最后链接器把所有的*.o文件链接成一个可执行文件(?.exe)</span></font></p>
<p style="text-indent: 2em"><font color="#00ffff"><span style="color: #000000">1.部件:</span><br /><span style="color: #000000">首先要知道部件(可以暂且狭义地理解为一个类)一般分为头文件(我喜欢称为接口，如:*.h)及实现文件(如:*.cpp)。</span><br /><span style="color: #000000">一般头文件会是放一些用来作声明的东东作为接口而存在的。</span><br /><span style="color: #000000">而实现文件主要是实现的具体代码。</span></font></p>
<p style="text-indent: 2em"><font color="#00ffff"><span style="color: #000000">2.编译单个文件:</span><br /><span style="color: #000000">记住IDE在bulid文件时只编译实现文件(如*.cpp)来产生obj，在vc下你可以对某个?.cpp按下ctrl+f7单独编译它</span><br /><span style="color: #000000">生成对应一个?.obj文件。在编译?.cpp时IDE会在?.cpp中按顺序处理用#include包括进来的头文件</span><br /><span style="color: #000000">(如果该头文件中又#include有文件，同样会按顺序跟进处理各个头文件，如此递归。。)</span></font></p>
<p style="text-indent: 2em"><font color="#00ffff"><span style="color: #000000">3.内部链接与外部链接:</span><br /><span style="color: #000000">内、外链接是比较基础的东东，但是也是新手最容易错的地方,所以这里有必要祥细讨论一下。</span><br /><span style="color: #000000">内部链接产生的符号只在本地?.obj中可见，而外部链接的符号是所有*.obj之间可见的。</span><br /><span style="color: #000000">如:用inline的是内部链接，在文件头中直接声明的变量、不带inline的全局函数都是外部链接。</span><br /><span style="color: #000000">在文件头中类的内部声明的函数(不带函数体)是外部链接，而带函数体一般会是内部链接(因为IDE会尽量把它作为内联函数)</span><br /><span style="color: #000000">认识内部链接与外部链接有什么作用呢？下面用vc6举个例子：</span><br /><span style="color: #000000">// 文件main.cpp内容:</span><br /><span style="color: #000000">void main(){}</span><br /><span style="color: #000000">// 文件t1.cpp内容:</span><br /><span style="color: #000000">#include "a.h"</span><br /><span style="color: #000000">void Test1(){ Foo(); }</span><br /><span style="color: #000000">// 文件t2.cpp内容:</span><br /><span style="color: #000000">#include "a.h"</span><br /><span style="color: #000000">void Test2(){ Foo(); }</span><br /><span style="color: #000000">// 文件a.h内容:</span><br /><span style="color: #000000">void Foo( ){ }</span><br /><span style="color: #000000">好，用vc生成一个空的console程序(File - new - projects - win32 console application)，并关掉预编译选项开关</span><br /><span style="color: #000000">(project - setting - Cagegoryrecompiled Headers - Not using precompiled headers)</span><br /><span style="color: #000000">现在你打开t1.cpp按ctrl+f7编译生成t1.obj通过</span><br /><span style="color: #000000">打开t2.cpp按ctrl+f7编译生成t2.obj通过</span><br /><span style="color: #000000">而当你链接时会发现:</span><br /><span style="color: #000000">Linking...</span><br /><span style="color: #000000">t2.obj : error LNK2005: "void __cdecl Foo(void)" (</span></font><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#63;&#70;&#111;&#111;&#64;&#64;&#89;&#65;&#88;&#88;&#90;"><font color="#00ffff"><span style="color: #000000">?Foo@@YAXXZ</span></font></a><font color="#00ffff"><span style="color: #000000">) already defined in t1.obj</span><br /><span style="color: #000000">这是因为:</span><br /><span style="color: #000000">1. 编译t1.cpp在处理到#include "a.h"中的Foo时看到的Foo函数原型定义是外部链接的，所以在t1.obj中记录Foo符号是外部的。</span><br /><span style="color: #000000">2. 编译t2.cpp在处理到#include "a.h"中的Foo时看到的Foo函数原型定义是外部链接的，所以在t2.obj中记录Foo符号是外部的。</span><br /><span style="color: #000000">3. 最后在链接 t1.obj 及 t2.obj 时, vc发现有两处地方(t1.obj和t2.obj中)定义了相同的外部符号(注意：是定义，外部符号可以</span><br /><span style="color: #000000">多处声明但不可多处定义，因为外部符号是全局可见的，假设这时有t3.cpp声明用到了这个符号就不知道应该调用t1.obj</span><br /><span style="color: #000000">中的还是t2.obj中的了)，所以会报错。</span><br /><span style="color: #000000">解决的办法有几种: </span><br /><span style="color: #000000">a.将a.h中的定义改写为声明，而用另一个文件a.cpp来存放函数体。(提示：把上述程序改来试试)</span><br /><span style="color: #000000">(函数体放在其它任何一个cpp中如t1.cpp也可以，不过良好的习惯是用对应cpp文件来存放)。</span><br /><span style="color: #000000">这时包括a.h的文件除了a.obj中有函数体代码外，</span><br /><span style="color: #000000">其它包括a.h的cpp生成的obj文件都只有对应的符号而没有函数体，如t1.obj、t2.obj就只有符号，当最后链接时IDE会把</span><br /><span style="color: #000000">a.obj的Foo()函数体链接进exe文件中，并把t1.obj、t2.obj中的Foo符号转换成对应在函数体exe文件中的地址。</span><br /><span style="color: #000000">另外：当变量放在a.h中会变成全局变量的定义，如何让它变为声明呢?</span><br /><span style="color: #000000">例如: 我们在a.h中加入:class CFoo{};CFoo* obj;</span><br /><span style="color: #000000">这时按f7进行build时出现:</span><br /><span style="color: #000000">Linking...</span><br /><span style="color: #000000">t2.obj : error LNK2005: "class CFoo * obj" (</span></font><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#63;&#111;&#98;&#106;&#64;&#64;&#51;&#80;&#65;&#86;&#67;&#70;&#111;&#111;&#64;&#64;&#65;"><font color="#00ffff"><span style="color: #000000">?obj@@3PAVCFoo@@A</span></font></a><font color="#00ffff"><span style="color: #000000">) already defined in t1.obj</span><br /><span style="color: #000000">一个好办法就是在a.cpp中定义此变量( CFoo* obj，然后拷贝此定义到a.h文件中并在前面加上extern(extern CFoo* obj</span><br /><span style="color: #000000">如此就可通过了。当然extern也可以在任何调用此变量的位置之前声明，不过强烈建议不要这么作，因为到处作用extern，会</span><br /><span style="color: #000000">导致接口不统一。良好的习惯是接口一般就放到对应的头文件。</span></font></p>
<p style="text-indent: 2em"><font color="#00ffff"><span style="color: #000000">b. 将a.h中的定义修改成内部链接，即加上inline关键字，这时每个t1.obj和t2.obj都存放有一份Foo函数体，但它们不是外部</span><br /><span style="color: #000000">符号，所以不会被别的obj文件引用到，故不存在冲突。(提示：把上述程序改来试试)</span><br /><span style="color: #000000">另外我作了个实验来验证&#8221;vc是把是否是外部符号的标志记录在obj文件中的&#8220;(有点绕口)。可以看看，如下:</span><br /><span style="color: #000000">(1)文件内容:</span><br /><span style="color: #000000">// 文件main.cpp内容:</span><br /><span style="color: #000000">void main(){}</span><br /><span style="color: #000000">// 文件t1.cpp内容:</span><br /><span style="color: #000000">#include "a.h"</span><br /><span style="color: #000000">void Test1(){ Foo(); }</span><br /><span style="color: #000000">// 文件t2.cpp内容:</span><br /><span style="color: #000000">#include "a.h"</span><br /><span style="color: #000000">void Test2(){ Foo(); }</span><br /><span style="color: #000000">// 文件a.h内容:</span><br /><span style="color: #000000">inline void Foo( ){ }</span><br /><span style="color: #000000">(2) 选t1.cpp按ctrl+f7单独编译,并把编译后的t1.obj修改成t1.obj_inline</span><br /><span style="color: #000000">(3) 选t2.cpp按ctrl+f7单独编译,并把编译后的t2.obj修改成t2.obj_inline</span><br /><span style="color: #000000">(4) 把除了t1.obj_inline及t2.obj_inline外的其它编译生成的文件删除。</span><br /><span style="color: #000000">(5) 修改a.h内容为:void Foo( ){ },使之变为非内联函数作测试</span><br /><span style="color: #000000">(6) rebuild all所有文件。这时提示:</span><br /><span style="color: #000000">Linking...</span><br /><span style="color: #000000">t2.obj : error LNK2005: "void __cdecl Foo(void)" (</span></font><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#63;&#70;&#111;&#111;&#64;&#64;&#89;&#65;&#88;&#88;&#90;"><font color="#00ffff"><span style="color: #000000">?Foo@@YAXXZ</span></font></a><font color="#00ffff"><span style="color: #000000">) already defined in t1.obj</span><br /><span style="color: #000000">Debug/cle.exe : fatal error LNK1169: one or more multiply defined symbols found</span><br /><span style="color: #000000">(7) 好，看看工程目录下的debug目录中会看到新生成的obj文件。</span><br /><span style="color: #000000">下面我们来手工链接看看，</span><br /><span style="color: #000000">打开菜单中的project - setting - Link,拷贝Project options下的所有内容,如下:</span><br /><span style="color: #000000">kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:yes /pdb:"Debug/cle.pdb" /debug /machine:I386 /out:"Debug/cle.exe" /pdbtype:sept </span><br /><span style="color: #000000">把它修改成:</span><br /><span style="color: #000000">Link.exe kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:yes /pdb:"Debug/cle.pdb" /debug /machine:I386 /out:"Debug/cle.exe" /pdbtype:sept Debug/t1.obj Debug/t2.obj Debug/main.obj</span><br /><span style="color: #000000">pause</span><br /><span style="color: #000000">注意前面多了Link.exe，后面多了Debug/t1.obj Debug/t2.obj Debug/main.obj以及</span><br /><span style="color: #000000">最后一个pause批处理命令，然后把它另存到工程目录(此目录下会看到debug目录)下起名为link.bat</span><br /><span style="color: #000000">运行它，就会看到:</span><br /><span style="color: #000000">t2.obj : error LNK2005: "void __cdecl Foo(void)" (</span></font><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#63;&#70;&#111;&#111;&#64;&#64;&#89;&#65;&#88;&#88;&#90;"><font color="#00ffff"><span style="color: #000000">?Foo@@YAXXZ</span></font></a><font color="#00ffff"><span style="color: #000000">) already defined i</span><br /><span style="color: #000000">n t1.obj</span><br /><span style="color: #000000">Debug/cle.exe : fatal error LNK1169: one or more multiply defined symbols found</span><br /><span style="color: #000000">很好，我们链接原来的obj文件得到的效果跟在vc中用rebuild all出来的效果一样。那么现在如果</span><br /><span style="color: #000000">我们把备份出来的t1.obj_inline覆盖t1.obj而t2.obj_inline覆盖t2.obj再手动链接应该会是</span><br /><span style="color: #000000">不会出错的，因为原t1.obj_inline及t2.obj_inline中存放的是内部链接符号。好运行Link.bat，果然</span><br /><span style="color: #000000">不出所料，链接成功了，看看debug目录下多出了一个exe文件。这就说明了内或外符号在obj有标志标识!</span><br /><span style="color: #000000">(提示：上述为什么不用vc的f7build链接呢,因为文件时间改变了，build会重新生成新的obj，</span><br /><span style="color: #000000">所以我们用手动链接保证obj不变)[注bj信息可用dumpbin.exe查看]</span></font></p>
<p style="text-indent: 2em"><br /><font color="#00ffff"><span style="color: #000000">4.#include规则:</span><br /><span style="color: #000000">有很多人不知道#include 文件该放在何处？</span></font></p>
<p style="text-indent: 2em"><font color="#00ffff"><span style="color: #000000">1). 增强部件自身的完整性：</span><br /><span style="color: #000000">为了保证部件完整，部件的cpp实现文件(如test.cpp)中第一个#include的应当是它自身对应的头文件(如test.h)。</span><br /><span style="color: #000000">(除非你用预编译头文件, 预编译头必须放在第一个)。这样就保证了该部件头文件(test.h)所必须依赖的其它接口(如a.h等)要放到它对应的文件头中(test.h),而不是在cpp中(test.cpp)把所依赖的其它头文件(a.h等)移到其自身对应的头文件(test.h等)之前（因为这样强迫其它包括此部件的头文件(test.h)的文件(b.cpp)也必须再写一遍include(即b.cpp若要#include "test.h"也必须#include "a.h")&#8221;。另外我们一般会尽量减少文件头之间的依赖关系，看下面：</span></font></p>
<p style="text-indent: 2em"><font color="#00ffff"><span style="color: #000000">2). 减少部件之间的依赖性：</span><br /><span style="color: #000000">在1的基础上尽量把#include到的文件放在cpp中包括。</span><br /><span style="color: #000000">这就要求我们一般不要在头文件中直接引用其它变量的实现，而是把此引用搬到实现文件中。</span><br /><span style="color: #000000">例如: </span><br /><span style="color: #000000">// 文件foo.h:</span><br /><span style="color: #000000">class CFoo{</span><br /><span style="color: #000000">void Foo(){}</span><br /><span style="color: #000000">};</span><br /><span style="color: #000000">// 文件test.h:</span><br /><span style="color: #000000">#include "foo.h"</span><br /><span style="color: #000000">class CTest{</span><br /><span style="color: #000000">CFoo* m_pFoo;</span><br /><span style="color: #000000">public:</span><br /><span style="color: #000000">CTest() : m_pFoo(NULL){}</span><br /><span style="color: #000000">void Test(){ if(m_pFoo){ m_pFoo-&gt;Foo();}}</span><br /><span style="color: #000000">...........</span><br /><span style="color: #000000">};</span><br /><span style="color: #000000">// 文件test.cpp:</span><br /><span style="color: #000000">#include "test.h"</span><br /><span style="color: #000000">.....</span></font></p>
<p style="text-indent: 2em"><font color="#00ffff"><span style="color: #000000">如上文件test.h中我们其实可以#include "foo.h"移到test.cpp文件中。因为CFoo* m_pFoo我们只想在部件CTest中用到,</span><br /><span style="color: #000000">而将来想用到CTest部件而包括test.h的其它部件没有必要见到foo.h接口，所以我们用前向声明修改原文件如下:</span><br /><span style="color: #000000">// 文件foo.h:</span><br /><span style="color: #000000">class CFoo{</span><br /><span style="color: #000000">public:</span><br /><span style="color: #000000">void Foo(){}</span><br /><span style="color: #000000">};</span><br /><span style="color: #000000">// 文件test.h:</span><br /><span style="color: #000000">class CFoo;</span><br /><span style="color: #000000">class CTest{</span><br /><span style="color: #000000">CFoo* m_pFoo;</span><br /><span style="color: #000000">public:</span><br /><span style="color: #000000">CTest();</span><br /><span style="color: #000000">void Test();</span><br /><span style="color: #000000">//........</span><br /><span style="color: #000000">};</span><br /><span style="color: #000000">// 文件test.cpp:</span><br /><span style="color: #000000">#include "test.h" // 这里第一个放该部件自身对应的接口头文件</span><br /><span style="color: #000000">#include "foo.h" // 该部件用到了foo.h</span><br /><span style="color: #000000">CTest::CTest() : m_pFoo(0){ </span><br /><span style="color: #000000">m_pFoo = new CFoo; </span><br /><span style="color: #000000">}</span><br /><span style="color: #000000">void CTest::Test(){ </span><br /><span style="color: #000000">if(m_pFoo){ </span><br /><span style="color: #000000">m_pFoo-&gt;Foo();</span><br /><span style="color: #000000">}</span><br /><span style="color: #000000">}</span><br /><span style="color: #000000">//.....</span><br /><span style="color: #000000">// 再加上main.cpp来测试:</span><br /><span style="color: #000000">#include "test.h" // 这里我们就不用见到#include "foo.h"了</span><br /><span style="color: #000000">CTest test;</span><br /><span style="color: #000000">void main(){</span><br /><span style="color: #000000">test.Test();</span><br /><span style="color: #000000">}</span></font></p>
<p style="text-indent: 2em"><font color="#00ffff"><span style="color: #000000">3). 双重包含卫哨:</span><br /><span style="color: #000000">在文件头中包括其它头文件时(如：#include "xx.h")建议也加上包含卫哨:</span><br /><span style="color: #000000">// test.h文件内容:</span><br /><span style="color: #000000">#ifndef __XX1_H_</span><br /><span style="color: #000000">#include "xx1.h"</span><br /><span style="color: #000000">#endif</span><br /><span style="color: #000000">#ifndef __XX2_H_</span><br /><span style="color: #000000">#include "xx2.h"</span><br /><span style="color: #000000">#endif</span><br /><span style="color: #000000">...... </span></font></p>
<p style="text-indent: 2em"><font color="#00ffff"><span style="color: #000000">虽然我们已经在xx.h文件中开头已经加过，但是因为编译器在打开#include文件也</span><br /><span style="color: #000000">是需要时间的，如果在外部加上包含卫哨，对于很大的工程可以节省更多的编译时间。</span></font></p><img src ="http://www.cppblog.com/Carriexiaxia/aggbug/146921.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Carriexiaxia/" target="_blank">Carrie</a> 2011-05-22 13:47 <a href="http://www.cppblog.com/Carriexiaxia/archive/2011/05/22/146921.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>