libsvm是國立臺灣大學Chih-Jen Lin開發的一個SVM的函數庫,是當前應用最普遍的svm函數庫,從2000年到2010年,該函數庫的下載量達到250000之多。它的最新版本是version 3.17,主要是對是svm_group_classes作了修改。html
主頁:LIBSVM -- A Library for Support Vector Machines node
我下載後的解壓文件以下所示:web
libsvm函數包的組織結構以下:面試
一、主文件路徑:包含了核心的C/C++程序和例子數據。其中svm.cpp是svm的核心程序,它實現了svm的訓練和測試算法。算法
二、tool子文件路徑:包含了一些檢驗數據格式以及選擇svm參數的tool。編程
三、其餘子文件路徑:主要包含pre-built 二值文件和相關語言的接口。數組
關於libsvm的官方實現文檔:LIBSVM: A Library for Support Vector Machines,本相關博文也是以這篇文檔爲基礎的,同時本相關博文還參考了上海交大模式分析與機器智能實驗室的libsvm2.6代碼註釋。app
關於svm的理論知識,本文不想多說,若是你還不是很懂,能夠參考我前面的兩篇文章:函數
=======================================================
如今開始看一看libsvm的頭文件svm.h
svm.h中主要是定義了4個結構體,分別是svm_node、svm_problem、svm_parameter、svm_model,而後就是19個函數的聲明,函數的聲明我就不先講了,等到在svm.cpp中碰到後再細說。下面來看一看這幾個結構體:
這個結構體用於存儲單一貫量中的單個特徵。例如:向量x1={0.002,0.345,4.000,5.677},則用svm_node來存儲就是使用一個包含5個svm_node的數組來存儲這個4維向量,內存中的表示以下:
這個結構體用於存儲本次參加運算的全部樣本及其所屬類別,一個示意圖以下(其中最右邊的4個長方格如同上圖中的表格):
這個結構體用於存儲svm的各個參數,知道就行。
這個函數體用於保存訓練後的訓練模型model,在predict中要用到。
=======================================
關於extern 「C」的解析
在閱讀svm.h時發現了以下一段代碼:
顯然,前3行代碼是爲了防止頭文件被重複引用,那麼5-6行是什麼意思呢?
某企業曾經給出以下的一道面試題:爲何標準頭文件都有相似如下的結構?
分析
顯然,頭文件中的編譯宏「#ifndef __INCvxWorksh、#define __INCvxWorksh、#endif」 的做用是防止該頭文件被重複引用。
那麼
的做用又是什麼呢?
extern "C" 包含雙重含義,從字面上便可獲得:首先,被它修飾的目標是「extern」的;其次,被它修飾的目標是「C」的。讓咱們來詳細解讀這兩重含義。
被extern "C"限定的函數或變量是extern類型的;extern是C/C++語言中代表函數和全局變量做用範圍(可見性)的關鍵字,該關鍵字告訴編譯器,其聲明的函數和變量能夠在本模塊或其它模塊中使用。記住,下列語句:extern int a;僅僅是一個變量的聲明,其並非在定義變量a,並未爲a分配內存空間。變量a在全部模塊中做爲一種全局變量只能被定義一次,不然會出現鏈接錯誤。一般,在模塊的頭文件中對本模塊提供給其它模塊引用的函數和全局變量以關鍵字extern聲明。例如,若是模塊B欲引用該模塊A中定義的全局變量和函數時只需包含模塊A的頭文件便可。這樣,模塊B中調用模塊A中的函數時,在編譯階段,模塊B雖然找不到該函數,可是並不會報錯;它會在鏈接階段中從模塊A編譯生成的目標代碼中找到此函數。
與extern對應的關鍵字是static,被它修飾的全局變量和函數只能在本模塊中使用。所以,一個函數或變量只可能被本模塊使用時,其不可能被extern 「C」修飾。
被extern "C"修飾的變量和函數是按照C語言方式編譯和鏈接的;
未加extern 「C」聲明時的編譯方式
首先看看C++中對相似C的函數是怎樣編譯的。做爲一種面向對象的語言,C++支持函數重載,而過程式語言C則不支持。函數被C++編譯後在符號庫中的名字與C語言的不一樣。例如,假設某個函數的原型爲:
該函數被C編譯器編譯後在符號庫中的名字爲_foo,而C++編譯器則會產生像_foo_int_int之類的名字(不一樣的編譯器可能生成的名字不一樣,可是都採用了相同的機制,生成的新名字稱爲「mangled name」)。_foo_int_int這樣的名字包含了函數名、函數參數數量及類型信息,C++就是靠這種機制來實現函數重載的。例如,在C++中,函數void foo( int x, int y )與void foo( int x, float y )編譯生成的符號是不相同的,後者爲_foo_int_float。一樣地,C++中的變量除支持局部變量外,還支持類成員變量和全局變量。用戶所編寫程序的類成員變量可能與全局變量同名,咱們以"."來區分。而本質上,編譯器在進行編譯時,與函數的處理類似,也爲類中的變量取了一個獨一無二的名字,這個名字與用戶程序中同名的全局變量名字不一樣。
未加extern "C"聲明時的鏈接方式
假設在C++中,模塊A的頭文件以下:
在模塊B中引用該函數:
實際上,在鏈接階段,鏈接器會從模塊A生成的目標文件moduleA.obj中尋找_foo_int_int這樣的符號!
加extern "C"聲明後的編譯和鏈接方式
加extern "C"聲明後,模塊A的頭文件變爲:
在模塊B的實現文件中仍然調用foo( 2,3 ),其結果是:
(1)模塊A編譯生成foo的目標代碼時,沒有對其名字進行特殊處理,採用了C語言的方式;
(2)鏈接器在爲模塊B的目標代碼尋找foo(2,3)調用時,尋找的是未經修改的符號名_foo。
因此,能夠用一句話歸納extern 「C」這個聲明的真實目的:實現C++與C及其它語言的混合編程。
extern "C"的慣用法
(1)在C++中引用C語言中的函數和變量,在包含C語言頭文件(假設爲cExample.h)時,需進行下列處理:
而在C語言的頭文件中,對其外部函數只能指定爲extern類型,C語言中不支持extern "C"聲明,在.c文件中包含了extern "C"時會出現編譯語法錯誤。筆者編寫的C++引用C函數例子工程中包含的三個文件的源代碼以下:
若是C++調用一個C語言編寫的.DLL時,當包括.DLL的頭文件或聲明接口函數時,應加extern "C" { }。
(2)在C中引用C++語言中的函數和變量時,C++的頭文件需添加extern "C",可是在C語言中不能直接引用聲明瞭extern "C"的該頭文件,應該僅將C文件中將C++中定義的extern "C"函數聲明爲extern類型。
筆者編寫的C引用C++函數例子工程中包含的三個文件的源代碼以下:
上面關於extern C的解析轉載自:C++中extern 「C」含義深層探索
其餘關於extern C 的知識可參見博文: