程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 語言的數據親和力

語言的數據親和力

編輯:關於C語言

目前,程序設計語言似乎進入了一個蓬勃發展的時期,Javascript、Perl、Python、Ruby、Groovy等一批較新的語言正越來越多地被熟悉和使用,而C++、C#、Java等主流語言也在不斷地融入函數式和動態性特征。程序員的百寶箱中可供選擇的寶貝是越來多了,而社區中關於語言間的比較和爭論也更為熱烈,我們常常見到關於“面向過程和面向對象的比較”、“動態語言和靜態語言的比較”、“命令式和函數式范式的比較”等比較。我注意到這類討論的關注點多集中於設計相關話題,如“動態語言的Duck typing多態和靜態語言的繼承多態的比較”,“Prototype based和Class based的比較”等。但我認為還有一個十分重要的方面值得關注,這就是數據處理。

數據處理之所以重要是因為不論是本地信息存儲還是系統間信息交換都需要建立在一定的數據格式基礎上。另外,不管語言屬於那種范式,設計上采用什麼模式,在微觀層次上程序很大一部分工作都是在做數據處理。所以,從數據處理角度比較和理解語言間的差異有重要的現實意義。雖然數據通常是平台和語言無關的,但不同的語言在處理某種格式的數據時會表現出不同的難度,甚至某些數據格式只能采用特定的語言才能實現,這就是數據親和力的不同。

語言的數據親和力(Data Affinity)指的是語言的數據模型與某種數據格式之間的匹配程度。語言對某種數據格式親和力越強,則操作某類數據越容易。


二進制字節塊格式


在偏底層的操作系統、嵌入式和通信系統中,二進制的字節塊是最常見的一種數據格式。二進制數據布局緊湊和接近機器的特點使得它常常作為系統間通信或系統文件的數據格式,但一般高級語言都不方便直接和0101打交道,而是基於記錄、結構體和類等結構化表示操作數據,這就存在著在底層的二進制字節塊和高層的結構化數據直接的轉換問題。

 


C語言作為最主要的系統語言具有很高的字節塊數據親和力。這不僅因為C語言具有指針可以直接訪問內存以外,還因為C的結構體(struct)可以和字節塊建立起直接的映射關系。例如,在基於Socket連接的分布式系統中服務器端和客戶端通過二進制的字節數據進行通信,通信雙方只要事先定義共用的結構體,發送方先創建相應的結構體變量並填充字段,然後把變量對應的內存塊copy到Socket,接收方從Socket讀取字節塊,然後把字節塊強制類型轉換為相應的結構體指針即可讀取個字段信息。整個過程中通信的雙方都沒有復雜的信息編碼和解碼的過程。示例代碼如下:

1234567891011121314151617 struct t_data {     int version;     char type[10];     float value; };   //發送方 struct t_data data; data.version = 1; strcpy(data.type,  “degree”); data.value = 189.0; send(socket,  &data,  sizeof(data));   //接收方 struct t_data data; read(socket,  &data,  sizeof(data)); printf(“%d, %s, %f”, data.version,  data.type, data.value);


上面的方法在實際應用中還需要注意內存對齊問題和大小端問題。內存對齊問題可以通過編譯器預處理命令來進行控制,保證內存中struct結構與傳輸的字節塊具有相同的對齊方式;大小端問題需要通信的雙方采用同樣的大小端方式,否則就需要進行轉換。

C++可以完全兼容C的結構體,但C++的類(包括class和struct)中如果定義了虛函數,則會喪失結構的字節塊數據親和力,這是C++編程時需要權衡的一個因素。而除了C/C++,其他語言中則難以見到字節塊數據親和力,其原因在於C/C++允許控制結構體/對象的內存布局,並允許對指針進行非類型安全的強制類型轉換,這都是在Java,C#等語言中不允許的。所以,在Java、C#中進行字節塊的編碼解碼就只能按照協議一個字段一個字段地按偏移量和長度進行解析。C/C++的指針以及結構體和內存的直接映射帶來了對字節塊數據的親和力,但同時也留下了內存訪問和類型安全的隱患;而Java、C#在擁有引用安全和類型安全的同時也失去了對字節塊數據的親和力。

 

