c 学习总结| 耗时:0.222秒|74860条结果

总结C#学习

  寻求一套可以练习C#全方面知识点的练习题。   包含     1、C# 基础知识(类型、变量、类型转换、表达式、面向对象、C#语法、泛型、委托、异步委托、部分类、异常处理、垃圾回收、特性、Lambda表达式、LINQ语言集成查询
http://www.itnose.net/detail/528364.html 2014-02-08 11:25   [C#语言]

C#基础学习总结

1.C#基础思维导图 --------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------- 通过对C#基础知识的学习让我对对C#有了一定的了解,在学习
http://www.itnose.net/detail/6740443.html 2017-04-10 01:06   [C#语言]

C语言学习总结

        最近公司指派任务,为平台3.0下一阶段研发工作对PG进行研究,其实PG的移植工作一直由算法部在负责,但是PG移植后的任务却是担当这整个平台软件的底层数据存储,事务处理,数据挖掘等方面工作,所以就索性将这一快拿到了平台部来做。因为我所负责的RCP这部分在功能性上基本上也算是告一段落,目前主要就是带带新人,在框架型上进一些指导工作,而学习C语言对我来说有两大好处:1.考试是需要考C和数据结构的;2.学习C语言能够帮助我理解程序在执行过程中的运行情况,能更清楚的了解计算机底层结构。         在近两周对PG代码的阅读中对C和系统底层都有了更进一步的了解,就进程而言,以前根本不理解,只知道程序运行就需要一个进程,对进程包含那些东西,创建进程需要那些资源,都是毫无概念的,在阅读PG代码的过程中通过网上、书籍的查阅后,对进程有了进一步的了解。         学习C语言最难的无疑是指针,几乎每一位C语言学习者在处理指针问题上都是伤透脑经的。因为你要真正搞懂C程序,你就必须知道指针所指向的内容是什么?是指向具体数值、是指向内存地址、数组、亦或是函数等等。因为指针是unsafe的,所以在开发的时候脑子里一定要对内存结构有一个清晰的认识,否这就很有可能出现堆栈溢出的错误了。作为总结,那就把学习的经验记下来,以后再次翻阅时也好有一个提示:在阅读指针时首先从未定一标识符开始,遇到扩符变向解析,如此反复,直至定义结束。         在PG这种多进程程序中,进程间是如何通讯的呢?我们都知道线程通讯可以采用互斥锁来实现,那么进程通讯如何实现呢?在PG中是采用共享内存的方式实现的(还有没有其他的方式我不知道),在主进程中创建内存虚拟文件镜像映射表,各个子进程通过同步信号量来决定是否进入访问共享内存,从而实现进程间通信的。         C语言中字符串处理对我来说是一个大问题,在高级编程语言(C#、JAVA)中我可以轻松的采用StringBuilder或是String.Format()等方式来实现字符串的拼接,而C中即便是处理这么一个小小的字符串拼接问题都会用到指针,相当头痛。         唯一值得庆幸的是在经过N多天的努力后,终于将PG跑起来,并且能够DEBUG了。
http://www.itnose.net/detail/482605.html 2014-01-23 17:59   [C语言]

C++单元测试学习总结

; {         int bodyLength = 0;         bool ret = false;             /// get the message body length from the message         try         {               char buf[HeaderLength + 1] = "";               std::strncat( buf, Data_, HeaderLength );               bodyLength = boost::lexical_cast<int> (buf);                   if( bodyLength > MaxBodyLength )               {                     bodyLength = MaxBodyLength;                             }               else               {                     ret = true;               }         }         catch(boost::bad_lexical_cast& e)         {               /// cast error happens               bodyLength = 0;                   TraceLog::WriteLine("Message::DecodeHeader(),error:%s, orinal message:%s",  e.what(), Data_ );         }             /// set the value and return         BodyLength_ = bodyLength;         return ret;   }       char* Message::Data()   {         return Data_ ;   }       const char* Message::Data() const   {         return Data_ ;   }       char* Message::Body()   {         return Data_ + HeaderLength;   }       const char* Message::Body() const   {         return Data_ + HeaderLength;   }       int Message::SetData(const char* src, const int srclength)   {         /// check the length of source         int length = srclength;         if( length > MaxBodyLength )         {               length = MaxBodyLength;         }             /// copy the data into the local buffer         /// std::snprintf is unavailable in this c++ compiler         int ret = ::_snprintf_s(Data_+HeaderLength, MaxBodyLength + 1, length, "%s", src );                /// set the length of the message body         BodyLength_ = length;             /// return the length of copied         return ret;   }       int Message::Length() const   {         return BodyLength_ + HeaderLength;   }       int Message::BodyLength() const   {         return BodyLength_;   }       void Message::Reset()   {         BodyLength_ = 0;             /// just for using the lamda         std::for_each(Data_, Data_ + HeaderLength + MaxBodyLength + 1, [](char& p) { p =  '\0'; } );   }   ChatRoom类代码 [cpp] view plain copy /// ChatRoom.h   #pragma once   #include "ChatSession.h"   #include "Message.h"   #include <set>   #include <queue>       /// class that manages the clients   /// deliver the messages from one client to the others       class ChatRoom   {   public:         ChatRoom(void);         ~ChatRoom(void);       public:         /// a client joins in the room         void Join(ChatParticipantPtr participant);             /// a client leaves the room         void leave(ChatParticipantPtr participant);             /// deliver the message from one client to all of the users in the room         void Deliver(const Message& msg);       private:         /// all of the participants are stored here         std::set<ChatParticipantPtr> Participants_;             /// recent messages         /// questions, how to synchronize this object in threads         typedef std::deque<Message> MessageQueue;         MessageQueue RecentMessages_;         enum { MaxRecentMsgs = 100 };   };           /// ChatRoom.cpp   #include "ChatRoom.h"   #include <boost/bind.hpp>   #include <algorithm>   #include "TraceLog.h"       ChatRoom::ChatRoom(void)   {   }           ChatRoom::~ChatRoom(void)   {   }       /// a client joins in the room   void ChatRoom::Join(ChatParticipantPtr participant)   {         TraceLog::WriteLine("ChatRoom::Join(), a new user joins in");             /// add into the queue         Participants_.insert( participant );             /// sending the recent message to the client         std::for_each(RecentMessages_.begin(), RecentMessages_.end(),               boost::bind( &ChatParticipant::Deliver, participant, _1 ) );   }          /// a client leaves the room   void ChatRoom::leave(ChatParticipantPtr participant)   {         TraceLog::WriteLine("ChatRoom::leave(), a user leaves");             /// remove it from the queue         Participants_.erase( participant );   }          /// deliver the message from one client to all of the users in the room   void ChatRoom::Deliver(const Message& msg)   {         TraceLog::WriteLine("ChatRoom::Deliver(), %s", msg.Body() );             /// add the msg to queue         RecentMessages_.push_back( msg );             /// check the length         while( RecentMessages_.size() > MaxRecentMsgs )         {               RecentMessages_.pop_front();         }             /// deliver the msg to clients         std::for_each(Participants_.begin(), Participants_.end(),               boost::bind( &ChatParticipant::Deliver, _1, boost::ref(msg) ) );   }   开始单元测试 由于到手了VisualStudio 2012,这货已经原始支持了C++Native代码的单元测试,就用这货开始做 UT吧。 如何引入被测代码 好了,我们开始单元测试。首先创建一个C++单元测试的工程,这个很easy。接着我们就要让测 试工程能够“看到”被测的代码,这如何搞呢?有这样几种方法: 如果被测代码是静态库或者动态库,包含对应的.h文件,让测试工程链接DLL及LIB,这样测试工 程。 或者,让测试工程链接对应的obj文件,直接编译进测试工程 或者,直接把被测是的代码,如上述的Message.h和Message.cpp包含进测试工程(注意这里不 要拷贝一份Message.h和Message.cpp,用“Add->ExsitingItem”将他们包含进去,这样只保 留一份代码)  或者在单元测试代码文件,如TestMessage.cpp中直接用#include把Message.h和Message.cpp 包含进来,如:                 #include "../ChatroomServer/ChatRoom.h"                #include "../ChatroomServer/ChatRoom.cpp" 上面这几种方法,其实原理都是一样的,反正就是让测试工程能够看到到被测的代码,我们使用把 被测代码引入测试工程的方法,这样测试工程的代码结构看起来是这样: Ok,现在在测试工程里面,可以看到Message类的声明和定义了,然后你的单元测试代码,该怎 么写,就怎么写了。 一个测试工程只能测一个类吗? 使用VS2012中的单元测试框架,写完了对Message的的单元测试,在TestExplorer中RunAll,一 切正常;好了,至此,一切还算顺利,那我们继续吧,来对ChatRoom类编写单元测试; 继续按照前面的方法,我们很容易让测试工程看到ChatRoom的被测代码;然而从ChatRoom的 实现来看,这个类和Message类有着关联关系,而且在ChatRoom的方法中,也的确使用了 Message类的方法,从单元测试的角度来看,我们应该将他们俩之间的关系隔断,从而保证我们 只对ChatRoom进行测试,那这样,我们就需要Mock一份Message的实现。 可是问题来了,由于之前我们在测试Message类的时候,已经引入了Message.cpp文件,使得测 试工程中,已经有了一份Message的实现,那么我们如何再能为Message提供一份“伪”实现呢 ??(使用其他几种引入方式,结果都是一样的) 是的,惯用的DependencyInjection在这里不起作用。查了不少资料,也没找到一个像样的说明 如何解决这个问题;现在唯一可以采用的,就是在一个测试工程里面,只测试一个被测类,虽然可 以工作,但是,未免又过于繁琐和“愚蠢”,那聪明的方法,又是什么呢?不瞒你说,这正是目前 困扰我的问题之一。 追加一个后记: 其实,在关于如何为Message提供一份“伪”实现的问题上,原来想法是在测试工程中包含 Message的头文件,然后在测试工程里面,直接写Message::Message()等方法,事实上是在测试 工程里面定义一个Message的实现;这样由于我们已经引入了Message的真正实现,从而必然导 致链接器报符号重复定义的错误,因此,这种思路并不可行,故而强迫我去创建另外一个工程;后 来想一想,其实也不必真的去创建一个新工程,他们是可以在一个工程里面完成的,方法是新建一 个MockMessage类,让他从Message继承下来,然后重新定义自己想Mock的方法就可以了。但 是,这种方法创建出来的Mock,还是真的Mock吗,他首先已经是一个“真”的Message了啊? ======== C/C++单元测试理论精要(一) http://blog.csdn.net/easytdd/article/details/5484405 内容介绍     本系列文章根据《单元测试与VU2.6应用》视频讲座的理论部分整理而成,主要讨论四个问题 :为什么需要单元测试?怎样征服可测性难题?怎样才能高效率测试?怎样保证测试效果?重点阐 述单元测试的关键问题,不是一般概念,适合于对单元测试有一定了解的读者。     在选择工具和实施单元测试前,我们应该对相关理论有一个系统的了解,特别是将会遇到哪些 难题,如何解决,要心里有数,否则的话,很可能劳民伤财,半途而废。如果只会测试加法函数或 者三角形函数之类的独立小程序,就以为可以做单元测试了,那就像一个人刚学会走路,就去长途 跋涉。     本文介绍的是针对企业项目的单元测试。企业项目具有两个特点:项目复杂,时间紧张。项目 复杂,意味着测试时会遇到很多难题;时间紧张,要求我们不但要保证测试效果,还要尽可能高效 率。本文不是泛泛而谈,而是针对企业项目的两个特点,努力揭示本质性的问题,并提出解决办法 ,对于常识性的问题,将比较简略的带过。使用的工具是Visual Unit 2.6,本文主要不是介绍工具 ,而是介绍问题所在和解决办法,涉及到工具,只是为了具体的展示解决办法,也为了说明,这些 办法都是可行的,并非空谈。 第1章 为什么需要单元测试? 1.1 从代码特性看单元测试的必要性     代码有一个很基本的特性,是什么呢?对数据分类处理。一个判定,就是一次分类。如果判定 中又嵌套了判定的话,分类次数就会翻倍。循环判定也是一种分类。     如果一个分类遗漏的话,也就是说,某种输入没有处理,会怎么样呢?一个Bug诞生了!如果 一个分类的处理不正确,又会怎么样呢?又一个Bug诞生了!     一个函数要做到没有错误,要保证两点:分类完整,也就是各类可能输入都要考虑到; 处理正确,也就是每一类输入都要进行正确的处理。做到了这两点,就可以说,函数的功能逻辑是 正确的。函数的功能逻辑就是对数据的分类以及处理。     那么,怎样才能全面地检测程序的功能逻辑呢?调试,是临时的,不做记录,另一方面,调试 的工作方式是拦截数据,并不是所有输入分类都能拦截得到的,如果一个函数有十类输入,调试能 覆盖五六个就不错了。系统测试,不针对具体的函数,无法做到对具体函数的输入分类覆盖。要全 面地检测程序的功能逻辑,必须把输入分类全部列出来。并检测程序是否处理了这些输入,处理是 否正确。这就是单元测试。 说明 本系列文章根据《单元测试与VU2.6应用》视频讲座的理论部分整理而成,PPT及视频下载: PPT下载:http://download.csdn.net/source/2246006 视频part1: http://download.csdn.net/source/2246273 视频part2: http://download.csdn.net/source/2246345 视频part3: http://download.csdn.net/source/2246364 本系列文章及视频讲座介绍的是单元测试理论的精要部分,详细内容请阅读《C/C++单元测试实 用教程》  ======== 玩转Google开源C++单元测试框架Google Test系列(gtest)之八 - 打造自己的单元测试框架 http://www.cnblogs.com/coderzh/archive/2009/04/12/1434155.html 一、前言 上一篇我们分析了gtest的一些内部实现,总的来说整体的流程并不复杂。本篇我们就尝试编写一 个精简版本的C++单元测试框架:nancytest ,通过编写这个简单的测试框架,将有助于我们理 解gtest。 二、整体设计 使用最精简的设计,我们就用两个类,够简单吧: 1. TestCase类 包含单个测试案例的信息。  2. UnitTest类 负责所有测试案例的执行,管理。 三、TestCase类 TestCase类包含一个测试案例的基本信息,包括:测试案例名称,测试案例执行结果,同时还提 供了测试案例执行的方法。我们编写的测试案例都继承自TestCase类。 复制代码 class TestCase { public:     TestCase(const char* case_name) : testcase_name(case_name){}     // 执行测试案例的方法     virtual void Run() = 0;     int nTestResult; // 测试案例的执行结果      const char* testcase_name; // 测试案例名称 }; 复制代码   四、UnitTest类 我们的UnitTest类和gtest的一样,是一个单件。我们的UnitTest类的逻辑非常简单: 1. 整个进程空间保存一个UnitTest 的单例。 2. 通过RegisterTestCase()将测试案例添加到测试案例集合testcases_中。 3. 执行测试案例时,调用UnitTest::Run(),遍历测试案例集合testcases_,调用案例的Run()方法 复制代码 class UnitTest { public:     // 获取单例     static UnitTest* GetInstance();      // 注册测试案例     TestCase* RegisterTestCase(TestCase* testcase);          // 执行单元测试     int Run();     TestCase* CurrentTestCase; // 记录当前执行的测试案例     int nTestResult; // 总的执行结果     int nPassed; // 通过案例数     int nFailed; // 失败案例数 protected:     std::vector<TestCase*> testcases_; // 案例集合 }; 复制代码 下面是UnitTest类的实现: 复制代码 UnitTest* UnitTest::GetInstance() {     static UnitTest instance;     return &instance; } TestCase* UnitTest::RegisterTestCase(TestCase* testcase) {     testcases_.push_back(testcase);     return testcase; } int UnitTest::Run() {     nTestResult = 1;     for (std::vector<TestCase*>::iterator it = testcases_.begin();         it != testcases_.end(); ++it)     {         TestCase* testcase = *it;         CurrentTestCase = testcase;         std::cout << green << "======================================"  << std::endl;         std::cout << green << "Run TestCase:" << testcase->testcase_name << std::endl;         testcase->Run();         std::cout << green << "End TestCase:" << testcase->testcase_name << std::endl;         if (testcase->nTestResult)         {             nPassed++;         }         else         {             nFailed++;             nTestResult = 0;         }     }     std::cout << green << "======================================"  << std::endl;     std::cout << green << "Total TestCase : " << nPassed + nFailed << std::endl;     std::cout << green << "Passed : " << nPassed << std::endl;     std::cout << red << "Failed : " << nFailed << std::endl;     return nTestResult; } 复制代码 五、NTEST宏 接下来定一个宏NTEST,方便我们写我们的测试案例的类。 复制代码 #define TESTCASE_NAME(testcase_name) \     testcase_name##_TEST #define NANCY_TEST_(testcase_name) \ class TESTCASE_NAME(testcase_name) : public TestCase \ { \ public: \     TESTCASE_NAME(testcase_name)(const char* case_name) : TestCase(case_name){}; \     virtual void Run(); \ private: \     static TestCase* const testcase_; \ }; \ \ TestCase* const TESTCASE_NAME(testcase_name) \     ::testcase_ = UnitTest::GetInstance()->RegisterTestCase( \         new TESTCASE_NAME(testcase_name)(#testcase_name)); \ void TESTCASE_NAME(testcase_name)::Run() #define NTEST(testcase_name) \     NANCY_TEST_(testcase_name) 复制代码   六、RUN_ALL_TEST宏 然后是执行所有测试案例的一个宏: #define RUN_ALL_TESTS() \     UnitTest::GetInstance()->Run(); 七、断言的宏EXPECT_EQ  这里,我只写一个简单的EXPECT_EQ : 复制代码 #define EXPECT_EQ(m, n) \     if (m != n) \     { \         UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \         std::cout << red << "Failed" << std::endl; \         std::cout << red << "Expect:" << m << std::endl; \         std::cout << red << "Actual:" << n << std::endl; \     } 复制代码   八、案例Demo 够简单吧,再来看看案例怎么写: 复制代码 #include "nancytest.h" int Foo(int a, int b) {     return a + b; } NTEST(FooTest_PassDemo) {     EXPECT_EQ(3, Foo(1, 2));     EXPECT_EQ(2, Foo(1, 1)); } NTEST(FooTest_FailDemo) {     EXPECT_EQ(4, Foo(1, 2));     EXPECT_EQ(2, Foo(1, 2)); } int _tmain(int argc, _TCHAR* argv[]) {     return RUN_ALL_TESTS(); } 复制代码 整个一山寨版gtest,呵。执行一下,看看结果怎么样: 九、总结  本篇介绍性的文字比较少,主要是我们在上一篇深入解析gtest时已经将整个流程弄清楚了,而现 在编写的nancytest又是其非常的精简版本,所有直接看代码就可以完全理解。希望通过这个 Demo,能够让大家对gtest有更加直观的了解。回到开篇时所说的,我们没有必要每个人都造一 个轮子,因为gtest已经非常出色的为我们做好了这一切。如果我们每个人都写一个自己的框架的 话,一方面我们要付出大量的维护成本,一方面,这个框架也许只能对你有用,无法让大家从中受 益。 gtest正是这么一个优秀C++单元测试框架,它完全开源,允许我们一起为其贡献力量,并能让更 多人从中受益。如果你在使用gtest过程中发现gtest不能满足你的需求时(或发现BUG),gtest 的开发人员非常急切的想知道他们哪来没做好,或者是gtest其实有这个功能,但是很多用户都不 知道。所以你可以直接联系gtest的开发人员,或者你直接在这里回帖,我会将您的意见转告给 gtest的主要开发人员。 如果你是gtest的超级粉丝,原意为gtest贡献代码的话,加入他们吧。    本Demo代码下载:/Files/coderzh/Code/nancytest.rar  本篇是该系列最后一篇,其实gtest还有更多东西值得我们去探索,本系列也不可能将gtest介绍完 全,还是那句话,想了解更多gtest相关的内容的话: 访问官方主页:http://code.google.com/p/googletest/ 下载gtest源码: http://code.google.com/p/googletest/downloads/list 系列链接: 1.玩转Google开源C++单元测试框架Google Test系列(gtest)之一 - 初识gtest 2.玩转Google开源C++单元测试框架Google Test系列(gtest)之二 - 断言 3.玩转Google开源C++单元测试框架Google Test系列(gtest)之三 - 事件机制 4.玩转Google开源C++单元测试框架Google Test系列(gtest)之四 - 参数化 5.玩转Google开源C++单元测试框架Google Test系列(gtest)之五 - 死亡测试  6.玩转Google开源C++单元测试框架Google Test系列(gtest)之六 - 运行参数 7.玩转Google开源C++单元测试框架Google Test系列(gtest)之七 - 深入解析gtest 8.玩转Google开源C++单元测试框架Google Test系列(gtest)之八 - 打造自己的单元测试框架   ======== 使用 Visual Studio 2015 对 C++ 代码运行单元测试 http://blog.csdn.net/lxf200000/article/details/51100094 代码写多了,往往规模会越来越大,这时候就有必要保证代码的稳定性了;不过我从网上看到的单 元测试貌似大多都是用的 JUnit, 难道 C++ 就没有了吗?我从网上找了一些方法试了下其实挺简 单的。下面我以一个示例作说明。(如果你有准备好的待测代码可直接看创建单元测试项目那里。 ) 创建一个 Win32 空项目“stg”并添加下面的代码用作测试。这里我创建了一个结构体用来表示 一个物体,有X,Y,半径这些变量,还有一个用来表示另一个物体是否在它的半径内的函数,是 则返回1,否则为0。 【stg.h】 [cpp] view plain copy #pragma once   struct SpriteType   {       SpriteType();       void SetValue(float, float, float, float);       int IsShotBy(SpriteType*);   private:       float posX, posY, shotRadius, sensedRadius;       float _temp0;   };   【stg.cpp】 [cpp] view plain copy #include<cmath>   #include"stg.h"      SpriteType::SpriteType() :posX(0.0f), posY(0.0f), shotRadius(0.0f), sensedRadius(0.0f)   {      }      void SpriteType::SetValue(float x, float y, float rshot, float rsensor)   {       posX = x, posY = y, shotRadius = rshot, sensedRadius = rsensor;   }      int SpriteType::IsShotBy(SpriteType *pOtherSprite)   {       _temp0 = sqrtf((pOtherSprite->posX - posX)*(pOtherSprite->posX - posX) +  (pOtherSprite->posY - posY)*(pOtherSprite->posY - posY));       return (int)(_temp0 < shotRadius);   }   (为了简单我把 main 函数省略了。) 然后是创建单元测试项目。在这个解决方案中创建一个名为 stgTest 的单元测试工程(命名规则是 “项目名”+Test), 创建好后在引用中添加待测项目的引用(右键引用选择“添加引用项目”), 点确定,它应该会出现在单元测试工程的引用中。 然后在“stg”项目上右键选择属性,将其配置类型改为静态库(你可以在测试完后改回为应用程 序) 接下来找到单元测试的代码,其文件名默认为“unittest1.cpp”,最好也改为“stgTest.cpp”以 便区分;在这个代码中有一个默认的方法“TestMethod1”,它是由宏“TEST_METHOD”定义 的一个函数,这个函数就是用来作测试的,运行测试时它里面的代码会执行,测试结果由 Assert  中的一系列函数决定。另外两个 宏“TEST_METHOD_INITIALIZE”,“TEST_METHOD_CLEANUP”分别用于定义测试开始前与 结束后执行的函数,通常将函数名定义为“SetUp”和“TearDown”(或许是因为 JUnit 中就是 这样的?)。这里我将默认的“TestMethod1”改为“TestShot”(命名规则为 Test+“函数名 ”),然后包含头文件 #include“..\stg\stg.h”,加入测试代码后形成下面这个样子: 【stgTest.cpp 中的部分代码】 [cpp] view plain copy namespace AmIShotTest   {              TEST_CLASS(UnitTest1)       {       private:           SpriteType *s1, *s2;       public:           TEST_METHOD_INITIALIZE(SetUp)           {               s1 = new SpriteType();               s2 = new SpriteType();               Logger::WriteMessage("Test initialized.\n"); //用于输出信息           }              TEST_METHOD_CLEANUP(TearDown)           {               delete s1;               delete s2;               Logger::WriteMessage("Test completed.\n");           }              TEST_METHOD(TestShot)           {               s1->SetValue(2.0f, 3.0f, 1.2f, 1.5f);               s2->SetValue(2.2f, 3.1f, 0.0f, 0.0f);               Assert::AreEqual<int>(1, s1->IsShotBy(s2));               Logger::WriteMessage("Shot tested.\n");           }       };   }   上面 AreEqual 那句中,模板填入待测值的类型,第一个参数为预测值,第二个为实际运行的结果 ,若相等则测试成功,否则为失败。写好代码后选择生成 stgTest 项目,然后在测试,窗口中打开 测试资源管理器,如果生成没有问题就可以在这里看到测试项了,选择运行即可。 既然学会了如何使用单元测试,那么以后写代码就不要忘了用哦!这样你的代码中的BUG就会越 来越少了! ======== 轻松编写 C++ 单元测试 http://www.ibm.com/developerworks/cn/linux/l-cn-cppunittest/ 介绍全新单元测试框架组合: googletest 与 googlemock googletest 与 googlemock 是 Google 公司于 2008 年发布的两套用于单元测试的应用框架,本 文将向读者介绍如何应用这两套应用框架轻松编写 C++ 单元测试代码。以下讨论基于 gtest- 1.2.1 及 gmock-1.0.0 。 单元测试概述 测试并不只是测试工程师的责任,对于开发工程师,为了保证发布给测试环节的代码具有足够好的 质量( Quality ),为所编写的功能代码编写适量的单元测试是十分必要的。 单元测试( Unit Test ,模块测试)是开发者编写的一小段代码,用于检验被测代码的一个很小的 、很明确的功能是否正确,通过编写单元测试可以在编码阶段发现程序编码错误,甚至是程序设计 错误。 单元测试不但可以增加开发者对于所完成代码的自信,同时,好的单元测试用例往往可以在回归测 试的过程中,很好地保证之前所发生的修改没有破坏已有的程序逻辑。因此,单元测试不但不会成 为开发者的负担,反而可以在保证开发质量的情况下,加速迭代开发的过程。 对于单元测试框架,目前最为大家所熟知的是 JUnit 及其针对各语言的衍生产品, C++ 语言所对 应的 JUnit 系单元测试框架就是 CppUnit 。但是由于 CppUnit 的设计严格继承自 JUnit ,而没 有充分考虑 C++ 与 Java 固有的差异(主要是由于 C++ 没有反射机制,而这是 JUnit 设计的基 础),在 C++ 中使用 CppUnit 进行单元测试显得十分繁琐,这一定程度上制约了 CppUnit 的普 及。笔者在这里要跟大家介绍的是一套由 google 发布的开源单元测试框架( Testing  Framework ): googletest 。 应用 googletest 编写单元测试代码 googletest 是由 Google 公司发布,且遵循 New BSD License (可用作商业用途)的开源项目 ,并且 googletest 可以支持绝大多数大家所熟知的平台。与 CppUnit 不同的是: googletest 可 以自动记录下所有定义好的测试,不需要用户通过列举来指明哪些测试需要运行。 定义单元测试 在应用 googletest 编写单元测试时,使用 TEST() 宏来声明测试函数。如: 清单 1. 用 TEST() 宏声明测试函数 TEST(GlobalConfigurationTest, configurationDataTest)   TEST(GlobalConfigurationTest, noConfigureFileTest) 分别针对同一程序单元 GlobalConfiguration 声明了两个不同的测试(Test)函数,以分别对配 置数据进行检查( configurationDataTest ),以及测试没有配置文件的特殊情况(  noConfigureFileTest )。 实现单元测试 针对同一程序单元设计出不同的测试场景后(即划分出不同的 Test 后),开发者就可以编写单元 测试分别实现这些测试场景了。 在 googletest 中实现单元测试,可通过 ASSERT_* 和 EXPECT_* 断言来对程序运行结果进行检查 。 ASSERT_* 版本的断言失败时会产生致命失败,并结束当前函数; EXPECT_* 版本的断言失败 时产生非致命失败,但不会中止当前函数。因此, ASSERT_* 常常被用于后续测试逻辑强制依赖 的处理结果的断言,如创建对象后检查指针是否为空,若为空,则后续对象方法调用会失败;而  EXPECT_* 则用于即使失败也不会影响后续测试逻辑的处理结果的断言,如某个方法返回结果的多 个属性的检查。 googletest 中定义了如下的断言: 表 1: googletest 定义的断言( Assert ) 基本断言 二进制比较 字符串比较 ASSERT_TRUE(condition); EXPECT_TRUE(condition); condition为真 ASSERT_FALSE(condition); EXPECT_FALSE(condition); condition为假 ASSERT_EQ(expected,actual); EXPECT_EQ(expected,actual); expected==actual ASSERT_NE(val1,val2); EXPECT_NE(val1,val2); val1!=val2 ASSERT_LT(val1,val2); EXPECT_LT(val1,val2); val1<val2 ASSERT_LE(val1,val2); EXPECT_LE(val1,val2); val1<=val2 ASSERT_GT(val1,val2); EXPECT_GT(val1,val2); val1>val2 ASSERT_GE(val1,val2); EXPECT_GE(val1,val2); val1>=val2 ASSERT_STREQ(expected_str,actual_str); EXPECT_STREQ(expected_str,actual_str); 两个 C 字符串有相同的内容 ASSERT_STRNE(str1,str2); EXPECT_STRNE(str1,str2); 两个 C 字符串有不同的内容 ASSERT_STRCASEEQ(expected_str,actual_str); EXPECT_STRCASEEQ(expected_str,actual_str); 两个 C 字符串有相同的内容,忽略大小写 ASSERT_STRCASENE(str1,str2); EXPECT_STRCASENE(str1,str2); 两个 C 字符串有不同的内容,忽略大小写 下面的实例演示了上面部分断言的使用: 清单 2. 一个较完整的 googletest 单元测试实例 // Configure.h   #pragma once   #include <string>   #include <vector>   class Configure   {   private:      std::vector<std::string> vItems;   public:      int addItem(std::string str);      std::string getItem(int index);      int getSize();   };   // Configure.cpp   #include "Configure.h"   #include <algorithm>   /**   * @brief Add an item to configuration store. Duplicate item will be ignored   * @param str item to be stored   * @return the index of added configuration item   */   int Configure::addItem(std::string str)   {  std::vector<std::string>::const_iterator vi=std::find(vItems.begin(), vItems.end(), str);      if (vi != vItems.end())          return vi - vItems.begin();      vItems.push_back(str);      return vItems.size() - 1;   }   /**   * @brief Return the configure item at specified index.   * If the index is out of range, "" will be returned   * @param index the index of item   * @return the item at specified index   */   std::string Configure::getItem(int index)   {      if (index >= vItems.size())          return "";      else          return vItems.at(index);   }   /// Retrieve the information about how many configuration items we have had   int Configure::getSize()   {      return vItems.size();   }   // ConfigureTest.cpp   #include <gtest/gtest.h>   #include "Configure.h"   TEST(ConfigureTest, addItem)   {      // do some initialization      Configure* pc = new Configure();           // validate the pointer is not null      ASSERT_TRUE(pc != NULL);      // call the method we want to test      pc->addItem("A");      pc->addItem("B");      pc->addItem("A");      // validate the result after operation      EXPECT_EQ(pc->getSize(), 2);      EXPECT_STREQ(pc->getItem(0).c_str(), "A");      EXPECT_STREQ(pc->getItem(1).c_str(), "B");      EXPECT_STREQ(pc->getItem(10).c_str(), "");      delete pc;   } 运行单元测试 在实现完单元测试的测试逻辑后,可以通过 RUN_ALL_TESTS() 来运行它们,如果所有测试成功, 该函数返回 0,否则会返回 1 。 RUN_ALL_TESTS() 会运行你链接到的所有测试――它们可以来自不 同的测试案例,甚至是来自不同的文件。 因此,运行 googletest 编写的单元测试的一种比较简单可行的方法是: 为每一个被测试的 class 分别创建一个测试文件,并在该文件中编写针对这一 class 的单元测试; 编写一个 Main.cpp 文件,并在其中包含以下代码,以运行所有单元测试: 清单 3. 初始化 googletest 并运行所有测试 #include <gtest/gtest.h>   int main(int argc, char** argv) {      testing::InitGoogleTest(&argc, argv);      // Runs all tests using Google Test.      return RUN_ALL_TESTS();   } 最后,将所有测试代码及 Main.cpp 编译并链接到目标程序中。 此外,在运行可执行目标程序时,可以使用 --gtest_filter 来指定要执行的测试用例,如: ./foo_test 没有指定filter,运行所有测试; ./foo_test --gtest_filter=* 指定filter为*,运行所有测试; ./foo_test --gtest_filter=FooTest.* 运行测试用例FooTest的所有测试; ./foo_test --gtest_filter=*Null*:*Constructor* 运行所有全名(即测试用例名 + “ . ” + 测试名 ,如 GlobalConfigurationTest.noConfigureFileTest)含有"Null"或"Constructor"的测试; ./foo_test --gtest_filter=FooTest.*-FooTest.Bar 运行测试用例FooTest的所有测试,但不包括 FooTest.Bar。 这一特性在包含大量测试用例的项目中会十分有用。 回页首 应用 googlemock 编写 Mock Objects 很多 C++ 程序员对于 Mock Objects (模拟对象)可能比较陌生,模拟对象主要用于模拟整个应 用程序的一部分。在单元测试用例编写过程中,常常需要编写模拟对象来隔离被测试单元的“下游 ”或“上游”程序逻辑或环境,从而达到对需要测试的部分进行隔离测试的目的。 例如,要对一个使用数据库的对象进行单元测试,安装、配置、启动数据库、运行测试,然后再卸 装数据库的方式,不但很麻烦,过于耗时,而且容易由于环境因素造成测试失败,达不到单元测试 的目的。模仿对象提供了解决这一问题的方法:模仿对象符合实际对象的接口,但只包含用来“欺 骗”测试对象并跟踪其行为的必要代码。因此,其实现往往比实际实现类简单很多。 为了配合单元测试中对 Mocking Framework 的需要, Google 开发并于 2008 年底开放了:  googlemock 。与 googletest 一样, googlemock 也是遵循 New BSD License (可用作商业 用途)的开源项目,并且 googlemock 也可以支持绝大多数大家所熟知的平台。 注 1:在 Windows 平台上编译 googlemock 对于 Linux 平台开发者而言,编译 googlemock 可能不会遇到什么麻烦;但是对于 Windows 平 台的开发者,由于 Visual Studio 还没有提供 tuple ( C++0x TR1 中新增的数据类型)的实现, 编译 googlemock 需要为其指定一个 tuple 类型的实现。著名的开源 C++ 程序库 boost 已经提 供了 tr1 的实现,因此,在 Windows 平台下可以使用 boost 来编译 googlemock 。为此,需要 修改 %GMOCK_DIR%/msvc/gmock_config.vsprops ,设定其中 BoostDir 到 boost 所在的目 录,如: <UserMacro      Name="BoostDir"      Value="$(BOOST_DIR)"   /> 其中 BOOST_DIR 是一个环境变量,其值为 boost 库解压后所在目录。 对于不希望在自己的开发环境上解包 boost 库的开发者,在 googlemock 的网站上还提供了一个 从 boost 库中单独提取出来的 tr1 的实现,可将其下载后将解压目录下的 boost 目录拷贝到  %GMOCK_DIR% 下(这种情况下,请勿修改上面的配置项;建议对 boost 不甚了解的开发者采 用后面这种方式)。 在应用 googlemock 来编写 Mock 类辅助单元测试时,需要: 编写一个 Mock Class (如 class MockTurtle ),派生自待 Mock 的抽象类(如 class Turtle ) ; 对于原抽象类中各待 Mock 的 virtual 方法,计算出其参数个数 n ; 在 Mock Class 类中,使用 MOCK_METHODn() (对于 const 方法则需用  MOCK_CONST_METHODn() )宏来声明相应的 Mock 方法,其中第一个参数为待 Mock 方法 的方法名,第二个参数为待 Mock 方法的类型。如下: 清单 4. 使用 MOCK_METHODn 声明 Mock 方法 #include <gmock/gmock.h>  // Brings in Google Mock.   class MockTurtle : public Turtle {      MOCK_METHOD0(PenUp, void());      MOCK_METHOD0(PenDown, void());      MOCK_METHOD1(Forward, void(int distance));      MOCK_METHOD1(Turn, void(int degrees));      MOCK_METHOD2(GoTo, void(int x, int y));      MOCK_CONST_METHOD0(GetX, int());      MOCK_CONST_METHOD0(GetY, int());   }; 在完成上述工作后,就可以开始编写相应的单元测试用例了。在编写单元测试时,可通过  ON_CALL 宏来指定 Mock 方法被调用时的行为,或 EXPECT_CALL 宏来指定 Mock 方法被调用 的次数、被调用时需执行的操作等,并对执行结果进行检查。如下: 清单 5. 使用 ON_CALL 及 EXPECT_CALL 宏 using testing::Return;                              // #1,必要的声明  TEST(BarTest, DoesThis) {      MockFoo foo;                                    // #2,创建 Mock 对象     ON_CALL(foo, GetSize())                         // #3,设定 Mock 对象默认的行为(可选)         .WillByDefault(Return(1));      // ... other default actions ...      EXPECT_CALL(foo, Describe(5))                   // #4,设定期望对象被访问的方式及其响应         .Times(3)          .WillRepeatedly(Return("Category 5"));      // ... other expectations ...      EXPECT_EQ("good", MyProductionFunction(&foo));       // #5,操作 Mock 对象并使用 googletest 提供的断言验证处理结果  }                                                    // #6,当 Mock 对象被析构时, googlemock 会对结果进行验证以判断其行为是否与所有设定 的预期一致 其中, WillByDefault 用于指定 Mock 方法被调用时的默认行为; Return 用于指定方法被调用 时的返回值; Times 用于指定方法被调用的次数; WillRepeatedly 用于指定方法被调用时重复的 行为。 对于未通过 EXPECT_CALL 声明而被调用的方法,或不满足 EXPECT_CALL 设定条件的 Mock 方 法调用, googlemock 会输出警告信息。对于前一种情况下的警告信息,如果开发者并不关心这 些信息,可以使用 Adapter 类模板 NiceMock 避免收到这一类警告信息。如下: 清单 6. 使用 NiceMock 模板 testing::NiceMock<MockFoo> nice_foo; 在笔者开发的应用中,被测试单元会通过初始化时传入的上层应用的接口指针,产生大量的处理成 功或者失败的消息给上层应用,而开发者在编写单元测试时并不关心这些消息的内容,通过使用  NiceMock 可以避免为不关心的方法编写 Mock 代码(注意:这些方法仍需在 Mock 类中声明, 否则 Mock 类会被当作 abstract class 而无法实例化)。 与 googletest 一样,在编写完单元测试后,也需要编写一个如下的入口函数来执行所有的测试: 清单 7. 初始化 googlemock 并运行所有测试 #include <gtest/gtest.h>   #include <gmock/gmock.h>   int main(int argc, char** argv) {      testing::InitGoogleMock(&argc, argv);      // Runs all tests using Google Test.      return RUN_ALL_TESTS();   } 下面的代码演示了如何使用 googlemock 来创建 Mock Objects 并设定其行为,从而达到对核心 类 AccountService 的 transfer (转账)方法进行单元测试的目的。由于 AccountManager 类 的具体实现涉及数据库等复杂的外部环境,不便直接使用,因此,在编写单元测试时,我们用  MockAccountManager 替换了具体的 AccountManager 实现。 清单 8. 待测试的程序逻辑 // Account.h   // basic application data class   #pragma once   #include <string>   class Account   {   private:      std::string accountId;      long balance;   public:      Account();      Account(const std::string& accountId, long initialBalance);      void debit(long amount);      void credit(long amount);      long getBalance() const;      std::string getAccountId() const;   };   // Account.cpp   #include "Account.h"   Account::Account()   {   }   Account::Account(const std::string& accountId, long initialBalance)   {      this->accountId = accountId;      this->balance = initialBalance;   }   void Account::debit(long amount)   {      this->balance -= amount;   }   void Account::credit(long amount)   {      this->balance += amount;   }   long Account::getBalance() const   {      return this->balance;   }   std::string Account::getAccountId() const   {      return accountId;   }   // AccountManager.h   // the interface of external services which should be mocked   #pragma once   #include <string>   #include "Account.h"   class AccountManager   {   public:      virtual Account findAccountForUser(const std::string& userId) = 0;      virtual void updateAccount(const Account& account) = 0;   };   // AccountService.h   // the class to be tested   #pragma once   #include <string>   #include "Account.h"   #include "AccountManager.h"   class AccountService   {   private:      AccountManager* pAccountManager;   public:      AccountService();      void setAccountManager(AccountManager* pManager);      void transfer(const std::string& senderId,                 const std::string& beneficiaryId, long amount);   };   // AccountService.cpp   #include "AccountService.h"   AccountService::AccountService()   {      this->pAccountManager = NULL;   }   void AccountService::setAccountManager(AccountManager* pManager)   {      this->pAccountManager = pManager;   }   void AccountService::transfer(const std::string& senderId,                    const std::string& beneficiaryId, long amount)   {      Account sender = this->pAccountManager->findAccountForUser(senderId);      Account beneficiary = this->pAccountManager->findAccountForUser(beneficiaryId);      sender.debit(amount);      beneficiary.credit(amount);      this->pAccountManager->updateAccount(sender);      this->pAccountManager->updateAccount(beneficiary);   } 清单 9. 相应的单元测试 // AccountServiceTest.cpp   // code to test AccountService   #include <map>   #include <string>   #include <gtest/gtest.h>   #include <gmock/gmock.h>   #include "../Account.h"   #include "../AccountService.h"   #include "../AccountManager.h"   // MockAccountManager, mock AccountManager with googlemock   class MockAccountManager : public AccountManager   {   public:      MOCK_METHOD1(findAccountForUser, Account(const std::string&));      MOCK_METHOD1(updateAccount, void(const Account&));   };   // A facility class acts as an external DB   class AccountHelper   {   private:      std::map<std::string, Account> mAccount;               // an internal map to store all Accounts for test   public:      AccountHelper(std::map<std::string, Account>& mAccount);      void updateAccount(const Account& account);      Account findAccountForUser(const std::string& userId);   };   AccountHelper::AccountHelper(std::map<std::string, Account>& mAccount)   {      this->mAccount = mAccount;   }   void AccountHelper::updateAccount(const Account& account)   {      this->mAccount[account.getAccountId()] = account;   }   Account AccountHelper::findAccountForUser(const std::string& userId)   {      if (this->mAccount.find(userId) != this->mAccount.end())          return this->mAccount[userId];      else          return Account();   }   // Test case to test AccountService   TEST(AccountServiceTest, transferTest)   {      std::map<std::string, Account> mAccount;      mAccount["A"] = Account("A", 3000);      mAccount["B"] = Account("B", 2000);      AccountHelper helper(mAccount);      MockAccountManager* pManager = new MockAccountManager();      // specify the behavior of MockAccountManager      // always invoke AccountHelper::findAccountForUser       // when AccountManager::findAccountForUser is invoked      EXPECT_CALL(*pManager, findAccountForUser(testing::_)).WillRepeatedly(          testing::Invoke(&helper, &AccountHelper::findAccountForUser));      // always invoke AccountHelper::updateAccount      //when AccountManager::updateAccount is invoked      EXPECT_CALL(*pManager, updateAccount(testing::_)).WillRepeatedly(          testing::Invoke(&helper, &AccountHelper::updateAccount));      AccountService as;      // inject the MockAccountManager object into AccountService      as.setAccountManager(pManager);      // operate AccountService      as.transfer("A", "B", 1005);      // check the balance of Account("A") and Account("B") to      //verify that AccountService has done the right job      EXPECT_EQ(1995, helper.findAccountForUser("A").getBalance());      EXPECT_EQ(3005, helper.findAccountForUser("B").getBalance());      delete pManager;   }   // Main.cpp   #include <gtest/gtest.h>   #include <gmock/gmock.h>   int main(int argc, char** argv) {      testing::InitGoogleMock(&argc, argv);      // Runs all tests using Google Test.      return RUN_ALL_TESTS();   } 注 2:上述范例工程详见附件。要编译该工程,请读者自行添加环境变量 GTEST_DIR 、  GMOCK_DIR ,分别指向 googletest 、 googlemock 解压后所在目录;对于 Windows 开发者 ,还需要将 %GMOCK_DIR%/msvc/gmock_config.vsprops 通过 View->Property Manager 添 加到工程中,并将 gmock.lib 拷贝到工程目录下。 通过上面的实例可以看出, googlemock 为开发者设定 Mock 类行为,跟踪程序运行过程及结果 ,提供了丰富的支持。但与此同时,应用程序也应该尽量降低应用代码间的耦合度,使得单元测试 可以很容易对被测试单元进行隔离(如上例中, AccountService 必须提供了相应的方法以支持  AccountManager 的替换)。关于如何通过应用设计模式来降低应用代码间的耦合度,从而编写 出易于单元测试的代码,请参考本人的另一篇文章《应用设计模式编写易于单元测试的代码》(  developerWorks , 2008 年 7 月)。 注 3:此外,开发者也可以直接通过继承被测试类,修改与外围环境相关的方法的实现,达到对其 核心方法进行单元测试的目的。但由于这种方法直接改变了被测试类的行为,同时,对被测试类自 身的结构有一些要求,因此,适用范围比较小,笔者也并不推荐采用这种原始的 Mock 方式来进 行单元测试。 回页首 总结 Googletest 与 googlemock 的组合,很大程度上简化了开发者进行 C++ 应用程序单元测试的编 码工作,使得单元测试对于 C++ 开发者也可以变得十分轻松;同时, googletest 及  googlemock 目前仍在不断改进中,相信随着其不断发展,这一 C++ 单元测试的全新组合将变 得越来越成熟、越来越强大,也越来越易用。 ========
http://www.itnose.net/detail/6735240.html 2017-03-24 17:56   [C++]

C#进阶系列】30 学习总结

前面学起来还是很顺的,毕竟很多都接触过。 后面学起来只能用“磨”来形容,以至于八章用了2个月。(当然也有相当一些原因是这两个月中发生了一些个人生活上的问题) 总的来说收获超大,这种感觉就像大一的时候学习老谭的C语言一样,醍醐灌顶。 如果是靠.NET吃饭的人,不读这本书真的是太可惜了。 不过这中间也
http://www.itnose.net/detail/6513795.html 2016-06-01 03:35   [C#语言]

学习 C++的用途,(前辈总结)

C++准确说是一门中级语言,介于汇编和高级语言之间吧,要求程序员了解计算机的内部数据存储。个人认为,作为学生还是花功夫学C++,因为《设计模式》《数据结构》这些课程基本上还是C++应付的比较好(我的切身体会),学习 C++,认真阅读c++ primer,而后配合 The ADAPTIVE
http://www.itnose.net/detail/6476263.html 2016-03-26 10:53   [C++]

CC++的学习过程总结

总是被同学们问到,如何学习CC++才不茫然,才不是乱学,想了一下,这里给出一个总的回复。  一家之言,欢迎拍砖哈。  1、可以考虑先学习C.  大多数时候,我们学习语言的目的,不是为了成为一个语言专家,而是希望成为一个解决问题的专家。做一个有用的程序员,做一个赚钱的程序员。我们的价值,将体现在
http://www.itnose.net/detail/6423256.html 2015-12-30 14:53   [C语言]

JAVA并发编程J.U.C学习总结

前言   学习了一段时间J.U.C,打算做个小结,个人感觉总结还是非常重要,要不然总感觉知识点零零散散的。 有错误也欢迎指正,大家共同进步; 本文目录如下,基本上涵盖了J.U.C的主要内容; JSR 166及J.U.C Executor框架(线程池、 Callable 、Future
http://www.itnose.net/detail/6529095.html 2016-07-07 01:02   [J2SE]

C语言 时间函数的学习总结

一直都是以简单的time_t t,time(&t),ctime(&t)来表示时间,后来要以时间为日志文件的名字时,就有点蒙逼了。学习一下。   tm结构: struct tm {       
http://www.itnose.net/detail/6515296.html 2016-06-04 01:38   [C语言]

学习ios之路:objective-c实例变量总结

201-5-730x456.jpg 前言 <Programming in Objective-c2.0>这本书已经看完了,但是现在有个感觉是:看了后面的知识,前面看过的知识就忘记了,并且自己对整个oc的知识体系没有一个系统的认识。因此计划在重新复习下。 因为java和oc都是
http://www.itnose.net/detail/6498978.html 2016-05-06 13:07   [iphone]

c语言初学者一周学习总结

 今天是2016年3月19日,我是3月14日接触c语言的掐指一算到今天已经有一周了;首先我先对我这一周学习什么做个总结: 一,熟悉了Mac操作(ps:就是苹果电脑系统);                
http://www.itnose.net/detail/6472478.html 2016-03-20 17:22   [C语言]

C++ Primer 学习笔记_57_总结

终于在过年放假的时间把笔记整理完,在看书和看一些学习视频的过程中,学到了很多知识。对于基础知识的学习,书本是最好的指导老师,有时候网上的资料比较杂乱。对于源码的知识,通过IDE去跟踪源代码,是最好的学习过程,可以遍历整个过程,主要是理解核心的算法,一般核心算法和常规的算法其实是类似的,只是被移植
http://www.itnose.net/detail/6454990.html 2016-02-19 13:49   [C++]

C语言学习总结(二) 运算流程

操作数 如 : i++       !       sizeof 双目运算:有两个操作数 如 : a+b 三目预算:C语言中唯一的一个,也称为问号表达式 a>b ? 1 : 0  运算遵循规则:数学的运算规则,先看
http://www.itnose.net/detail/6413149.html 2015-12-03 00:52   [C语言]

编程基础?学习C语言基础的总结

第一章 编程的基本概念   程序:为了让计算机执行某些操作或解决某个问题编写的一系列有序指令的集合。 C语言源程序的结构特点: 1. 可以由一个或多个源文件组成。 2. 每个源文件可由一个或多个函数组成。 3. 一个源程序不论由多少个文件组成,有且
http://www.itnose.net/detail/478178.html 2014-01-22 18:47   [基础]

  1  2  3  4  5 下一页>