RSS 2.0 Feed
编译(CodeGen)
摘要: C语言中并未规定char、int和long这样的基本类型的长度和符号。这给与了编译器很大的灵活性,但是也产生了很多问题。 int是程序中最常用的类型。理论上来说,int应该被定义为CPU中运算最快的类型,比如80386系列中的32位整数。在升级程序到64位CPU环境的时候,应该可以重新编译程序来把32位运算升级到64位运算以增加性能。但是太多代码不正确地使用int和long来做指针运算,以至于会在升级时崩溃。目前很多64位编译器中的int仍然是32位,在有的编译器中甚至连long也仍旧是32位,而引入新的数据类型来代表64位变量。 另外一个问题是基本类型的符号。在Visual C++中,基本类型是有符号的,如果在开发时使用无符号修饰符的基本类型的话,这会在移植程序到使用无符号基本类型的编译器时出现问题。举例来说,在基本类型的符号不同的情况下,下面两行代码int b=-1;unsigned int a=b; int b=-1;b>>5; 的行为会有所不同。Visual C++ 2005编译器开发人员试图关闭/J开关(这个开关决定char是unsigned还是signed),并且用改进的警告功能来在编译未指定符号的基本类型时给出警告信息。但是这会使得绝大多数代码工作不正常,用户的负面反馈淹没了这个动议。 为了代码的可移植性起见,建议在使用基本类型的时候加上符号修饰符。...[阅读全文]

posted @ | Feedback (4) | Filed Under [ 编译(CodeGen) 语言(Language) ]