文本格式
文本格式是另一種十分常見的數據格式。《Unix編程藝術》中是這樣描述文本格式的:”Text streams are a valuable universal format because they’re easy for human beings to read, write, and edit without specialized tools ”。基於文本流的管道處理是一種備受贊譽的Unix風格。Shell可以通過管道把各種功能單一的命令串聯起來,讓文本流在管道上流動,因而Shell語言具有很好的文本數據親和力。許多文本數據處理任務Bash都可以一行搞定,這就是Hacker們酷愛的One Liner風格。


下面我們來看兩個用Bash進行文本處理的例子:

1. 統計當前目錄下的gz文件數目:

1 ls –l *.gz | wc –l


2. 在Web服務器日子service.log中統計2011年6月26和27兩天中每天中各頁面的PV

1 cat service.log | grep  ^2011-06-2[6-7] | cut –d ‘ ‘ –f 1, 3 | sort | uniq –c


service.log:

2011-06-25 13:00:55 /music/c.htm Safari

2011-06-26 08:01:23 /main.htm IE
2011-06-26 08:03:01 /sports/b.htm Chrome

2011-06-27 11:41:06 /main.htm IE
2011-06-27 11:52:41 /news/a.htm Firefox

 


輸出:

210 2011-06-26 /main.htm
231 2011-06-26 /news/a.htm
155 2011-06-26 /sports/b.htm
288 2011-06-27 /main.htm
292 2011-06-27 /news/a.htm
161 2011-06-27 /sports/b.htm


上面的兩個簡單文本數據處理任務如果是在C或C++下實現則要麻煩得多,代碼量至少是十幾行或者數十行,加上編譯調試,整個開發效率可能比Shell低一個數量級。除了Shell外,Perl也是以強大的文本數據處理而聞名的。我們來看一個Perl正則表達式的例子:

12345678 while (<STDIN>) {     if (/hellos(w+)/i)  {         print “say hello to $1“      }      else if (/goodbyes(w+)/i)  {          print “say goodbye to  $1”     } }

輸入:

HeLLo world

Goodbye bug

輸出:

say hello to world

say goodbye to bug

上面的例子中我們看到Perl直接進行字符串匹配並進行數據提取的強大威力。Perl基於正則表達式的字符串處理不僅比C/C++等系統語言更強大,甚至比Python這樣的動態語言也更強大和更方便,這是因為正則表達式是Perl語言的“一等公民”,這就使得Perl比其他以庫的方式支持正則表達式功能的語言具有更好的文本數據親和力。後來的Ruby也學習Perl把直接在語言上支持正則表達式。


結構化文本格式
XML是最近十幾年來流行起來的一種通用(半)結構化的文本數據交換格式。XML除具有一般文本格式的優點外,還具有表達復雜的層次信息的優勢,所以它至誕生以來就被大量用於配置文件和各種Web Service中。現代程序設計基本都少不了了XML打交道,不過在C++、Java和C#集中靜態類型語言中處理XML卻並不是一件十分輕松的事情。我們先來看一個Java解析和構建下面這個XML的例子:

12345 <langs type="current">   <language>Java</language>   <language>Groovy</language>   <language>JavaScript</language> </langs>


1234567891011121314151617181920212223242526272829303132333435363738394041 //Java解析XML DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try {     DocumentBuilder db = dbf.newDocumentBuilder();     Document doc = db.parse("src/languages.xml");     Element langs = doc.getDocumentElement();     System.out.println("type = " + langs.getAttribute("type"));     NodeList list = langs.getElementsByTagName("language");     for(int i = 0 ; i &lt; list.getLength();i++) {         Element language = (Element) list.item(i);         System.out.println(language.getTextContent());     } }catch(Exception e) {     e.printStackTrace(); }   //Java創建XML DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try {     DocumentBuilder db = dbf.newDocumentBuilder();     Document doc = db.newDocument();     Element langs = doc.createElement("langs");     langs.setAttribute("type", "current");     doc.appendChild(langs);       Element language1 = doc.createElement("language");     Text text1 = doc.createTextNode("Java");     language1.appendChild(text1);     langs.appendChild(language1);       Element language2 = doc.createElement("language");     Text text2 = doc.createTex

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved