如何使用CppUnit進行單元測試

http://www.vckbase.com/document/viewdoc/?id=1762

一、前言

  測試驅動開發(TDD)是以測試作為開發過程的中心,它堅持,在編寫實際代碼之前,先寫好基于產品代碼的測試代碼。開發過程的目標就是首先使測試能夠通過,然后再優化設計結構。測試驅動開發式是極限編程的重要組成部分。XUnit,一個基于測試驅動開發的測試框架,它為我們在開發過程中使用測試驅動開發提供了一個方便的工具,使我們得以快速的進行單元測試。XUnit的成員有很多,如JUnit,PythonUnit等。今天給大家介紹的CppUnit即是XUnit家族中的一員,它是一個專門面向C++的測試框架。

本文不對CppUnit源碼做詳細的介紹,而只是對CppUnit的應用作一些介紹。你將看到:

  1. CppUnit源代碼的各個組成部分;
  2. 怎樣設置你的開發環境以能夠使用CppUnit;
  3. 怎樣為你的產品代碼添加測試代碼(實際上應該反過來,為測試代碼添加產品代碼。在TDD中,先有測試代碼后有產品代碼),并通過CppUnit來進行測試;

本文敘述背景為:CppUnit1.12.0, Visual C++ 6.0, WindowsXP。文中敘述有誤之處,敬請批評指正。

一. CppUnit的安裝
從http://sourceforge.net/projects/cppunit CppUnit的源碼包. CppUnit是開源產品 , 當前最高版本為1.12.0. (在上面的鏈接所指向的頁面上選擇 Development Snapshot ).?
下載后,將源碼包解壓縮到本地硬盤,例如解壓到E:/ cppunit-1.12.0。筆者把文件夾名稱中的版本號去掉,即源碼包解壓縮到E:/cppunit。下載解壓后,你將看到如下文件夾:

?picture1

主要的文件夾有:

  • doc: CppUnit的說明文檔。另外,代碼的根目錄,還有三個說明文檔,分別是INSTALL,INSTALL-unix,INSTALL-WIN32.txt;
  • examples: CpppUnit提供的例子,也是對CppUnit自身的測試,通過它可以學習如何使用CppUnit測試框架進行開發;
  • include: CppUnit頭文件;
  • src: CppUnit源代碼目錄;
  • config:配置文件;
  • contrib:contribution,其他人貢獻的外圍代碼;
  • lib:存放編譯好的庫;
  • src:源文件,以及編譯庫的project等;

  接下來進行編譯工作。 在src/目錄下, 將CppUnitLibraries.dsw工程文件用vc 打開。執行build/batch build,編譯成功的話,生成的庫文件將被拷貝到lib目錄下。中途或者會有些project編譯失敗,一般不用管它,我們重點看的是cppunit和TestRunner 這兩個project的debug和release版本。
  編譯通過以后, 在lib/目錄下,會生成若干lib,和dll文件, 都以cppunit開頭. cppunitd表示debug版, cppunit表示release版。
CppUnit為我們提供了兩套框架庫,一個為靜態的lib,一個為動態的dll。cppunit project:靜態lib;cppunit_dll project:動態dll和lib。在開發中我們可以根據實際情況作出選擇。
你也可以根據需要選擇所需的項目進行編譯,其中項目cppunit為靜態庫,cppunit_dll為動態庫,生成的庫文件為:

  • cppunit.lib:靜態庫release版;
  • cppunitd.lib:靜態庫debug版;
  • cppunit_dll.lib:動態庫release版;
  • cppunitd_dll.lib:動態庫debug版;

  另外一個需要關注的project是TestRunner,它輸出一個dll,提供了一個基于GUI 方式的測試環境,在CppUnit下, 可以選擇控制臺方式和GUI方式兩種表現方案。兩種方案分別如下圖所示:

picture2

?picture3

我們選擇GUI方式,所以我們也需要編譯這個project,輸出位置亦為lib文件夾。
要使用CppUnit,還得設置好頭文件和庫文件路徑,以VC6為例,選擇Tools/Options/Directories,在Include files和Library files中分別添加%CppUnitPath%/include和%CppUnitPath%/lib,其中%CppUnitPath%表示CppUnit所在路徑。本文這里分別填的是E:/CPPUNIT/INCLUDE和E:/CPPUNIT/LIB。

picture4

二、概念

在使用之前,我們有必要認識一下CppUnit中的主要類,當然你也可以先看后面的例子,遇到問題再回過頭來看這一節。
CppUnit核心內容主要包括一些關鍵類:

Test:所有測試對象的基類。

CppUnit采用樹形結構來組織管理測試對象(類似于目錄樹,如下圖所示),因此這里采用了組合設計模式(Composite Pattern),Test的兩個直接子類TestLeaf和TestComposite分別表示“測試樹”中的葉節點和非葉節點,其中TestComposite主要起組織管理的作用,就像目錄樹中的文件夾,而TestLeaf才是最終具有執行能力的測試對象,就像目錄樹中的文件。

picture3

Test最重要的一個公共接口為:

virtual void run(TestResult *result) = 0;

其作用為執行測試對象,將結果提交給result。
在實際應用中,我們一般不會直接使用Test、TestComposite以及TestLeaf,除非我們要重新定制某些機制。

TestFixture:用于維護一組測試用例的上下文環境。

  在實際應用中,我們經常會開發一組測試用例來對某個類的接口加以測試,而這些測試用例很可能具有相同的初始化和清理代碼。為此,CppUnit引入TestFixture來實現這一機制。
TestFixture具有以下兩個接口,分別用于處理測試環境的初始化與清理工作:

virtual void setUp(); 
virtual void tearDown(); TestCase:測試用例,從名字上就可以看出來,它便是單元測試的執行對象。

  TestCase從Test和TestFixture多繼承而來,通過把Test::run制定成模板函數(Template Method)而將兩個父類的操作融合在一起,run函數的偽定義如下:

// 偽代碼 
void TestCase::run(TestResult* result)
{result->startTest(this); // 通知result測試開始if( result->protect(this, &TestCase::setUp) ) // 調用setUp,初始化環境result->protect(this, &TestCase::runTest); // 執行runTest,即真正的測試代碼result->protect(this, &TestCase::tearDown); // 調用tearDown,清理環境result->endTest(this); // 通知result測試結束
} 

這里要提到的是函數runTest,它是TestCase定義的一個接口,原型如下:

virtual void runTest(); 

用戶需從TestCase派生出子類并實現runTest以開發自己所需的測試用例。
另外還要提到的就是TestResult的protect方法,其作用是對執行函數(實際上是函數對象)的錯誤信息(包括斷言和異常等)進行捕獲,從而實現對測試結果的統計。

TestSuit:測試包,按照樹形結構管理測試用例

TestSuit是TestComposite的一個實現,它采用vector來管理子測試對象(Test),從而形成遞歸的樹形結構。

TestFactory:測試工廠

這是一個輔助類,通過借助一系列宏定義讓測試用例的組織管理變得自動化。參見后面的例子。

TestRunner:用于執行測試用例

TestRunner將待執行的測試對象管理起來,然后供用戶調用。其接口為:

virtual void addTest( Test *test ); 
virtual void run( TestResult &controller, const std::string &testPath = "" ); 

  這也是一個輔助類,需注意的是,通過addTest添加到TestRunner中的測試對象必須是通過new動態創建的,用戶不能刪除這個對象,因為TestRunner將自行管理測試對象的生命期。

三、CppUnit 的使用

  以上工作完成以后,就可以正式使用CppUnit了,由于單元測試是TDD(測試驅動開發)的利器,一般人會先寫測試代碼,然后再寫產品代碼,不過筆者認為先寫產品代碼框架后再寫測試代碼,然后通過慢慢補充產品代碼以使得能通過測試的方法會好些。不管先寫誰只要寫得舒服安全就可以。本文決定先寫測試代碼。
  前面我們提到過,CppUnit最小的測試單位是TestCase,多個相關TestCase組成一個TestSuite。要添加測試代碼最簡單的方法就是利用CppUnit為我們提供的幾個宏來進行(當然還有其他的手工加入方法,但均是殊途同歸,大家可以查閱CppUnit頭文件中的演示代碼)。這幾個宏是:

CPPUNIT_TEST_SUITE() 開始創建一個TestSuite;
CPPUNIT_TEST() 添加TestCase;
CPPUNIT_TEST_SUITE_END() 結束創建TestSuite;
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION() 添加一個TestSuite到一個指定的TestFactoryRegistry工廠。

感興趣的朋友可以在HelperMacros.h看看這幾個宏的聲明,本文在此不做詳述。

假定我們要實現一個類,類名暫且取做CPlus,它的功能主要是實現兩個數相加(多簡單的一個類啊,這也要測試嗎?不要緊,我們只是了解怎樣加入測試代碼來測試它就行了,所以越簡單越好)。 假定這個類要實現的相加的方法是:

int Add(int nNum1, int nNum2);

  OK,那我們先來寫測試這個方法的代碼吧。TDD 可是先寫測試代碼,后寫產品代碼(CPlus)的哦!先寫的測試代碼往往是不能運行或編譯的,我們的目標是在寫好測試代碼后寫產品代碼,使之編譯通過,然后再進行重構。這就是Kent Beck說的“red/green/refactor”。所以,上面的類名和方法應該還只是在你的心里,還只是你的idea而已。
  根據測試驅動的原理,我們需要先建立一個單元測試框架。我們在VC中為測試代碼建立一個project。通常,測試代碼和被測試對象(產品代碼)是處于不同的project中的。這樣就不會讓你的產品代碼被測試代碼所“污染 ”。
由于在CppUnit下, 可以選擇控制臺方式和UI方式兩種表現方案,我們選擇UI方式。在本例中,我們將建立一個基于GUI 方式的測試環境。因此我們建立一個基于對話框的Project。假設名為UnitTest。
建立了UnitTest project之后,我們首先配置這個工程。
首先在project中打開RTTI開關,具體位置在菜單Project/Settings/C++/C++ Language。如下圖所示設置:

picture6

  由于CppUnit所用的動態運行期庫均為多線程動態庫,因此你的單元測試程序也得使用相應設置,否則會發生沖突。于是我們在Project/Settings/C++/Code Generation中進行如下設置:
  在Use run-time library一欄中,針對debug和release分別設置為‘Debug Multithreaded DLL’和‘Multithreaded DLL’。如下圖所示:

picture7

picture8

  最后別忘了在project中link正確的lib。包括本例采用的cppunit.lib和cppunitd.lib靜態庫以及用于GUI方式的TestRunner.dll對應的lib。具體位置在Project/Settings/Link/General
  在‘Object/library modules’中,針對debug和release分別加入cppunitd.lib testrunnerd.lib和cppunit.lib TestRunner.lib。如下圖所示:

picture9

picture10

  最后,由于TestRunner.dll為我們提供了基于GUI的測試環境。為了讓我們的測試程序能正確的調用它,TestRunner.dll必須位于你的測試程序的路徑下。所以把/lib目錄下的testrunnerd.dll和TestRunner.dll文件分別拷貝到UnitTest priject的程序debug和release版本輸出目錄中。如下圖所示:

picture11

(這是release版本)只要放在一起就可以了。
配置工作終于完成,下面開始寫測試框架。

在CppUnit中, 是以TestCase為最小的測試單位, 若干TestCase組成一個TestSuite。所以我們要先建立一個TestCase。
在UnitTest project中新建一個類, 命名為CPlusTestCase, 讓其從CppUnit::TestCase派生。為其新增一個方法,假設為 void testAdd(); 我們將在這個函數中寫入我們的一些測試代碼(還記得我們要測試的構想中的CPlus::Add(…)嗎)。代碼如下:切記要包含頭文件

#include <cppunit/TestCase.h>
class CPlusTestCase : public CppUnit::TestCase
{
public:CPlusTestCase ();virtual ~ CPlusTestCase ();void testAdd();
};

接下來, 我們要對我們的CPlusTestCase進行聲明。聲明用到了三個宏.

    CPPUNIT_TEST_SUITE();CPPUNIT_TEST();CPPUNIT_TEST_SUITE_END();

第一個宏聲明一個測試包(suite),第二個宏聲明(添加)一個測試用例. 現在我們的CPlusTestCase類看上去象這樣:切記要包含頭文件,否則無法識別這些宏。

#include <cppunit/TestCase.h>
#include <CppUnit/extensions/HelperMacros.h>class CPlusTestCase : public CppUnit::TestCase
{CPPUNIT_TEST_SUITE(CPlusTestCase);CPPUNIT_TEST(testAdd);CPPUNIT_TEST_SUITE_END();
public:CPlusTestCase ();virtual ~ CPlusTestCase ();void testAdd();
};

通過這幾個宏,我們就把CPlusTestCase和testAdd注冊到了測試列表當中。

  接下來,我們要注冊我們的測試suite. 使用CPPUNIT_TEST_SUITE_NAMED_REGISTRATION()來注冊一個測試suite. 這個宏的第二個參數是我們注冊的suite的名字. 在這里我們可以用字符串來代替, 但我們用一個靜態函數來返回這個suite的名字.

// PlusTestCase.h 
class CPlusTestCase : public CppUnit::TestCase
{CPPUNIT_TEST_SUITE(CPlusTestCase);CPPUNIT_TEST(testAdd);CPPUNIT_TEST_SUITE_END();
public:CPlusTestCase ();virtual ~ CPlusTestCase ();void testAdd();static std::string GetSuiteName();
};// PlusTestCase.cppstd::string CPlusTestCase::GetSuiteName(){return " CPlus ";}

記得要在PlusTestCase.h中包含 #include <string>?
然后在 PlusTestCase.cpp注冊我們的suite.

CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CPlusTestCase, CPlusTestCase::GetSuiteName());

它將CPlusTestCase這個TestSuite注冊到一個指定的TestFactory工廠中。
接下來我們寫一個注冊函數static CppUnit::Test* GetSuite(), 使其在運行期生成一個Test.

		
// PlusTestCase.h 
class CPlusTestCase : public CppUnit::TestCase
{CPPUNIT_TEST_SUITE(CPlusTestCase);CPPUNIT_TEST(testAdd);CPPUNIT_TEST_SUITE_END();
public:CPlusTestCase ();virtual ~ CPlusTestCase ();void testAdd();static std::string GetSuiteName();static CppUnit::Test* GetSuite();
};// PlusTestCase.cppCppUnit::Test* CPlusTestCase::GetSuite(){CppUnit::TestFactoryRegistry& reg = CppUnit::TestFactoryRegistry::getRegistry (CPlusTestCase::GetSuiteName());return reg.makeTest();}

記住在PlusTestCase.h中包含頭文件:

#include <cppunit/extensions/TestFactoryRegistry.h>

最后, 我們為單元測試建立一個UI測試界面.

  由于我們希望這個Project運行后顯示的是GUI界面,所以我們需要在App的 InitInstance ()中屏蔽掉原有的對話框,代之以CppUnit的GUI。
我們在CUnitTestApp::InitInstance()函數中,將原先顯示主對話框的代碼以下面的代碼取代:

		
CppUnit::MfcUi::TestRunner runner;runner.addTest(CPlusTestCase::GetSuite());//添加測試runner.run();//show UI
/*	CUnitTestDlg dlg;m_pMainWnd = &dlg;int nResponse = dlg.DoModal();if (nResponse == IDOK){// TODO: Place code here to handle when the dialog is//  dismissed with OK}else if (nResponse == IDCANCEL){// TODO: Place code here to handle when the dialog is//  dismissed with Cancel}
*/

切記必須先在UnitTest.cpp中包含頭文件:

#include <cppunit/ui/mfc/TestRunner.h>
#include " PlusTestCase.h "

到此為止, 我們已經建立好一個簡單的單元測試框架。測試框架雖然寫好了,但是測試代碼仍然為空,產品代碼也還沒有寫。下面我們來寫測試代碼:?
如前所述,在測試類中,我們添加了一個測試方法:

void testAdd();

它測試的對象是前面提到的CPlus類的方法:int Add(int nNum1, int nNum2);(產品代碼)我們來看看testAdd()的實現:記得在PlusTestCase.h中包含頭文件

#include <cppunit/TestAssert.h>
// PlusTestCase.cpp
void CPlusTestCase::testAdd()
{CPlus plus;int nResult = plus.Add(10, 20); //執行Add操作CPPUNIT_ASSERT_EQUAL(30, nResult); //檢查結果是否等于30	
}

