??xml version="1.0" encoding="utf-8" standalone="yes"?>日产亚洲一区二区三区,亚洲片一区二区三区,久久久久亚洲AV无码专区首JN http://m.tkk7.com/Archangelsy/category/20558.htmlLSY zh-cn Fri, 21 Sep 2007 05:52:36 GMT Fri, 21 Sep 2007 05:52:36 GMT 60 C~程手册 http://m.tkk7.com/Archangelsy/articles/146413.htmlarchangel archangel Wed, 19 Sep 2007 04:25:00 GMT http://m.tkk7.com/Archangelsy/articles/146413.html http://m.tkk7.com/Archangelsy/comments/146413.html http://m.tkk7.com/Archangelsy/articles/146413.html#Feedback 0 http://m.tkk7.com/Archangelsy/comments/commentRss/146413.html http://m.tkk7.com/Archangelsy/services/trackbacks/146413.html 阅读全文 ]]> ODBC驱动E序不支持动态记录集 http://m.tkk7.com/Archangelsy/articles/146183.htmlarchangel archangel Tue, 18 Sep 2007 07:47:00 GMT http://m.tkk7.com/Archangelsy/articles/146183.html http://m.tkk7.com/Archangelsy/comments/146183.html http://m.tkk7.com/Archangelsy/articles/146183.html#Feedback 0 http://m.tkk7.com/Archangelsy/comments/commentRss/146183.html http://m.tkk7.com/Archangelsy/services/trackbacks/146183.html CSetSourCertInfo certinfo(g_pDB); if(!certinfo.Open(CRecordset::dynaset,NULL,CRecordset::none)) { return; } Open时会报出pȝ错误 后来发现Q把dynasetҎ(gu)snapshot可以了Q动态不支持动态记录集Q! ]]> LNK2005 原因 http://m.tkk7.com/Archangelsy/articles/146109.htmlarchangel archangel Tue, 18 Sep 2007 03:47:00 GMT http://m.tkk7.com/Archangelsy/articles/146109.html http://m.tkk7.com/Archangelsy/comments/146109.html http://m.tkk7.com/Archangelsy/articles/146109.html#Feedback 0 http://m.tkk7.com/Archangelsy/comments/commentRss/146109.html http://m.tkk7.com/Archangelsy/services/trackbacks/146109.html
许多Visual C++的用者都到q?font size="+0">LNK2005 :symbol already defined和LNK1169:one or more multiply defined symbols foundq样的链接错误,而且通常是在使用W三方库旉到的。对于这个问题,有的朋友可能不知其然Q而有的朋友可能知其然却不知其所以然Q那么本文就试图为大家彻底解开关于它的U种疑惑?/font>
大家都知道,从C/C++源程序到可执行文件要l历两个阶段:(1)~译器将源文件编译成汇编代码Q然后由汇编?assembler)译成机器指?再加上其它相关信?后输出到一个个目标文g(object file,VC的编译器~译出的目标文g默认的后~名是.obj)中;(2)链接?linker)一个个的目标文?或许q会有若q程序库)链接在一L成一个完整的可执行文件?/font>
~译器编译源文g时会把源文g的全局W号(global symbol)分成?strong)和弱(weak)两类传给汇编器,而随后汇~器则将强弱信息~码q保存在目标文g的符可中。那么何谓强弱呢Q编译器认ؓ函数与初始化了的全局变量都是强符P而未初始化的全局变量则成了弱W号。比如有q么个源文g:
extern int errorno; int buf[2] = {1,2}; int *p;
int main() { return 0; }
其中main、buf是强W号Qp是弱W号Q而errorno则非强非弱,因ؓ它只是个外部变量的用声明?/font>
有了强弱W号的概念,我们可以看看链接器是如何处理与选择被多ơ定义过的全局W号:
规则1 : 不允许强W号被多ơ定?即不同的目标文g中不能有同名的强W号)Q?/font>
规则2 : 如果一个符号在某个目标文g中是强符P在其它文件中都是qP那么选择强符P
规则3 : 如果一个符号在所有目标文件中都是qP那么选择其中L一个;
׃可知多个目标文g不能重复定义同名的函C初始化了的全局变量Q否则必然导?font size="+0">LNK2005 和LNK1169两种链接错误。可是,有的时候我们ƈ没有在自qE序中发现这L重定义现象,却也遇到了此U链接错误,q又是何解?嗯,问题E微有点儿复杂,Ҏ(gu)慢慢道来?br />
众所周知QANSI C/C++ 定义了相当多的标准函敎ͼ而它们又分布在许多不同的目标文g中,如果直接以目标文件的形式提供l程序员使用的话Q就需要他们确切地知道哪个函数存在于哪个目标文件中Qƈ且在链接时显式地指定目标文g名才能成功地生成可执行文Ӟ昄q是一个巨大的负担。所以C语言提供了一U将多个目标文g打包成一个文件的机制Q这是静态程序库(static library)。开发者在链接时只需指定E序库的文g名,链接器就会自动到E序库中L那些应用E序实用到的目标模块,q把(且只?它们从库中拷贝出来参与构建可执行文g。几乎所有的C/C++开发系l都会把标准函数打包成标准库提供l开发者?有不q么做的吗?)?/font>
E序库ؓ开发者带来了方便Q但同时也是某些混ؕ的根源。我们来看看链接器是如何解析(resolve)对程序库的引用的?br /> 在符可?symbol resolution)阶段Q链接器按照所有目标文件和库文件出现在命o行中的顺序从左至右依ơ扫描它们,在此期间它要l护若干个集?(1)集合E是将被合q到一L成可执行文g的所有目标文仉合;(2)集合U是未解析W号(unresolved symbolsQ比如已l被引用但是q未被定义的W号)的集合;(3)集合D是所有之前已被加入到E的目标文件定义的W号集合。一开始,E、U、D都是I的?/font>
(1): 对命令行中的每一个输入文件fQ链接器定它是目标文gq是库文Ӟ如果它是目标文gQ就把f加入到EQƈ把f中未解析的符号和已定义的W号分别加入到U、D集合中,然后处理下一个输入文件?/font>
(2): 如果f是一个库文gQ链接器会尝试把U中的所有未解析W号与f中各目标模块定义的符可行匹配。如果某个目标模块m定义了一个U中的未解析符P那么把m加入到E中,q把m中未解析的符号和已定义的W号分别加入到U、D集合中。不断地对f中的所有目标模块重复这个过E直臛_达一个不动点(fixed point)Q此时U和D不再变化。而那些未加入到E中的f里的目标模块p单地丢弃Q链接器l箋处理下一输入文g?/font>
(3): 如果处理q程中往D加入一个已存在的符P或者当扫描完所有输入文件时U非空Q链接器报错q停止动作。否则,它把E中的所有目标文件合q在一L成可执行文g?/font>
VC带的~译器名字叫cl.exeQ它有这么几个与标准E序库有关的选项: /ML?MLd?MT?MTd?MD?MDd。这些选项告诉~译器应用程序想使用什么版本的C标准E序库?ML(~省选项)对应单线E静态版的标准程序库(libc.lib)Q?MT对应多线E静态版标准?libcmt.lib)Q此时编译器会自动定义_MT宏;/MD对应多线EDLL?导入库msvcrt.libQDLL是msvcrt.dll)Q编译器自动定义_MT和_DLL两个宏。后面加d的选项都会让编译器自动多定义一个_DEBUG宏,表示要用对应标准库的调试版Q因?MLd对应调试版单U程静态标准库(libcd.lib)Q?MTd对应调试版多U程静态标准库(libcmtd.lib)Q?MDd对应调试版多U程DLL标准?导入库msvcrtd.libQDLL是msvcrtd.dll)。虽然我们的在~译时明白无误地告诉了编译器应用E序希望使用什么版本的标准库,可是当编译器q完了活Q轮到链接器开工时它又如何得知一个个目标文g到底在思念谁?Z传递相思,我们的编译器干了点U密的勾当。在cl~译出的目标文g中会有一个专门的区域(兛_q个区域到底在文件中什么地方的朋友可以参考COFF和PE文g格式)存放一些指导链接器如何工作的信息,其中有一U就叫缺省库(default library)Q这些信息指定了一个或多个库文件名Q告诉链接器在扫描的时候也把它们加入到输入文g列表?当然序位于在命令行中被指定的输入文件之?。说到这里,我们先来做个实验。写个顶简单的E序Q然后保存ؓmain.c :
/* main.c */ int main() { return 0; }
用下面这个命令编译main.c(什么?你从不用命o行来~译E序Q这?.....) :
cl /c main.c
/c是告诉cl只编译源文gQ不用链接。因?ML是缺省选项Q所以上q命令也相当? cl /c /ML main.c 。如果没什么问题的?要出了问题才是活见鬼Q当焉非你的环境变量没有设|好Q这时你应该去VC的bin目录下找到vcvars32.bat文g然后q行它?Q当前目录下会出C个main.obj文gQ这是我们可爱的目标文件。随便用一个文本编辑器打开?是的Q文本编辑器Q大胆地d别害?Q搜?defaultlib"字符Ԍ通常你就会看到这L东西: "-defaultlib:LIBC -defaultlib:OLDNAMES"。啊哈,没错Q这?br />是保存在目标文g中的~省库信息。我们的目标文g昄指定了两个缺省库Q一个是单线E静态版标准库libc.lib(q与/ML选项相符)Q另外一个是oldnames.lib(它是Z兼容微Y以前的C/C++开发系l??/font>
VC的链接器是link.exeQ因为main.obj保存了缺省库信息Q所以可以用
link main.obj libc.lib
或?/font>
link main.obj
来生成可执行文gmain.exeQ这两个命o是等L。但是如果你?/font>
link main.obj libcd.lib
的话Q链接器会给Z个警? "warning LNK4098: defaultlib "LIBC" conflicts with use of other libs; use /NODEFAULTLIB:library"Q因Z昑ּ指定的标准库版本与目标文件的~省g一致。通常来说Q应该保证链接器合ƈ的所有目标文件指定的~省标准库版本一_否则~译器一定会l出上面的警告,?font size="+0">LNK2005 和LNK1169链接错误则有时会出现有时不会。那么这个有时到底是什么时候?呵呵Q别着急,下面的一切正是ؓ喜欢q根I底的你准备的?/font>
Z个源文gQ就叫mylib.cQ内容如?
/* mylib.c */
Qi nclude
void foo() { printf("%s","I am from mylib!\n"); }
?/font>
cl /c /MLd mylib.c
命o~译Q注?MLd选项是指定libcd.lib为默认标准库。lib.exe是VC自带的用于将目标文g打包成程序库的命令,所以我们可以用
lib /OUT:my.lib mylib.obj
mylib.obj打包成库Q输出的库文件名是my.lib。接下来把main.cҎ(gu):
/* main.c */
void foo();
int main() { foo(); return 0; }
?/font>
cl /c main.c
~译Q然后用
link main.obj my.lib
q行链接。这个命令能够成功地生成main.exe而不会?font size="+0">LNK2005 和LNK1169链接错误Q你仅仅是得C一条警告信?"warning LNK4098: defaultlib "LIBCD" conflicts with use of other libs; use /NODEFAULTLIB:library"。我们根据前文所q的扫描规则来分析一下链接器此时做了些啥?/font>
一开始E、U、D都是I集Q链接器首先扫描到main.objQ把它加入E集合Q同时把未解析的foo加入UQ把main加入DQ而且因ؓmain.obj的默认标准库是libc.libQ所以它被加入到当前输入文g列表的末。接着扫描my.libQ因是个库,所以会拿当前U中的所有符?当然现在׃个foo)与my.lib中的所有目标模?当然也只有一个mylib.obj)依次匚wQ看是否有模块定义了U中的W号。结果mylib.obj实定义了fooQ于是它被加入到EQfoo从U转移到DQmylib.obj引用的printf加入到UQ同样地Qmylib.obj指定的默认标准库是libcd.libQ它也被加到当前输入文g列表的末?在libc.lib的后?。不断地在my.lib库的各模块上q行q代以匹配U中的W号Q直到U、D都不再变化。很明显Q现在就已经到达了这么一个不动点Q所以接着扫描下一个输入文Ӟ是libc.lib。链接器发现l(f)ibc.lib里的printf.obj里定义有printfQ于是printf从UUdDQ而printf.obj被加入到EQ它定义的所有符号加入到DQ它里头的未解析W号加入到U。链接器q会把每个程序都要用到的一些初始化操作所在的目标模块(比如crt0.obj{?及它们所引用的模?比如malloc.obj、free.obj{?自动加入到E中,q更新U和D以反应这个变化。事实上Q标准库各目标模块里的未解析W号都可以在库内其它模块中找到定义,因此当链接器处理完libc.libӞU一定是I的。最后处理libcd.libQ因为此时U已经为空Q所以链接器会抛弃它里面的所有目标模块从而结束扫描,然后合ƈE中的目标模块q输出可执行文g?/font>
上文描述了虽然各目标模块指定了不同版本的~省标准库但仍然链接成功的例子,接下来你目睹因U不严}而导致的(zhn)惨p|?/font>
修改mylib.c成这个样?
Qi nclude
void foo() { // just a test , don"t care memory leak _malloc_dbg( 1, _NORMAL_BLOCK, __FILE__, __LINE__ ); }
其中_malloc_dbg不是ANSI C的标准库函数Q它是VC标准库提供的malloc的调试版Q与相关函数配套能帮助开发者抓各种内存错误。用它一定要定义_DEBUG宏,否则预处理器会把它自动{为malloc。l用
cl /c /MLd mylib.c lib /OUT:my.lib mylib.obj
~译打包。当再次?/font>
link main.obj my.lib
q行链接Ӟ我们看到了什么?天哪Q一堆的LNK2005 加上个贵?fatal error"的LNK1169垫底Q当然还不了那个LNK4098。链接器是不是疯了?不,你冤枉可怜的链接器了Q我拍胸脯保证它可是一直在心?yu)责地照章办事?/font>
一开始E、U、D为空Q链接器扫描main.objQ把它加入EQ把foo加入UQ把main加入DQ把libc.lib加入到当前输入文件列表的末尾。接着扫描my.libQfoo从U转移到DQ_malloc_dbg加入到UQlibcd.lib加到当前输入文g列表的尾部。然后扫描libc.libQ这时会发现l(f)ibc.lib里Q何一个目标模块都没有定义_malloc_dbg(它只在调试版的标准库中存?Q所以不会有M一个模块因为_malloc_dbg而加入EQ但是每个程序都要用到的初始化模?如crt0.obj{?及它们所引用的模?比如malloc.obj、free.obj{?q是会自动加入到E中,同时U和D被更C反应q个变化。当链接器处理完libc.libӞU只剩_malloc_dbgq一个符受最后处理libcd.libQ发现dbgheap.obj定义了_malloc_dbgQ于是dbgheap.obj加入到EQ它里头的未解析W号加入UQ它定义的所有其它符号也加入DQ这时灾难便来了。之前malloc{符号已l在D?随着libc.lib里的malloc.obj加入E而加入的)Q而dbgheap.obj又定义了包括malloc在内的许多同名符Pq引发了重定义冲H,链接器只好中断工作ƈ报告错误?/font>
现在我们该知道,链接器完全没有责任,责Q在我们自qw上。是我们_心地把~省标准库版本不一致的目标文g(main.obj)与程序库(my.lib)链接hQ导致了大灾难。解军_法很单,要么?MLd选项来重~译main.cQ要么用/ML选项重编译mylib.c?/font>
在上qC子中Q我们拥有库my.lib的源代码(mylib.c)Q所以可以用不同的选项重新~译q些源代码ƈ再次打包。可如果使用的是W三方的库,它ƈ没有提供源代码,那么我们只有改变自q序的~译选项来适应q些库了。但是如何知道库中目标模块指定的默认库呢Q其实VC提供的一个小工具便可以完成Q务,q就是dumpbin.exe。运行下面这个命?/font>
dumpbin /DIRECTIVES my.lib
然后在输ZN?Linker Directives"引导的信息,你一定会发现每一处这L信息都会包含若干个类?-defaultlib:XXXX"q样的字W串Q其中XXXX便代表目标模块指定的~省库名?/font>
知道了第三方库指定的默认标准库,再用合适的选项~译我们的应用程序,可以避?font size="+0">LNK2005 和LNK1169链接错误。喜ƢIDE的朋友,你一样可以到 "Project属? -> "C/C++" -> "代码生成(code generation)" -> "q行时库(run-time library)" 下讄应用E序的默认标准库版本Q这与命令行选项的效果是一L?/font>
l极解决办法Q?/strong>
?Project/Setting/Link/General中的 Project Options: 加入 /FORCE:MULTIPLE卛_?/font>
]]>VC++的链接错误LNK2005 http://m.tkk7.com/Archangelsy/articles/146105.htmlarchangel archangel Tue, 18 Sep 2007 03:30:00 GMT http://m.tkk7.com/Archangelsy/articles/146105.html http://m.tkk7.com/Archangelsy/comments/146105.html http://m.tkk7.com/Archangelsy/articles/146105.html#Feedback 0 http://m.tkk7.com/Archangelsy/comments/commentRss/146105.html http://m.tkk7.com/Archangelsy/services/trackbacks/146105.html ~程中经常能遇到LNK2005错误——重复定义错误,其实LNK2005错误q不是一个很难解决的错误。弄清楚它Ş成的原因Q就可以L解决它了? 造成LNK2005错误主要有以下几U情况: 1Q重复定义全局变量。可能存在两U情况: A、对于一些初学编E的E序员,有时候会以ؓ需要用全局变量的地方就可以使用定义x一下。其实这是错误的Q全局变量是针Ҏ(gu)个工E的。正的应该是在 一个CPP文g中定义如下:int g_Test;那么在用的CPP文g中就应该使用Qextern int g_Test卛_Q如果还是用int g_TestQ那么就会生LNK2005错误Q一般错误错误信息类|AAA.obj error LNK2005 int book cQbook@@3HA already defined in BBB.obj。切记的是不能l变量赋值否则还是会有LNK2005错误? q里需要的是“声明”,不是“定义”!Ҏ(gu)C++标准的规定,一个变量是声明Q必d时满两个条Ӟ否则是定义Q? (1)声明必须使用extern关键字;(2)不能l变量赋初? 所以,下面的是声明: extern int a; 下面的是定义 int a; int a = 0; extern int a =0; B、对于那么编E不是那么严谨的E序员,L在需要用变量的文g中随意定义一个全局变量Qƈ且对于变量名也不予考虑Q这也往往Ҏ(gu)造成变量名重复,而造成LNK2005错误。 ?br /> 2Q头文g的包含重复。往往需要包含的头文件中含有变量、函数、类的定义,在其它用的地方又不得不多次包含之,如果头文件中没有相关的宏{防止重复链?的措施,那么׃产生LNK2005错误。解军_法是在需要包含的头文件中做类似的处理Q?ifndef MY_H_FILE //如果没有定义q个? #define MY_H_FILE //定义q个? …? //头文件主体内? …? #endif 上面是用宏来做的,也可以用预~译来做Q在头文件中加入Q? #pragma once //头文件主体 ?br /> 3Q用第三方的库造成的。这U情况主要是Cq行期函数库和MFC的库冲突造成的。具体的办法是那个提C出错的库放到另外一个库的前面。另外选择不同 的C函数库,可能会引赯个错误。微软和C有两UCq行期函数库Q一U是普通的函数库:LIBC.LIBQ不支持多线E。另外一U是支持多线E的Q?msvcrt.lib。如果一个工E里Q这两种函数库合用,可能会引赯个错误,一般情况下它需要MFC的库先于Cq行期函数库被链接,因此使用 支持多线E的msvcrt.lib。所以在使用W三方的库之前首先要知道它链接的是什么库Q否则就可能造成LNK2005错误。如果不得不使用W三方的 库,可以试按下面所说的Ҏ(gu)修改Q但不能保证一定能解决问题Q前两种Ҏ(gu)是微软提供的Q? A、选择VC菜单Project->Settings->Link->Catagory选择InputQ再在Ignore libraries 的Edit栏中填入你需要忽略的库,如:Nafxcwd.lib;Libcmtd.lib。然后在Object/library Modules的Edit栏中填入正确的库的顺序,q里需要你能确定什么是正确的顺序,呵呵QGod bless youQ? B、选择VC菜单Project->Settings->Link,然后在Project Options的Edit栏中输入/verbose:libQ这样就可以在编译链接程序过E中在输出窗口看到链接的序了? C、选择VC菜单Project->Settings->C/C++,Catagory选择Code Generation后再在User Runtime libraray中选择MultiThread DLL{其他库Q逐一试? 关于~译器的相关处理q程Q参考: http://www.donews.net/xzwenlan/archive/2004/12/23/211668.aspx q就是我所遇到q的LNK2005错误的几U情况,肯定q有其他的情况也可能造成q种错误Q所以我不希望你在看完这文章以后,再遇到LNK2005错误 时候,不动脑筋的想对号入的排除错误。编E的q程是一个思考的q程Q所以还是多多开动你的头脑,那样收获会更多! Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q? 支持,我在C里也看到了许多LINK 2005? 补充一?是一ơ在用第三方库时,׃errno被重定义,用多U方法都不能解决,后查找MSDN,发现l(f)ink有个选项/FORCE可以解决,在IDE? Project->Settings->Link?选categroy为custom,force file output前打? 但会有警? warning LNK4088: image being generated due to /FORCE option; image may not run 但的解决了问题,q是׃VC寚w定义比较严格,像BCB或GCC在库中的重定义不会有M警告或错? Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q= 我发现的另外一个出现LINK2005的现象,好像是由于名U空间而引L。我在dos下写的程序没有问题,但是攑֜mfc中就出现了这个链接错误。因?起初囄事,我在一个头文g中写了using namespace std,q且q个头文件我多处使用Q另外,我还使用了boost库。后来,问题解决的方法非常奇怪,在一个头文g中引用其他头文gQ这些头文g的顺序换一 下就通过了,那个出现问题的头文g中我使用了std::mapQ当我把q种容器使用模板代替后,链接有没事了。(例如Qtemplate< class coll>Q?后来感到模板技术还有这U效?赚了!哈哈 Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q= Knowledge Base What are the C and C++ libraries my program would link with? ------------------------------------------------------------------ | Compile Old New IOStream Libraries | | Option IOStream or STL Linked With | |================================================================| | /ML Yes No LIBC.LIB, LIBCI.LIB | | /MDd Yes No MSVCRTD.LIB, MSVCIRTD.LIB | 你的E序使用?ML~译选项,而程序依赖的.lib可能使用/MDd选项~译,造成链接冲突. l一~译选项可回避此错误 Project Settings->C/C++ Tab->Category:CodeGeneration Use run-time libraryl合框中选择Multithread Dll(或Debug Multithread Dll ) 注意Q所有相兛_E都应该选择相同~译选项 Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q= 微Y的MSDN中查C息的 可能的原? 不慎同时与单U程库和多线E库链接。确保应用程序项目文件只包括适当的库Qƈ且Q何第三方库已适当创徏了单U程或多U程版本? 该符号ؓ装函数Q通过? /Gy ~译创徏Q,包含在多个文件中Q但在各~译间已改变。重新编译所有包? symbol 的文件? 以不同的形式在不同库中的两个成员对象中定义了该符Pq且使用了这两个成员对象? 某个l对W号被定义两ơ,而每ơ定义的g同? 头文件声明ƈ定义了变量。可能的解决Ҏ(gu)有: ? .h 中声明变量:extern BOOL MyBool;Q然后在 .c ? .cpp 文g中向它分配:BOOL MyBool = FALSE;? 变量声明ؓ Static? 变量声明ؓ selectany? 当将 uuid.lib 与定? GUID 的其? .lib 文gQ例? oledb.lib ? adsiid.libQ一起用时。例如: oledb.lib(oledb_i.obj) : error LNK2005: _IID_ITransactionObject already defined in uuid.lib(go7.obj) 若要修复Q请? /FORCE:MULTIPLE d到链接器命o行选项Qƈ保 uuid.lib 是引用的W一个库? 有关更多信息Q请参阅知识库文章: Q148652QPRB: LNK2005 Errors When Link C Run-Time Libraries Are Linked Before MFC Libraries? Q140440QFIX: Global Overloaded Delete Operator Causes LNK2005? Q184235QPRB: LNK2005 Errors on New and Delete When Defining _ATL_MIN_CRT? 该错误之后ؓ致命错误 LNK1169? Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q=Q? 有时候因为工E用了预编译头文gq且是增量编译,所以当你改动以后可能也会出现LNK2005错误Q提C“XXXX已经在XXXX.obj文g中定义?的消息,q时候只要Rebuild All一般都能解决问题。这是因为头文g的顺序被改动{等操作造成的? 最后要说明的:事物是在不断变化中的QC++的标准在变化Q编译器也在变化Q所以ƈ不是所有的LNK2005错误都可以在q里扑ֈ{案Q但是至它能给你以提示。学习ƈ思考才是正的Q ?br /> ]]> C/C++中的日期和时?time_t与struct tmQ{Q?/title> http://m.tkk7.com/Archangelsy/articles/112829.htmlarchangel archangel Sun, 22 Apr 2007 14:47:00 GMT http://m.tkk7.com/Archangelsy/articles/112829.html http://m.tkk7.com/Archangelsy/comments/112829.html http://m.tkk7.com/Archangelsy/articles/112829.html#Feedback 0 http://m.tkk7.com/Archangelsy/comments/commentRss/112829.html http://m.tkk7.com/Archangelsy/services/trackbacks/112829.html C/C++中的日期和时?time_t与struct tm
摘要Q?/p>
http://wiseman.cnblogs.com
本文从介l基概念入手Q探讨了在C/C++中对日期和时间操作所用到的数据结构和函数Qƈ对计时、时间的获取、时间的计算和显C格式等斚wq行了阐q。本文还通过大量的实例向你展CZtime.h头文件中声明的各U函数和数据l构的详l用方法?br /> 关键字:UTCQ世界标准时_QCalendar TimeQ日历时_QepochQ时间点Q,clock tickQ时钟计时单元) 1Q概?br />在C/C++中,对字W串的操作有很多值得注意的问题,同样QC/C++Ҏ(gu)间的操作也有许多值得大家注意的地斏V最q,在技术群中有很多|友也多ơ问到过C++语言中对旉的操作、获取和昄{等的问题。下面,在这文章中Q笔者将主要介绍在C/C++中时间和日期的用方? 通过学习许多C/C++库,你可以有很多操作、用时间的Ҏ(gu)。但在这之前你需要了解一些“时间”和“日期”的概念Q主要有以下几个Q?br /> Coordinated Universal TimeQUTCQ:协调世界Ӟ又称Z界标准时_也就是大家所熟知的格林威L准时_Greenwich Mean TimeQGMTQ。比如,中国内地的时间与UTC的时差ؓ+8Q也是UTC+8。美国是UTC-5?br /> Calendar TimeQ日历时_是用“从一个标准时间点到此时的旉l过的秒数”来表示的时间。这个标准时间点对不同的~译器来说会有所不同Q但对一个编译系l来_q个标准旉Ҏ(gu)不变的,该编译系l中的时间对应的日历旉都通过该标准时间点来衡量,所以可以说日历旉是“相Ҏ(gu)间”,但是无论你在哪一个时区,在同一时刻对同一个标准时间点来说Q日历时间都是一L?br /> epochQ时间点。时间点在标准C/C++中是一个整敎ͼ它用此时的时间和标准旉点相差的U数Q即日历旉Q来表示?br /> clock tickQ时钟计时单元(而不把它叫做旉滴答ơ数Q,一个时钟计时单元的旉长短是由CPU控制的。一个clock tick不是CPU的一个时钟周期,而是C/C++的一个基本计时单位?br /> 我们可以使用ANSI标准库中的time.h头文件。这个头文g中定义的旉和日期所使用的方法,无论是在l构定义Q还是命名,都具有明昄C语言风格。下面,我将说明在C/C++中怎样使用日期的时间功能?br /> 2Q?计时 C/C++中的计时函数是clock()Q而与其相关的数据cd是clock_t。在MSDN中,查得对clock函数定义如下Q?br /> clock_t clock( void ); q个函数q回从“开启这个程序进E”到“程序中调用clock()函数”时之间的CPU旉计时单元Qclock tickQ数Q在MSDN中称之ؓ挂钟旉Qwall-clockQ。其中clock_t是用来保存时间的数据cdQ在time.h文g中,我们可以扑ֈ对它的定义: #ifndef _CLOCK_T_DEFINED typedef long clock_t; #define _CLOCK_T_DEFINED #endif 很明显,clock_t是一个长整Ş数。在time.h文g中,q定义了一个常量CLOCKS_PER_SECQ它用来表示一U钟会有多少个时钟计时单元,其定义如下: #define CLOCKS_PER_SEC ((clock_t)1000) 可以看到可以看到每过千分之一U(1毫秒Q,调用clockQ)函数q回的值就?。下面D个例子,你可以用公式clock()/CLOCKS_PER_SEC来计一个进E自w的q行旉Q?br /> void elapsed_time() { printf("Elapsed time:%u secs.\n",clock()/CLOCKS_PER_SEC); } 当然Q你也可以用clock函数来计你的机器运行一个@环或者处理其它事件到底花了多时_ Qi nclude “stdio.h?br />Qi nclude “stdlib.h?br />Qi nclude “time.h?br /> int main( void ) { long i = 10000000L; clock_t start, finish; double duration; /* 量一个事件持l的旉*/ printf( "Time to do %ld empty loops is ", i ); start = clock(); while( i-- ) ; finish = clock(); duration = (double)(finish - start) / CLOCKS_PER_SEC; printf( "%f seconds\n", duration ); system("pause"); } 在笔者的机器上,q行l果如下Q?br /> Time to do 10000000 empty loops is 0.03000 seconds 上面我们看到旉计时单元的长度ؓ1毫秒Q那么计时的_ֺ也ؓ1毫秒Q那么我们可不可以通过改变CLOCKS_PER_SEC的定义,通过把它定义的大一些,从而计时_ֺ更高呢?通过试Q你会发现这h不行的。在标准C/C++中,最的计时单位是一毫秒?br /> 3Q与日期和时间相关的数据l构 在标准C/C++中,我们可通过tml构来获得日期和旉Qtml构在time.h中的定义如下Q?br /> #ifndef _TM_DEFINED struct tm { int tm_sec; /* U??取值区间ؓ[0,59] */ int tm_min; /* ?- 取值区间ؓ[0,59] */ int tm_hour; /* ?- 取值区间ؓ[0,23] */ int tm_mday; /* 一个月中的日期 - 取值区间ؓ[1,31] */ int tm_mon; /* 月䆾Q从一月开始,0代表一月) - 取值区间ؓ[0,11] */ int tm_year; /* q䆾Q其值等于实际年份减?900 */ int tm_wday; /* 星期 ?取值区间ؓ[0,6]Q其?代表星期天,1代表星期一Q以此类?*/ int tm_yday; /* 从每q的1?日开始的天数 ?取值区间ؓ[0,365]Q其?代表1?日,1代表1?日,以此cL */ int tm_isdst; /* 夏o时标识符Q实行夏令时的时候,tm_isdst为正。不实行夏o时的q候,tm_isdst?Q不了解情况Ӟtm_isdst()?/ }; #define _TM_DEFINED #endif ANSI C标准UC用tml构的这U时间表CZؓ分解旉(broken-down time)?br /> 而日历时_Calendar TimeQ是通过time_t数据cd来表C的Q用time_t表示的时_日历旉Q是从一个时间点Q例如:1970q?????U)到此时的U数。在time.h中,我们也可以看到time_t是一个长整型敎ͼ #ifndef _TIME_T_DEFINED typedef long time_t; /* 旉?*/ #define _TIME_T_DEFINED /* 避免重复定义 time_t */ #endif 大家可能会生疑问:既然time_t实际上是长整型,到未来的某一天,从一个时间点Q一般是1970q?????U)到那时的U数Q即日历旉Q超Z长整形所能表C的数的范围怎么办?对time_t数据cd的值来_它所表示的时间不能晚?038q??8?9?4?7U。ؓ了能够表C更久远的时_一些编译器厂商引入?4位甚x长的整Ş数来保存日历旉。比如微软在Visual C++中采用了__time64_t数据cd来保存日历时_q过_time64()函数来获得日历时_而不是通过使用32位字的time()函数Q,q样可以通过该数据类型保?001q?????U(不包括该旉点)之前的时间?br /> 在time.h头文件中Q我们还可以看到一些函敎ͼ它们都是以time_t为参数类型或q回值类型的函数Q?br /> double difftime(time_t time1, time_t time0); time_t mktime(struct tm * timeptr); time_t time(time_t * timer); char * asctime(const struct tm * timeptr); char * ctime(const time_t *timer); 此外Qtime.hq提供了两种不同的函数将日历旉Q一个用time_t表示的整敎ͼ转换为我们^时看到的把年月日时分U分开昄的时间格式tmQ?br /> struct tm * gmtime(const time_t *timer); struct tm * localtime(const time_t * timer); 通过查阅MSDNQ我们可以知道Microsoft C/C++ 7.0中时间点的|time_t对象的|是从1899q?2?1???U到该时间点所l过的秒敎ͼ而其它各U版本的Microsoft C/C++和所有不同版本的Visual C++都是计算的从1970q?????U到该时间点所l过的秒数?br /> 4Q与日期和时间相关的函数及应?br />在本节,我将向大家展C怎样利用time.h中声明的函数Ҏ(gu)间进行操作。这些操作包括取当前旉、算旉间隔、以不同的Ş式显C时间等内容?br /> 4.1 获得日历旉 我们可以通过time()函数来获得日历时_Calendar TimeQ,其原型ؓQ?br /> time_t time(time_t * timer); 如果你已l声明了参数timerQ你可以从参数timerq回现在的日历时_同时也可以通过q回D回现在的日历旉Q即从一个时间点Q例如:1970q?????U)到现在此时的U数。如果参CؓI(NULLQ,函数只通过q回D回现在的日历旉Q比如下面这个例子用来显C当前的日历旉Q?br /> Qi nclude "time.h" Qi nclude "stdio.h" int main(void) { struct tm *ptr; time_t lt; lt =time(NULL); printf("The Calendar Time now is %d\n",lt); return 0; } q行的结果与当时的时间有养I我当时运行的l果是: The Calendar Time now is 1122707619 其中1122707619是我运行程序时的日历时间。即?970q?????U到此时的秒数?br /> 4.2 获得日期和时?br /> q里说的日期和时间就是我们^时所说的q、月、日、时、分、秒{信息。从W?节我们已l知道这些信息都保存在一个名为tm的结构体中,那么如何一个日历时间保存ؓ一个tml构的对象呢Q?br /> 其中可以使用的函数是gmtime()和localtime()Q这两个函数的原型ؓQ?br /> struct tm * gmtime(const time_t *timer); struct tm * localtime(const time_t * timer); 其中gmtime()函数是将日历旉转化Z界标准时_x林尼L_Qƈq回一个tml构体来保存q个旉Q而localtime()函数是将日历旉转化为本地时间。比如现在用gmtime()函数获得的世界标准时间是2005q??0??8?0U,那么我用localtime()函数在中国地得的本地旉会比旉标准旉?个小Ӟ?005q??0?5?8?0U。下面是个例子: Qi nclude "time.h" Qi nclude "stdio.h" int main(void) { struct tm *local; time_t t; t=time(NULL); local=localtime(&t); printf("Local hour is: %d\n",local->tm_hour); local=gmtime(&t); printf("UTC hour is: %d\n",local->tm_hour); return 0; } q行l果是: Local hour is: 15 UTC hour is: 7 4.3 固定的时间格?br /> 我们可以通过asctime()函数和ctime()函数时间以固定的格式显C出来,两者的q回值都是char*型的字符丌Ӏ返回的旉格式为: 星期?月䆾 日期 ??U?q\n\0 例如QWed Jan 02 02:03:55 1980\n\0 其中\n是一个换行符Q\0是一个空字符Q表C字W串l束。下面是两个函数的原型: char * asctime(const struct tm * timeptr); char * ctime(const time_t *timer); 其中asctime()函数是通过tml构来生成具有固定格式的保存旉信息的字W串Q而ctime()是通过日历旉来生成时间字W串。这L话,asctimeQ)函数只是把tml构对象中的各个域填到时间字W串的相应位|就行了Q而ctimeQ)函数需要先参照本地的时间设|,把日历时间{化ؓ本地旉Q然后再生成格式化后的字W串。在下面Q如果lt是一个非I的time_t变量的话Q那么: printf(ctime(<)); {h(hun)于: struct tm *ptr; ptr=localtime(<); printf(asctime(ptr)); 那么Q下面这个程序的两条printf语句输出的结果就是不同的了(除非你将本地时区设ؓ世界标准旉所在的时区Q: Qi nclude "time.h" Qi nclude "stdio.h" int main(void) { struct tm *ptr; time_t lt; lt =time(NULL); ptr=gmtime(<); printf(asctime(ptr)); printf(ctime(<)); return 0; } q行l果Q?br /> Sat Jul 30 08:43:03 2005 Sat Jul 30 16:43:03 2005 4.4 自定义时间格?br /> 我们可以使用strftimeQ)函数时间格式化为我们想要的格式。它的原型如下: size_t strftime( char *strDest, size_t maxsize, const char *format, const struct tm *timeptr ); 我们可以Ҏ(gu)format指向字符串中格式命o把timeptr中保存的旉信息攑֜strDest指向的字W串中,最多向strDest中存放maxsize个字W。该函数q回向strDest指向的字W串中放|的字符数?br /> 函数strftime()的操作有些类gsprintf()Q识别以癑ֈ?%)开始的格式命o集合Q格式化输出l果攑֜一个字W串中。格式化命o说明串strDest中各U日期和旉信息的确切表C方法。格式串中的其他字符原样放进串中。格式命令列在下面,它们是区分大写的?br /> %a 星期几的? %A 星期几的全称 %b 月分的简? %B 月䆾的全U? %c 标准的日期的旉? %C q䆾的后两位数字 %d 十进制表C的每月的第几天 %D ??q? %e 在两字符域中Q十q制表示的每月的W几? %F q??? %g q䆾的后两位数字Q用基于周的年 %G q分Q用基于周的年 %h 写的月䆾? %H 24时制的时 %I 12时制的时 %j 十进制表C的每年的第几天 %m 十进制表C的月䆾 %M 十时制表C的分钟? %n 新行W? %p 本地的AM或PM的等hC? %r 12时的时? %R 昄时和分钟:hh:mm %S 十进制的U数 %t 水^制表W? %T 昄时分U:hh:mm:ss %u 每周的第几天Q星期一为第一?Qg0?Q星期一?Q?br />%U W年的第几周Q把星期日做为第一天(g0?3Q?br />%V 每年的第几周Q用基于周的年 %w 十进制表C的星期几(g0?Q星期天?Q?br />%W 每年的第几周Q把星期一做ؓW一天(g0?3Q? %x 标准的日期串 %X 标准的时间串 %y 不带世纪的十q制q䆾Qg0?9Q?br />%Y 带世U部分的十制q䆾 %zQ?Z 时区名称Q如果不能得到时区名U则q回I字W?br />%% 癑ֈ?br /> 如果xC现在是几点了,q以12时制显C,p下面q段E序Q?br /> Qi nclude “time.h?br />Qi nclude “stdio.h?br />int main(void) { struct tm *ptr; time_t lt; char str[80]; lt=time(NULL); ptr=localtime(<); strftime(str,100,"It is now %I %p",ptr); printf(str); return 0; } 其运行结果ؓQ?br />It is now 4PM 而下面的E序则显C当前的完整日期Q?br /> Qi nclude Qi nclude void main( void ) { struct tm *newtime; char tmpbuf[128]; time_t lt1; time( <1 ); newtime=localtime(<1); strftime( tmpbuf, 128, "Today is %A, day %d of %B in the year %Y.\n", newtime); printf(tmpbuf); } q行l果Q?br /> Today is Saturday, day 30 of July in the year 2005. 4.5 计算持箋的时间长?br /> 有时候在实际应用中要计算一个事件持l的旉长度Q比如计打字速度。在W?节计旉分中Q我已经用clock函数举了一个例子。Clock()函数可以_到毫U。同Ӟ我们也可以用difftime()函数Q但它只能精到U。该函数的定义如下: double difftime(time_t time1, time_t time0); 虽然该函数返回的以秒计算的时间间隔是doublecd的,但这q不说明该时间具有同double一L_度,q是由它的参数觉得的Qtime_t是以Uؓ单位计算的)。比如下面一D늨序: Qi nclude “time.h?br />Qi nclude “stdio.h?br />Qi nclude “stdlib.h?br />int main(void) { time_t start,end; start = time(NULL); system("pause"); end = time(NULL); printf("The pause used %f seconds.\n",difftime(end,start));//<- system("pause"); return 0; } q行l果为: hL键l? . . The pause used 2.000000 seconds. hL键l? . . 可以惛_Q暂停的旉q不那么巧是整整2U钟。其实,你将上面E序的带有?/<-”注释的一行用下面的一行代码替换: printf("The pause used %f seconds.\n",end-start); 其运行结果是一L?br /> 4.6 分解旉转化为日历时?br /> q里说的分解旉是以年、月、日、时、分、秒{分量保存的旉l构Q在C/C++中是tml构。我们可以用mktimeQ)函数用tml构表示的时间{化ؓ日历旉。其函数原型如下Q?br /> time_t mktime(struct tm * timeptr); 其返回值就是{化后的日历时间。这h们就可以先制定一个分解时_然后对这个时间进行操作了Q下面的例子可以计算?997q??日是星期几: Qi nclude "time.h" Qi nclude "stdio.h" Qi nclude "stdlib.h" int main(void) { struct tm t; time_t t_of_day; t.tm_year=1997-1900; t.tm_mon=6; t.tm_mday=1; t.tm_hour=0; t.tm_min=0; t.tm_sec=1; t.tm_isdst=0; t_of_day=mktime(&t); printf(ctime(&t_of_day)); return 0; } q行l果Q?br /> Tue Jul 01 00:00:01 1997 现在注意了,有了mktime()函数Q是不是我们可以操作现在之前的Q何时间呢Q你可以通过q种办法出1945q??5h星期几吗Q答案是否定的。因个时间在1970q??日之前,所以在大多数编译器中,q样的程序虽然可以编译通过Q但q行时会异常l止?br /> 5Qȝ 本文介绍了标准C/C++中的有关日期和时间的概念Qƈ通过各种实例讲述了这些函数和数据l构的用方法。笔者认为,和时间相关的一些概忉|相当重要的,理解q些概念是理解各U时间格式的转换的基Q更是应用这些函数和数据l构的基?br />
]]> C++中constȝ Q{Q?/title> http://m.tkk7.com/Archangelsy/articles/112828.htmlarchangel archangel Sun, 22 Apr 2007 14:46:00 GMT http://m.tkk7.com/Archangelsy/articles/112828.html http://m.tkk7.com/Archangelsy/comments/112828.html http://m.tkk7.com/Archangelsy/articles/112828.html#Feedback 0 http://m.tkk7.com/Archangelsy/comments/commentRss/112828.html http://m.tkk7.com/Archangelsy/services/trackbacks/112828.html
一、对于基本声? 1.const int r=100; //标准const变量声明加初始化Q因为默认内部连接所以必被初始化,其作用域为此文gQ编译器l过cd查后直接?00在编译时替换? 2.extend const int r=100; //const改ؓ外部q接Q作用于扩大臛_局Q编译时会分配内存,q且可以不进行初始化Q仅仅作为声明,~译器认为在E序其他地方q行了定义? 3.const int r[ ]={1,2,3,4}; struct S {int a,b;}; const S s[ ]={(1,2),(3.4)}; //以上两种都是帔R集合Q编译器会ؓ其分配内存,所以不能在~译期间使用其中的|例如Qint temp[r[2]];q样的编译器会报告不能找到常量表辑ּ 二、对于指? 1.const int *r=&x; //声明rZ个指向常量的x的指针,r指向的对象不能被修改Q但他可以指向Q何地址的常量? 2.int const *r=&x; //与用?完全{h(hun)Q没有Q何区别? 3.int * const r=&x; //声明rZ个常量指针,他指向xQrq个指针的指向不能被修改Q但他指向的地址的内容可以修攏V? 4.const int * const r=&x; //l合1?用法Qr是一个指向常量的帔R型指针? 三、对于类型检? 可以把一个非const对象赋给一个指向const的指针,因ؓ有时候我们不想从q个指针来修改其对象的|但是不可以把一个const对象赋值给一个非const指针Q因样可能会通过q个指针改变指向对象的|但也存在使这U操作通过的合法化写法Q用类型强制{换可以通过指针改变const对象Q? const int r=100; int * ptr = const_cast(&r); //C++标准QC语言使用Qint * ptr =(int*)&r; 四、对于字W数l? 如char * name = “china? q样的语句,在编译时是能够通过的,但是”china”是帔R字符数组QQ何想修改他的操作也能通过~译但会引vq行旉误,如果我们想修改字W数l的话就要用char name[ ] = “china? q种形式? 五、对于函? 1.void Fuction1 ( const int r ); //此处为参C递const|意义是变量初g能被函数改变 2.const int Fuction1 (int); //此处q回const|意思指q回的原函数里的变量的初g能被修改Q但是函数按D回的q个变量被制成副本,能不能被修改没有了意义Q它可以被赋lQ何的const或非constcd变量Q完全不需要加上这个const关键字。但q只对于内部cd而言Q因为内部类型返回的肯定是一个|而不会返回一个变量,不会作ؓ左g用)Q对于用戯定义cdQ返回值是帔R是非帔R要的Q见下面条款3? 3.Class CX; //内部有构造函敎ͼ声明如CX(int r =0) CX Fuction1 () { return CX(); } const CX Fuction2 () { return CX(); } 如有上面的自定义cCXQ和函数Fuction1()和Fuction2(),我们q行如下操作Ӟ Fuction1() = CX(1); //没有问题Q可以作为左D? Fuction2() = CX(1); //~译错误Qconstq回值禁止作为左D用。因为左值把q回g为变量会修改其返回|const声明止q种修改? 4.函数中指针的const传递和q回Q? int F1 (const char * pstr); //作ؓ传递的时候用const修饰可以保证不会通过q个指针来修改传递参数的初|q里在函数内部Q何修?pstr的企N会引L译错误? const char * F2 (); //意义是函数返回的指针指向的对象是一个const对象Q它必须赋给一个同h指向const对象的指针? const char * const F3(); //比上面多了一个constQ这个const的意义只是在他被用作左值时有效Q它表明了这个指针除了指向const对象外,它本w也不能被修改,所以就不能当作左值来处理? 5.函数中引用的const传递: void F1 ( const X& px); //q样的一个const引用传递和最普通的函数按g递的效果是一模一LQ他止对引用的对象的一切修改,唯一不同的是按g递会先徏立一个类对象的副本,然后传递过去,而它直接传递地址Q所以这U传递比按g递更有效? **另外只有引用的const传递可以传递一个时对象,因ؓ临时对象都是const属性,且是不可见的Q他短时间存在一个局部域中,所以不能用指针,只有引用的const传递能够捕捉到q个家伙? 六、对于类 1.首先Q对于const的成员变量,只能在构造函数里使用初始化成员列表来初始化,试图在构造函C内进行初始化const成员变量会引L译错误。初始化成员列表形如Q? 2.X:: X ( int ir ): r(ir) {} //假设r是类X的const成员变量 2.const成员函数。提到这个概念首先要谈到const对象Q正象内|类型能够定义const对象一Pconst int r=10;Q,用户自定义类型也可以定义const对象(const X px(10);)Q编译器要保证这个对象在其生命周期内不能够被改变。如果你定义了这L一个const对象Q那么对于这个对象的一切非const成员函数的调用,~译器ؓ了保证对象的constҎ(gu),都会止q在~译期间报错。所以如果你惌你的成员函数能够在const对象上进行操作的话,p把这个函数声明ؓconst成员函数。假如f( )是类中的成员函数的话Q它的声明Ş如: int f( ) const; //const攑֜函数的最后,~译器会对这个函数进行检查,在这个函C的Q何试图改变成员变量和调用非const成员函数的操作都被视为非? 注意Q类的构造和析构函数都不能是const函数? 3.建立了一个const成员函数Q但仍然想用q个函数改变对象内部的数据。这L一个要求也会经帔R刎ͼ其是在一个苛ȝ面试考官那里。首先我们要弄清楚考官的要求,因ؓ有两U方法可以实玎ͼ如果q位考官要求不改变原来类的Q何东西,只让你从当前q个const成员函数入手Q那么你只有使用前面提到的类型强制{换方法。实例如下: //假如有一个叫做X的类Q它有一个int成员变量rQ我们需要通过一个const成员函数f( )来对q个rq行++r操作Q代码如? void X::f( ) const { (const_cast(this)) -> ++r; } //通过this指针q行cd强制转换实现 另外一U方法就是用关键字Qmutable。如果你的成员变量在定义时是q个样子的: mutable int r ; 那么它就告诉~译器这个成员变量可以通过const成员函数改变。编译器׃会再理会对他的检查了? Q这个ȝq不错的?
]]> 关于CONST的用?? http://m.tkk7.com/Archangelsy/articles/112827.htmlarchangel archangel Sun, 22 Apr 2007 14:45:00 GMT http://m.tkk7.com/Archangelsy/articles/112827.html http://m.tkk7.com/Archangelsy/comments/112827.html http://m.tkk7.com/Archangelsy/articles/112827.html#Feedback 0 http://m.tkk7.com/Archangelsy/comments/commentRss/112827.html http://m.tkk7.com/Archangelsy/services/trackbacks/112827.html
const在C语言中算是一个比较新的描q符Q我们称之ؓ帔R修饰W,意即其所修饰 的对象ؓ帔R(immutable)?br /> 我们来分情况看语法上它该如何被用?br /> 1、函C内修饰局部变量?br />例: void func(){ const int a=0; } 首先Q我们先把constq个单词忽略不看Q那么a是一个intcd的局部自动变量, 我们l它赋予初始??br /> 然后再看const. const作ؓ一个类型限定词Q和int有相同的C?br />const int a; int const a; 是等L。于是此处我们一定要清晰的明白,const修饰的对象是谁,是a,和int?br />有关pRconst 要求他所修饰的对象ؓ帔RQ不可被改变Q不可被赋|不可作ؓ 左|l-value)?br />q样的写法也是错误的?br />const int a; a=0; q是一个很常见的用方式: const double pi=3.14; 在程序的后面如果企图对pi再次赋值或者修改就会出错?br /> 然后看一个稍微复杂的例子?br />const int* p; q是先去掉const 修饰W号?br />注意Q下面两个是{h(hun)的?br />int* p; int *p; 其实我们惌说的是,*p是intcd。那么显Ӟp是指向int的指针?br />同理 const int* p; 其实{h(hun)?br />const int (*p); int const (*p); 卻I*p是常量。也是_p指向的数据是帔R?br />于是 p+=8; //合法 *p=3; //非法Qp指向的数据是帔R?br /> 那么如何声明一个自w是帔R指针呢?Ҏ(gu)是让const可能的靠近p; int* const p; const右面只有p,昄Q它修饰的是p,说明p不可被更攏V然后把constLQ可?br />看出p是一个指?int形式变量的指针?br />于是 p+=8; //非法 *p=3; //合法 再看一个更复杂的例子,它是上面二者的l合 const int* const p; 说明p自己是常量,且p指向的变量也是常量?br />于是 p+=8; //非法 *p=3; //非法 const q有一个作用就是用于修饰常量静态字W串?br />例如Q?br />const char* name="David"; 如果没有const,我们可能会在后面有意无意的写name[4]='x'q样的语句,q样?br />D对只d存区域的赋|然后E序会立d常终止。有?const,q个错误?br />能在E序被编译的时候就立即查出来,q就是const的好处。让逻辑错误在编?br />期被发现?br /> const q可以用来修饰数l?br />const char s[]="David"; 与上面有cM的作用?br /> 2、在函数声明时修饰参?br />来看实际中的一个例子?br />NAME memmove -- copy byte string LIBRARY Standard C Library (libc, -lc) SYNOPSIS #include <string.h> void * memmove(void *dst, const void *src, size_t len); q是标准库中的一个函敎ͼ用于按字节方式复制字W串Q内存)?br />它的W一个参敎ͼ是将字符串复制到哪里去(dest),是目的地Q这D内存区域必?br />是可写?br />它的W二个参敎ͼ是要什么样的字W串复制出去Q我们对q段内存区域只做?br />取,不写?br />于是Q我们站在这个函数自q角度来看Qsrc q个指针Q它所指向的内存内所?br />储的数据在整个函数执行的q程中是不变。于是src所指向的内Ҏ(gu)帔R。于是就 需要用const修饰?br />例如Q我们这里这样用它?br />const char* s="hello"; char buf[100]; memmove(buf,s,6); //q里其实应该用strcpy或memcpy更好 如果我们反过来写Q?br />memmove(s,buf,6); 那么~译器一定会报错。事实是我们l常会把各种函数的参数顺序写反。事实是~?br />译器在此时帮了我们大忙。如果编译器静?zhn)?zhn)的不报错,(在函数声明处L const卛_),那么q个E序在运行的时候一定会崩溃?br /> q里q要说明的一Ҏ(gu)在函数参数声明中const一般用来声明指针而不是变量本w?br />例如Q上面的size_t len,在函数实现的时候可以完全不用更改len的|那么是否 应该把len也声明ؓ帔R呢?可以Q可以这么做。我们来分析q么做有什么优劣?br />如果加了const,那么对于q个函数的实现者,可以防止他在实现q个函数的时候修 改不需要修改的?len),q样很好?br />但是对于q个函数的用者, 1。这个修饰符h无意义,我们可以传递一个常量整数或者一个非帔R整数q?br />去,反正Ҏ(gu)获得的只是我们传递的一个copy?br />2。暴露了实现。我不需要知道你在实现这个函数的时候是否修改过len的倹{?br /> 所以,const一般只用来修饰指针?br /> 再看一个复杂的例子 int execv(const char *path, char *const argv[]); 着重看后面q个Qargv.它代表什么?br />如果Lconst,我们可以看出 char * argv[]; argv是一个数l,它的每个元素都是char *cd的指针?br />如果加上const.那么const修饰的是谁呢Q他修饰的是一个数l,argv[],意思就?br />说这个数l的元素是只ȝ。那么数l的元素的是什么类型呢Q是char *cd的指 ?也就是说指针是常量,而它指向的数据不是?br />于是 argv[1]=NULL; //非法 argv[0][0]='a'; //合法 3、全局变量?br />我们的原则依然是Q尽可能的使用全局变量?br />我们的第二条规则 则是Q尽可能多的使用const?br />如果一个全局变量只在本文件中使用Q那么用法和前面所说的函数局部变量没有什 么区别?br />如果它要在多个文仉׃nQ那么就牉|C个存储类型的问题?br /> 有两U方式?br />1.使用extern 例如 /* file1.h */ extern const double pi; /* file1.c */ const double pi=3.14; 然后其他需要用piq个变量的,包含file1.h #include "file1.h" 或者,自己把那句声明复制一遍就好?br />q样做的l果是,整个E序链接完后Q所有需要用piq个变量的共享一个存储区域?br /> 2.使用static,静态外部存储类 /* constant.h */ static const pi=3.14; 需要用这个变量的*.c文g中,必须包含q个头文件?br />前面的static一定不能少。否则链接的时候会报告说该变量被多ơ定义?br />q样做的l果是,每个包含了constant.h?.c文gQ都有一份该变量自己的copy, 该变量实际上q是被定义了多次Q占用了多个存储I间Q不q在加了static关键?br />后,解决了文仉重定义的冲突?br />坏处是浪费了存储I间Q导致链接完后的可执行文件变大。但是通常Q这个,小 几字节的变化Q不是问题?br />好处是,你不用关心这个变量是在哪个文件中被初始化的?br /> 最后,说说const的作用?br />const 的好处,是引入了帔R的概念,让我们不要去修改不该修改的内存。直接的 作用是让更多的逻辑错误在编译期被发现。所以我们要可能的多用const?br />但是很多人ƈ不习惯用它Q更有甚者,是在整个E序 ~写Q调?完后才补 const。如果是l函数的声明补const,好。如果是l?全局Q局部变量补const,?br />么……那么,为时已晚Q无非是让代码看h更漂亮了?/div>
]]> c++全局变量 的问?可能是~?/title> http://m.tkk7.com/Archangelsy/articles/104499.htmlarchangel archangel Sat, 17 Mar 2007 11:25:00 GMT http://m.tkk7.com/Archangelsy/articles/104499.html http://m.tkk7.com/Archangelsy/comments/104499.html http://m.tkk7.com/Archangelsy/articles/104499.html#Feedback 0 http://m.tkk7.com/Archangelsy/comments/commentRss/104499.html http://m.tkk7.com/Archangelsy/services/trackbacks/104499.html
遇到一个怪现象?/span>
写的
VC
E序打开Q再关闭Q就会提C异常?/span>
q个E序使用?/span>
ADO
?/span>
一开始定义了一个全局的:
CAdoConnection conn;
后面每个c都直接用了
conn.
~~
但是
全局变量在初时化前引入,
在退出时自动释放Q无法控刉攄地方?/span>
但用指针Q?/span>
CAdoConnection *pConn;
pConn = new CAdoConnection();
pConn->
~~
可以控制它的释放了Q?/span>
delete
pConn;
好像是这个道理吧?/span>
]]> time函数 http://m.tkk7.com/Archangelsy/articles/104498.htmlarchangel archangel Sat, 17 Mar 2007 11:19:00 GMT http://m.tkk7.com/Archangelsy/articles/104498.html http://m.tkk7.com/Archangelsy/comments/104498.html http://m.tkk7.com/Archangelsy/articles/104498.html#Feedback 1 http://m.tkk7.com/Archangelsy/comments/commentRss/104498.html http://m.tkk7.com/Archangelsy/services/trackbacks/104498.html 阅读全文 ]]>
վ֩ģ壺
һ |
þ4438 |
avר |
δʮ˽˸ӰԺ |
AVרӰ
|
ëƬڵ |
ŷղ |
һƵ
|
ƷһëƬ |
avþDz |
Ʒަv |
ľƷŮ |
ۺɫ¶ |
ҹҹҹҹƵ |
һҳ |
gavѲƵ |
18ŮվɫƬѹۿ |
97Ʒѹۿ |
վѹۿ |
Ƶ |
Ƶѹۿwww |
һëƬ |
ƯŮ |
ۺ |
椸Ƶۿ |
þѹۿƷ88av |
Ƶ |
ƷͼƬ |
av뾫Ʒվ |
Ʒһ |
Ů18һëƬѹۿ |
ƵĻȫ |
Ʒ˳վ |
Avۺ辫Ʒ |
¶ۺƵ |
ƵŷƵ |
þ99Ʒۿ |
츾AV߲ |
˳ɹƷ |
һ |
ձvƬһ |