摘要:好长时间没更新BLOG了,向大家拜个晚年先。最近没怎么写代码,转几篇在网易虚拟社区发的文章过来充数。 对于BUG的自信 Donald E. Knuth(高德纳)在TeX: The Program的前言中说:"我相信,在1985年11月27日,TeX代码里面的最后一个BUG已经被发现和解决了。但是,如果代码中仍旧有BUG,我很高兴付给任何第一个发现BUG的人20.48美元(这是前一个金额的两倍,而且我计划在一年内把它翻倍。你看,我很自信!)" 想知道后来发生了什么吗?在http://truetex.com/knuthchk.htm可以看到他写出去的支票的金额是从2.56美元开始翻倍的。微基百科中关于这种支票的文章(http://en.wikipedia.org/wiki/Knuth_reward_check)说,截至2001年10月为止,他写出去了超过两千张这样的支票,但是他的BUG支票是如此有名,以至于很多人把他的支票收藏起来而不是拿出去兑现(http://www.tug.org/whatis.html)。有多少程序员在发布产品的时候可以这样自信地声明产品没有问题? 遗憾的是,现在的程序员经常把发现BUG的责任推给测试人员——“不用担心,测试人员会发现所有BUG的,这是他们的工作”。实际上,测试人员并没有开发人员的条件,他们不可能进行源代码级别的调试,很大程度上只能靠运气——没错,是靠运气,如果一个BUG很容易被发现,程序员不太可能自己没有发现它——来发现BUG。 还有一些人干脆就认为BUG是不可避免的,或者认为不值得这么精益求精(参见网易虚拟社区http://p5.club.163.com/viewArticleByWWW.m?boardId=clanguage&articleId=clanguage_108eacc622169e7&boardOffset=0的讨论),但是实际上防止BUG出现的最好的时机,就是在编写代码的时候。在编写代码一段时间之后,即使是编写者本人也可能需要一段时间来理解代码(如果不习惯写注释的话,这段时间会更长),更别说定位问题所在了。在编写代码时,如果具有良好的习惯,可以免去很多在之后消灭BUG的困难。 规范不是语法 太多人把不要使用goto奉为圣旨,从来不想去打破。他们会争论,goto会造成难以维护的难读的代码,以及使编译器无法进行优化。这两点在很大程度上是真的,但是也有使用goto可以增加程序可读性和效率时候。在这种情况下,遵循“不使用goto语句”规范会产生更糟糕的代码。一些人喜欢在成员函数后面加const,但是另外一些人没有养成这个习惯。一个直接的结果就是,一些看起来对对象完全没有影响的函数不能在const函数里面使用。这时候应该怎么办?看看Paul DiLascia建议的,把this指针强行转化为一个非const指针(http://www.microsoft.com/msj/archive/S126E.aspx)。如果函数实际上会对对象成员造成影响(例如CToolBar::GetItemRect),这也会带来潜在危险。为了和ANSI标准之前编写的代码兼容,ANSI C中的memchr函数的声明为void *memchr( const void *buf, int c, size_t count ); 这里c是一个字符。很明显,标准为了兼容性放弃了明确性和更强的类型检查。如果放弃兼容性,这个函数应该声明为如下形式void *memchr( const void *buf, unsigned char c, size_t count ); 微软的很多代码使用一种叫做匈牙利表示法的命名规范。这使得标识符的含义和类型更加明确——但是这是从广义的角度来说的。考虑如下函数声明char *strcpy( char *strDestination, const char *strSource ); 如果严格遵循原始的匈牙利表示法,那么两个参数的声明应该是pch开头。但是以str开头给这两个参数更多含义:它们指向以\0为结束符的字符串。   规范是用来在大部分时间里遵循,以及在可以得到更好的结果时打破的。 编译警告的意义 智能化的编译器开始将语法正确的语句列为警告:while(size-->0);//注意这里有个分号 *pTo++=*pFrom++; 编译器会报告空循环问题。但是对于以0结尾的字符串复制while(*pTo++=*pFrom++); ,这样的警告是多余的。更加常见的警告是在条件判断语句中if(ch='\0') EndOfString(); 为了绕过这个警告,需要添加额外的运算或者语句,或者更正错误的赋值。while((*pTo++=*pFrom++)!='\0')...{} if(ch=='\0') 一些程序员甚至将比较语句修改成if('\0'==ch) 这样作的原因显而易见:为了减少潜在的BUG。如果你的编译器没有这样的警告,那么你可以使用一些工具来检查那些语法正确但是有潜在BUG的代码。LintProject (http://www.codeproject.com/tools/lintproject.asp)就是其中一个。但是,良好的编程习惯还是减少BUG出现的最好的方法。在觉得警告消息太烦人的时候,不妨想想编译器的开发人员为什么要编写这么多警告消息,而不是仅仅寻求关闭警告的方法。 P.S. Visual C++的默认警告等级是3级。发布软件之前应该改成4级,之后检查所有的编译警告。 无处不在的断言 使用编译器来捕获BUG的主意很好,Visual Studio 2005甚至会报告定义的变量不符合命名规范(Warning 1 CA1709 : Microsoft.Naming : Correct the casing of type name 'welcome'.);但是我敢打赌你检查BUG列表的时候,你会发现只有一小部分BUG会被编译器抓到。很多BUG在程序运行过程中很少会出现,例如内存分配失败的问题using namespace System; #define ARRAY_SIZE 1000 struct bubbleBase ...{ int value; }; class bubble1:public bubbleBase ...{ public: virtual int getvalue()...{return value;} virtual void setvalue(int newvalue)...{value=newvalue;} }; class bubble2:public bubbleBase ...{ public: virtual int __clrcall getvalue()...{return value;} virtual void __clrcall setvalue(int newvalue)...{value=newvalue;} }; template<class T> void bubbleSort(int length) ...{ TimeSpan ts; T* array1=new T[ARRAY_SIZE]; for (int i=0;i<ARRAY_SIZE ;i++) ...{ array1[i].setvalue(ARRAY_SIZE-i-1); } ......[阅读全文]

posted @ | Feedback (1) | Filed Under [ 随笔 .Net Framework 编译(CodeGen) 类库(Library) 语言(Language) C++/CLI/Managed C++ Extension ]

摘要:C#程序员可以用三个斜杠来开始XML格式的注释,而且编译器可以据此生成可用于自动生成帮助文档的XML文件。Visual C++ 2005中的编译器也支持了这个功能,而且对非托管函数也生效,前提是必须打开/clr和/DOC开关,并且不能使用/clr:oldSyntax开关编译。/**//// ///Use two bubble sort steps ///to show the performance information ///of different function calls. /// int main(array<System::String ^> ^args) ...{ bubbleSort<bubble1>(ARRAY_SIZE); bubbleSort<bubble2>(ARRAY_SIZE); return 0; } #pragma unmanaged /**//// ///testing unmanaged function... /// int foo() ...{ return 0; } 有空的话,多去微软的反馈中心提提对产品的建议是很有好处的…… 参考 /doc (Process Documentation Comments) (C/C++)( http://msdn2.microsoft.com/en-us/library/ms173501.aspx ) XML Comments for Managed C++ Applications (http://www.codeproject.com/dotnet/MCXDoc.asp) NDoc Code Documentation Generator for .NET(http://ndoc.sourceforge.net)...[阅读全文]

posted @ | Feedback (3) | Filed Under [ 编译(CodeGen) 集成开发环境(IDE) 语言(Language) C++/CLI/Managed C++ Extension ]

摘要:目前版本的VC2005测试版中,default关键字不仅用于指定类级别的索引器,而且也用于访问默认属性。但是奇怪的是,默认属性的原名不能访问了,也就是说,如果要把下面的代码段从托管C++移植到VC2005附带的C++/CLI,不仅需要更改指针的类型,而且要把属性的名称更改为default: //[System::Reflection::DefaultMemberAttribute("Fields")] interface _Recordset//托管C++语法//extern _Recordset* results;Fields* ResultFields=results->Fields;//C++/CLI语法//extern _Recordset^ results;Fields^ ResultFields=results->default; 如果继续使用原来名字来访问属性的话,会报告编译错误: Fields^ ResultFields=results->Fields;//C3293: 'Fields': use 'default' to access the default property (indexer)。 这是一个Breaking Change。在语言规范中,默认索引属性只使用一个名字“default”,而且只有这一个实现。更进一步,默认索引属性只能用如下方式访问: obj[index] obj->default[index] obj->default::get(index) obj->default::set(index, value) 顺便说一下,在C++/CLI中也可以使用类似C#里面的for each语句了( http://msdn2.microsoft.com/library/ms177202(en-us,vs.80).aspx),而且对于非托管的STL容器也有效,不过看起来真不习惯。 参考 New C++ Language Features (http://msdn2.microsoft.com/library/xey702bw(en-us,vs.80).aspx) Breaking Changes in the Visual C++ 2005 Compiler(http://msdn2.microsoft.com/library/ms177253(en-us,vs.80).aspx)...[阅读全文]

posted @ | Feedback (0) | Filed Under [ .Net Framework 编译(CodeGen) C++/CLI/Managed C++ Extension ]

摘要:程序员在我看来是比较会偷懒的一个群体。为了在开发软件的时候减少人工操作,他们会使用各种各样的软件和语言特性,例如IDE和预处理宏。李建忠在他的BLOG(http://blog.joycode.com/lijianzhong/archive/2005/05/08/50440.aspx)中提到,为了简化声明属性的工作,他的同事自己写了一些小工具来生成需要的代码。在C++托管扩展中,这个工作稍微简单一些,用预处理宏就可以了。 #define   DECLARE_PROPERTY_DOUBLE_PUBLIC(propertyName)\protected:\   double _##propertyName;public:\   __property double get_##propertyName(){ return _##propertyName; }\   __property void set_##propertyName( double new_##propertyName ){ _##propertyName= new_##propertyName; } public __gc __sealed class Vector {public:   // ...   DECLARE_PROPERTY_DOUBLE(x)   DECLARE_PROPERTY_DOUBLE(y)   DECLARE_PROPERTY_DOUBLE(z) }; 当然,如果使用C++/CLI的话,这个工作更加简单: public ref class Vector sealed{ public:    property double x;     property double y;    property double z;}; 我在编程的时候也是个彻底的实用主义者,需要大量重复编写的代码都是尽量用宏实现。例如,我用如下的宏来简化CCmdTarget派生类对IOleCommandTarget类的处理: #define DECLARE_IOLECOMMANDTARGET\    STDMETHOD(QueryStatus)(const GUID* pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [],OLECMDTEXT* pcmdtext);\    STDMETHOD(Exec)(const GUID*,DWORD nCmdID, DWORD nCmdExecOpt,VARIANTARG* pvarargIn, VARIANTARG* pvarargOut); #define IMPLEMENT_IOLECOMMANDTARGET(theClass,localclass)\STDMETHODIMP theClass::X##localclass::Exec(const GUID* pguidCmdGroup,DWORD nCmdID, DWORD nCmdExecOpt,VARIANTARG* pvarargIn, VARIANTARG* pvarargOut)\{\ METHOD_PROLOGUE_EX(theClass, localclass)\ ASSERT_VALID(pThis);\ return pThis->Exec(pguidCmdGroup,nCmdID,nCmdExecOpt,pvarargIn,pvarargOut);\}\STDMETHODIMP theClass::X##localclass::QueryStatus(const GUID* pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[],OLECMDTEXT* pcmdtext)\{\ METHOD_PROLOGUE_EX(theClass, localclass)\ ASSERT_VALID(pThis);\ return pThis->QueryStatus(pguidCmdGroup,cCmds,prgCmds,pcmdtext);\} #define IMPLEMENT_LOCALCLASS_UNKNOWN(theClass,localclass) \STDMETHODIMP_(ULONG) \theClass::X##localclass::AddRef() \{ \ METHOD_PROLOGUE_EX(theClass, localclass) \ ASSERT_VALID(pThis); \ return pThis->ExternalAddRef(); \} \\STDMETHODIMP_(ULONG) \theClass::X##localclass::Release() \{ \ METHOD_PROLOGUE_EX(theClass, localclass) \ ASSERT_VALID(pThis); \ return pThis->ExternalRelease(); \} \STDMETHODIMP theClass::X##localclass::QueryInterface( \REFIID iid, LPVOID* ppvObj) \{ \ METHOD_PROLOGUE_EX(theClass, localclass) \ ASSERT_VALID(pThis); \ return pThis->ExternalQueryInterface(&iid, ppvObj); \}  这样要在CCmdTarget派生类中实现IOleCommandTarget接口的话,只需要编写实现函数就行了: //声明class CScreenCaptureGDI : public CScreenCaptureBase{   DECLARE_OLECOMMANDTARGET……   DECLARE_INTERFACE_MAP()   BEGIN_INTERFACE_PART(OleCommandTarget, IOleCommandTarget)    DECLARE_OLECOMMANDTARGET   ......[阅读全文]

posted @ | Feedback (7) | Filed Under [ 随笔 编译(CodeGen) 文档(Documentation) 语言(Language) C++/CLI/Managed C++ Extension ]

摘要: 创建一个win32DLL工程,从DXSDK示例Ball复制代码之后就出这个问题 Deleting intermediate files and output files for project 'FScrCap - Win32 Debug'.--------------------Configuration: FScrCap - Win32 Debug--------------------Compiling...Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86Copyright Microsoft Corp 1984-1998. All rights reserved.cl? /MTd /Ze /W3 /Gm /Gi /GR- /GX /ZI /Od /D WIN32 /D _DEBUG /D _WINDOWS /D _MBCS /D _USRDLL /D FSCRCAP_EXPORTS /FpDebug/FScrCap.pch /Ycstdafx.h /FoDebug/ /FdDebug/ /FD /GZ /c F:\code\test\DirectShow\FScrCap\StdAfx.cppStdAfx.cppCompiling...Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86Copyright Microsoft Corp 1984-1998. All rights reserved.cl? /MTd /Ze /W3 /Gm /Gi /GR- /GX /ZI /Od /D WIN32 /D _DEBUG /D _WINDOWS /D _MBCS /D _USRDLL /D FSCRCAP_EXPORTS /FpDebug/FScrCap.pch /Yustdafx.h......[阅读全文]

posted @ | Feedback (9) | Filed Under [ CSDN 编译(CodeGen) 调试技巧(Debugging) 多媒体(Multimedia) 集成开发环境(IDE) 平台SDK(Platform SDK) ]