CPPUNIT_ASSERT_EQUAL是一個判斷結果的宏。CppUnit中類似的其它宏請查閱TestAssert.h,本文在此不做詳述 。

  另外,我們還可以覆寫基類的 setUp()、tearDown()兩個函數。這兩個函數實際上是一個模板方法,在測試運行之前會調用setUp()以進行一些初始化的工作,測試結束之后又會調用tearDown()來做一些“善后工作” ,比如資源的回收等等。當然,你也可以不覆寫這兩個函數,因為它們在基類里定義成了空方法,而不是純虛函數。?
  編寫完上面的測試代碼后,進行編譯。編譯肯定通不過,編譯器會告訴我們CPlus類沒有聲明,因為我們還沒有實現CPlus類呢!現在的工作就是馬上實現CPlus類,讓編譯通過。現在你應該嗅到一點“測試驅動”(Test Driven Develop)的味道了吧?

在VC中建立一個MFC Extension Dll的Project,在這個Project 中加入類CPlus,它的聲明如下:

		
// Plus.h
class AFX_EXT_CLASS CPlus
{
public:CPlus();virtual ~CPlus();
public:int Add(int nNum1, int nNum2);
};

Add在Plus.cpp中實現如下

		
int CPlus::Add(int nNum1, int nNum2)
{return nNum1 + nNum2;//這里可以寫一些錯誤的語句,用來看看錯誤的結果
}

非常簡單,不是嗎?現在讓前面那個包含測試代碼的Project dependent這個Project,并且include 相關頭文件 ,Rebuild All,你會發現編譯已通過。你體會到了測試代碼驅動產品代碼了嗎?當然我們的這個例子還很簡單 ,沒有重構這一步驟。

運行我們的測試程序,單擊Browse,你就會看到如下圖所示的界面:

picture12


選擇CPlusTestCase::testAdd后,單擊Run,你就會看到如下圖所示的界面:

picture13

  這下你應該對前面我們說的TestSuite的名字理解更深了吧。CPlus是一個測試包TestSuite,它的下面包含一個測試用例,這個測試用例下面又包含一個測試方法。

如果我修改CPlus::Add的代碼如下:

int CPlus::Add(int nNum1, int nNum2)
{
//	return nNum1 + nNum2;return 2;	
}

重新編譯通過,運行程序就會發現:

picture14

GUI顯示有一個單元測試不通過,并顯示出錯的地方和原因,這樣就很好的控制Bug了。


四、下面是完整的程序清單

// PlusTestCase.h
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <string>
#include <cppunit/TestCase.h>
#include <CppUnit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/TestAssert.h>
class CPlusTestCase : public CppUnit::TestCase  
{//通過這幾個宏,我們就把CPlusTestCase和testAdd注冊到了測試列表當中.CPPUNIT_TEST_SUITE(CPlusTestCase);		//聲明一個測試包CPPUNIT_TEST(testAdd);			//聲明一個測試用例CPPUNIT_TEST_SUITE_END();	
public:CPlusTestCase();virtual ~CPlusTestCase();void testAdd(); //測試方法static std::string GetSuiteName();//寫一個注冊函數, 使其在運行期生成一個Teststatic CppUnit::Test* GetSuite();
};
// PlusTestCase.cpp
#include "stdafx.h"
#include "UnitTest.h"
#include "PlusTestCase.h"
#include "plus.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//注冊一個測試suite到一個指定的TestFactory工廠中
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CPlusTestCase, CPlusTestCase::GetSuiteName());
//
// Construction/Destruction
//
CPlusTestCase::CPlusTestCase()
{
}
CPlusTestCase::~CPlusTestCase()
{
}
void CPlusTestCase::testAdd()
{CPlus plus;int nResult = plus.Add(10, 20); //執行Add操作CPPUNIT_ASSERT_EQUAL(30, nResult); //檢查結果是否等于30	
}
std::string CPlusTestCase::GetSuiteName()
{return "CPlus";
}
/**	注意:CPlusTestCase::GetSuite()返回一個指向CppUnit::Test的指針.*  這個指針就是整個測試的起點。*  CppUnit::TestFactoryRegistry::getRegistry()根據TestSuite的名字返回TestFactoryRegistry工*  然后調用工廠里的makeTest()對TestSuite進行組裝,將建立起一個樹狀的測試結構。*/
CppUnit::Test* CPlusTestCase::GetSuite()
{CppUnit::TestFactoryRegistry& reg = CppUnit::TestFactoryRegistry::getRegistry(CPlusTestCase::GetSuiteName());return reg.makeTest();
}
// UnitTest.cpp
#include "stdafx.h"
#include "UnitTest.h"
#include <cppunit/ui/mfc/TestRunner.h>
#include "PlusTestCase.h"
…
/
// CUnitTestApp initialization
BOOL CUnitTestApp::InitInstance()
{…CppUnit::MfcUi::TestRunner runner;runner.addTest(CPlusTestCase::GetSuite()); //添加測試	runner.addTest(CMinusTestCase::GetSuite());runner.run(); //show UI
/*	CUnitTestDlg dlg;m_pMainWnd = &dlg;int nResponse = dlg.DoModal();if (nResponse == IDOK){// TODO: Place code here to handle when the dialog is//  dismissed with OK}else if (nResponse == IDCANCEL){// TODO: Place code here to handle when the dialog is//  dismissed with Cancel}
*/return FALSE;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/458698.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/458698.shtml
英文地址,請注明出處:http://en.pswp.cn/news/458698.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

錄制wav格式的音頻

項目中有面部認證、聲紋認證&#xff0c;服務器端要求上傳wav格式的音頻&#xff0c;所以寫了這樣一個小demo。 剛剛開始寫博客還不知道怎么上傳代碼&#xff0c;就復制了&#xff0c;嘻嘻 DotimeManage.h class DotimeManage; protocol DotimeManageDelegate <NSObject&g…

iOS開發網絡篇—Reachability檢測網絡狀態

前言&#xff1a;當應用程序需要訪問網絡的時候&#xff0c;它首先應該檢查設備的網絡狀態&#xff0c;確認設備的網絡環境及連接情況&#xff0c;并針對這些情況提醒用戶做出相應的處理。最好能監聽設備的網絡狀態的改變&#xff0c;當設備網絡狀態連接、斷開時&#xff0c;程…

網絡七層協議 五層模型 TCP連接 HTTP連接 socket套接字

socket&#xff08;套接字&#xff09;是通信的基石&#xff0c;是支持TCP/IP協議的網絡通信的基本操作單元&#xff0c;包含進行網絡通信必須的五種信息&#xff1a;連接使用的協議&#xff0c;本地主機的IP地址&#xff0c;本地進程的協議端口&#xff0c;遠地主機的IP地址&a…

[vs2010 project] CppUnit快速入門

簡介 測試是軟件開發過程中極其重要的一環&#xff0c;詳盡周密的測試能夠減少軟件BUG&#xff0c;提高軟件品質。測試包括單元測試、系統測試等。其中單元測試是指針對軟件功能單元所作的測試&#xff0c;這里的功能單元可以是一個類的屬性或者方法&#xff0c;測試的目的是看…

[javascript|基本概念|Number]學習筆記

Number類型的值&#xff1a;整數/浮點數值 整數 十進制 e.g.: var intNum 50; 八進制 (嚴格模式下無效,解析錯誤)字面值首位必須是0,之后的數字序列為0&#xff5e;7 e.g.: var intNum 070; //解析為十進制56 (如果字面值數值超出了范圍&#xff0c;前導0將被忽略&#xf…

[轉]深入理解linux內核list_head

http://blog.chinaunix.net/uid-27122224-id-3277511.html 深入理解linux內核list_head的實現 2012-07-17 17:37:01 分類&#xff1a; LINUX 前言&#xff1a;在linux源代碼中有個頭文件為list.h。很多linux下的源代碼都會使用這個頭文件&#xff0c;它里面定義 了一個結構,以及…

xcode左側不顯示工程文件目錄,提示NO Filter Results

解決辦法&#xff1a; What solved was to go to Navigate > Reveal in Project Navigator . After this, the structure appeared again.

【VC++技術雜談005】如何與程控儀器通過GPIB接口進行通信

在工控測試系統中&#xff0c;經常需要使用到各類程控儀器&#xff0c;這些程控儀器通常具有GPIB、LAN、USB等硬件接口&#xff0c;計算機通過這些接口能夠與其通信&#xff0c;從而實現自動測量、數據采集、數據分析和數據處理等操作。本文主要介紹如何與程控儀器通過GPIB接口…

標題在上邊框中的html(fieldset標簽)

<fieldset> <legend>標題</legend> 內容 </fieldset> 轉載于:https://www.cnblogs.com/lswbk/p/4952820.html

移除項目中的CocoaPods

在項目中移除CocoaPods cocoaPods雖然很方便&#xff0c;但是我是真心的不喜歡用它&#xff0c;總是出錯如果你覺得CocoaPods讓你的項目出現了問題&#xff0c;不好用甚至是惡心&#xff0c;想將其從項目中徹底移除&#xff0c;也有方法&#xff1a; 1.刪除工程文件夾下的Podf…

ShellExecute使用詳解

有三個API函數可以運行可執行文件WinExec、ShellExecute和CreateProcess。 1.CreateProcess因為使用復雜&#xff0c;比較少用。 2.WinExec主要運行EXE文件。如&#xff1a;WinExec(Notepad.exe Readme.txt, SW_SHOW); 3.ShellExecute不僅可以運行EXE文件&#xff0c;也可以運行…

javascript筆記整理(對象基礎)

一、名詞解釋 1.基于對象&#xff08;一切皆對象&#xff0c;以對象的概念來編程&#xff09; 2.面向對象編程(Object Oriented Programming&#xff0c;OOP) A.對象(JavaScript 中的所有事物都是對象) B.對象的屬性和行為 屬性:用數據值來描述他的狀態 行為:用來改變對象行為的…

java的安裝和配置

JRE (JAVA Runtime Enviroment java運行環境),包括JVM(java虛擬機)和java程序所需的核心功能類庫&#xff0c;如果只是運行java程序&#xff0c;只需安裝JRE。 JDK &#xff08;Java Development Kit 開發工具包&#xff09;包括開發JAVA程序時所需的工具&#xff0c;包括JRE…

#if, #ifdef, #ifndef, #else, #elif, #endif的用法

#ifdef的用法 靈活使用#ifdef指示符&#xff0c;我們可以區隔一些與特定頭文件、程序庫和其他文件版本有關的代碼。 代碼舉例&#xff1a;新建define.cpp文件 &#xff03;include "iostream.h" int main() { #ifdef DEBUG cout<< "Beginning ex…

redhat 6.6 安裝 (LVM)

http://www.cnblogs.com/kerrycode/p/4341960.html轉載于:https://www.cnblogs.com/zengkefu/p/4954955.html

MFC對話框最小化到托盤

1、在資源中的Icon中導入一個自己喜歡的圖標&#xff0c;ID命名為IDR_MAINFRAME&#xff0c;將先前的IDR_MAINFRAME的圖標刪除掉&#xff1b; 2、在自己的Dialog頭文件中定義一個變量 NOTIFYICONDATA m_nid&#xff0c;關于該結構體的具體信息可以查閱MSDN&#xff1b; 3、添加…

Android acache讀后感

今天了解到了一個android輕量級的開源緩存框架,(github&#xff1a;https://github.com/yangfuhai/ASimpleCache),花了一點時間研究了一下源代碼&#xff0c;大概的思路就是每個緩存目錄對應一個Acache類&#xff0c;通過mInstanceMap關聯&#xff08;個人覺得這個主要是減少對…

continue break

塊作用域 一個塊或復合語句是用一對花括號&#xff08;"{}"&#xff09;括起來的任意數量的簡單的java語句。塊定義了變量的作用范圍。 1、嵌套塊是方法內的嵌套&#xff0c;不包括類的花括號。在嵌套塊內的 變量是不可以重復定義的。 2、不允許重復定義的是局部變…

GetVersionEx 獲取系統版本信息

轉自&#xff1a;http://blog.csdn.net/yyingwei/article/details/8286658 最近在windows 8上獲取系統版本信息需要調用系統API&#xff0c;于是用到了GetVersionEx。 首先看一看函數原型&#xff1a; [cpp] view plaincopy BOOL GetVersionEx(POSVERSIONINFO pVersionInformat…

popoverController(iPad)

一、設置尺寸 提示&#xff1a;不建議&#xff0c;像下面這樣吧popover的寬度和高度寫死。 1 //1.新建一個內容控制器2 YYMenuViewController *menuVc[[YYMenuViewController alloc]init];3 4 //2.新建一個popoverController&#xff0c;并設置其內容控制器5 s…