c語言重構
隨著互聯網編程技術的不斷發展,現在大多數的軟體開發都是通過編程語言來實現的,今天我們就一起來了解一下C語言編程開發技術都有哪些優勢和劣勢。
C語言的一些好的體驗
一次通過閱讀POV-Ray源代碼學會如何在C語言中實現面向對象編程。
通過閱讀GTK+源代碼了解C語言代碼的清晰、干凈和可維護性。
通過閱讀SIOD和Guile的源代碼,知道如何使用C語言實現Scheme解析器。
使用C語言寫出GNOMEEye的初始版本,並對MicroTile渲染進行調優。
C語言的一些不好的體驗
在Evolution團隊時,很多東西老是崩潰。那個時候還沒有Valgrind,為了得到Purify這個軟體,需要購買一台Solaris機器。
調試gnome-vfs線程死鎖問題。
調試Mesa,卻無果。
接手Nautilus-share的初始版本,卻發現代碼裡面居然沒有使用free()。
想要重構代碼,卻不知道該如何管理好內存。
想要打包代碼,卻發現到處是全局變數,而且沒有靜態函數。
但不管怎樣,還是來說說那些Rust里有但C語言里沒有的東西吧。
自動資源管理
Rust從C++那裡借鑒了一些想法,如RAII(,資源獲取即初始化)和智能指針,並加入了值的單一所有權原則,還提供了自動化的決策性資源管理機制。
自動化:不需要手動調用free()。內存使用完後會自動釋放,文件使用完後會自動關閉,互斥鎖在作用域之外會自動釋放。如果要封裝外部資源,基本上只要實現Drop這個trait就可以了。封裝過的資源就像是編程語言的一部分,因為你不需要去管理它的生命周期。
決策性:資源被創建(內存分配、初始化、打開文件等),然後在作用域之外被銷毀。根本不存在垃圾收集這回事:代碼執行完就都結束了。程序數據的生命周期看起來就像是函數調用樹。
如果在寫代碼時老是忘記調用這些方法(free/close/destroy),或者發現以前寫的代碼已經忘記調用,甚至錯誤地調用,那麼以後我再也不想使用這些方法了。
泛型
Vec真的就是元素T的vector,而不只是對象指針的數組。在經過編譯之後,它只能用來存放類型T的對象。
在C語言里需要些很多代碼才能實現類似的功能,所以我不想再這么幹了。
trait不只是interface
Rust並不是一門類似那樣的面向對象編程語言,它有trait,看起來就像是里的interface——可以用來實現動態綁定。如果一個對象實現了Drawable,那麼就可以肯定該對象帶有draw()方法。
不過不管怎樣,trait的威力可不止這些。
依賴管理
以前實現依賴管理需要:
手動調用或通過自動化工具宏來調用g-config。
指定頭文件和庫文件路徑。
基本上需要人為確保安裝了正確版本的庫文件。
而在Rust里,只需要編寫一個Cargo.toml文件,然後在文件里指明依賴庫的版本。這些依賴庫會被自動下載下來,或者從某個指定的地方獲取。
測試
C語言的單元測試非常困難,原因如下:
內部函數通常都是靜態的。也就是說,它們無法被外部文件調用。測試程序需要使用#include指令把源文件包含進來,或者使用#ifdefs在測試過程中移除這些靜態函數。
需要編寫Makefile文件將測試程序鏈接到其中的部分依賴庫或部分代碼。
需要使用測試框架,並把測試用例注冊到框架上,還要學會如何使用這些框架。
衛生宏(HygienicMacro)
Rust的衛生宏避免了C語言宏可能存在的問題,比如宏中的一些東西會掩蓋掉代碼里的標識符。Rust並不要求宏中所有的符號都必須使用括弧,比如max(5+3,4)。
沒有自動轉型
在C語言里,昆明北大青鳥http://www.kmbdqn.cn/發現很多bug都是因為在無意中將int轉成short或char而導致,而在Rust里就不會出現這種情況,因為它要求顯示轉型。
不會出現整型溢出
這個就不用再多作解釋了。
㈡ Qt通過TCP發送的結構體如何能被使用C語言寫
你應該是發送結構體里的數據吧。可以讀出來生成jason格式的字元串發送就好。接收端再用jason格式的解析器解析再生成結構體對象。c++寫的jason格式生成和解析的開源庫很多可以網上查。
㈢ 華為c語言編程規范是怎樣的
代碼總體原則
清晰第一。清晰性是易於維護、易於重構的程序必須具備的特徵。
簡潔為美。簡介就是易於理解並且易於實現。
選擇合適的風格,與源代碼風格保持一致。
頭文件
頭文件的設計體現了大部分的系統設計,不合理的頭文件布局是編譯時間過長的根因,實際上是不合理的設計。
頭文件中適合放置介面的聲明,不適合放置實現。
頭文件應當職責單一。
頭文件應向穩定的方向包含。
每一個.c文件應有一個同名的.h文件,用於聲明需要對外公開的介面。
禁止頭文件循環依賴。
禁止包含用不到的頭文件。
頭文件應當自包含。
編寫內部#include保護符(#define保護)。
禁止在頭文件中定義變數。
只能通過包含頭文件的方式使用其他C提供的介面,禁止在C中通過extern的方式使用外部函數介面和變數。
禁止在extern "C"中包含頭文件。
函數
函數設計的精髓:編寫整潔函數,同事把代碼有效組織起來。
一個函數僅完成一個功能。
重復代碼應該盡可能提煉成函數。
避免函數過長,新增函數不超過50行。
避免函數的代碼塊嵌套過深,新增函數的代碼塊嵌套不超過4層。
可重入函數應避免使用共享變數;若需要使用,則應該通過互斥手段對其加以保護。
對參數的合法性檢查,由調用者負責還是介面函數負責,應在項目組模塊內統一規定。預設由調用者負責。
對函數的錯誤返回碼要全面處理。
設計高扇入,合理扇出(小於7)的函數。扇出是指調用其它函數的數目。扇入是指有多少上級函數調用它。
廢棄代碼要及時清除。
函數參數不變使用const限定。
函數應避免使用全局變數、靜態局部變數和I/O操作,不可避免的地方應集中使用。
檢查函數所有非參數輸入的有效性,如數據文件、公共變數等。
函數的參數個數不超過5個。
在源文件范圍內聲明和定義的所有函數,除非外部可見,否則應該加static關鍵字。
標識符
標識符的命名要清晰、明了,有明確含義,同時使用完整的單詞或大家基本可以理解的縮寫,避免使人產生誤解。
產品、項目組內應保持同意的命名分格。
盡量避免名字中出現數字編號,除非邏輯上確實需要。
重構、修改部分代碼時,應該保持和原有代碼風格一致。
文件命令統一採用小寫字元。因為不同系統對文件名大小寫處理會有不同(windows不區分大小寫,但是linux系統則區分)。
全局變數應增加「g_」前綴。
靜態變數應增加「s_」前綴。
禁止使用單位元組命名變數,但是允許定義i,j,k作為局部循環變數。
不建議使用匈牙利命名法。
對於數值或者字元串常量的定義,建議採用全大寫字母,單詞之間加下劃線的方式命名。
變數
結構功能單一,不要設計面面俱到的數據結構。
不用或者少用全局變數
防止局部變數與全局變數同名
通訊過程中使用的機構,必須注意位元組序。
嚴禁使用未經初始化的變數作為右值。
使用面向介面編程思想,通過API訪問數據。
盡量減少沒有必要的數據類型默認轉換與強制轉換。
宏和常量
用宏定義表達式時,要使用完備的括弧。
將宏定義的多條表達式放在大括弧中。
使用宏時,不允許參數發生變化。
不允許直接使用魔鬼數字。
除非必要,應盡可能使用函數代替宏。
常量建議用const定義代替宏。
質量
時刻注意易混淆的操作符
必須了解編譯系統的內存分配方式,特別是編譯系統對不同類型的變數的內存分配規則,如局部變數在何處分配、靜態變數在何處分配等。
不僅關注介面,同樣要關注實現。
禁止內存操作越界。
禁止內存泄漏。
禁止引用已經釋放的內存空間。
編程時,要防止差1錯誤。
switch語句必須有default分支。
函數中分配的內存,在函數退出之前要釋放。
不要濫用goto語句。
時刻注意表達式是否會上溢、下溢。
程序效率
在保證軟體系統的正確性、簡潔、可維護性、可靠性及可測試性的前提下,提高代碼的效率。
通過對數據結構、程序演算法的優化來提高效率。
將不變條件的計算移到循環體外。
對於多維大數組,避免來回跳躍式訪問數組成員。
創建資源庫,以減少分配對象的開銷。
將多次被調用的「小函數」改為inline函數或者宏實現。
注釋
優秀的代碼可以自我解釋,不通過注釋即可輕易讀懂。
注釋的內容要清楚、明了,含義准確,防止注釋二義性。
修改代碼時,維護代碼周邊的所有注釋,以保證注釋與代碼的一致性。不再有用的注釋要刪除。
文件頭部應進行注釋,注釋需要列出:版權說明、版本號、生成日期、作者姓名、工號、內容、功能說明、與其他文件的關系、修改日誌等,頭文件的注釋中還應有函數功能的說明。
函數聲明處注釋描述函數功能、性能及用法,包括輸入和輸出參數、函數返回值、可重入的要求等;定義處詳細描述函數功能和實現要點,如實現的簡要步驟、實現的理由、設計約束等。
全局變數要有詳細的注釋,包括對其功能、取值范圍以及存取時注意事項等的說明。
盡量採用工具可以識別的格式注釋。
排版與格式
程序塊採用縮進風格編寫,每級縮進為4個空格。
相對獨立的程序塊之間、變數說明之後必須加空行。
一行只寫一條語句。
對等操作兩邊加空格,注釋符與內容之間加空格。
編譯
使用編譯器的最高告警級別,理解所有的告警,通過修改代碼而不是降低告警級別來消除所有告警。
在產品軟體中,要統一編譯開關、靜態檢查選項以及相應告警清除策略。
可測性
模塊劃分清晰,介面明確,耦合性小,有明確輸入和輸出,否則單元測試實施困難。
在統一項目組或產品組內,調測列印的日誌要有統一的規定。
使用斷言記錄內部假設。
不能用斷言來檢查運行時錯誤。
㈣ 如何重構這個switch語句
C語言還提供了多分支選擇的switch語句, 形式為:
switch(表達式){
case 常量表達式1: 語句1;
case 常量表達式2: 語句2;
…
case 常量表達式n: 語句n;
default: 語句n+1;
}
其語義是:計算表達式的值。 逐個與其後的常量表達式值相比較,當表達式的值與某個常量表達式的值相等時, 即執行其後的語句,不再進行判斷,繼續執行後面所有case後的語句。表達式的值與所有case後的常量表達式均不相同時,則執行default後的語句。
在使用switch語句時還應注意以下幾點:
在case後的各常量表達式的值不能相同,否則會出現錯誤。
在case後,允許有多個語句,可以不用{}括起來。
各case和default子句的先後順序可以變動,而不會影響程序執行結果。
default子句可以省略不用。
㈤ c語言重構是什麼意思,能舉一個具體的例子嗎,他和重構有什麼區別啊
親,你說的是函數重載吧?
重構是指代碼重構,就是重新寫代碼,因為前面寫過一次,所以再寫的時候可能會有更好的想法,就像做作業檢查一樣。
函數重載是指函數名一樣,參數不一樣,即為函數重載:
int func(int a){....},int func(char *p){....}和int func(int *p){....}都是它的重載函數
不知道你明白沒有
㈥ c語言是有什麼
C語言是一種通用的、面向過程式的計算機程序設計語言。1972 年,為了移植與開發 UNIX 操作系統,丹尼斯·里奇在貝爾電話實驗室設計開發了 C 語言。
C 語言是一種廣泛使用的計算機語言,它與 Java 編程語言一樣普及,二者在現代軟體程序員之間都得到廣泛使用。
C語言簡單例子:
(6)c語言重構擴展閱讀:
結構式語言的顯著特點是代碼及數據的分隔化,即程序的各個部分除了必要的信息交流外彼此獨立。這種結構化方式可使程序層次清晰,便於使用、維護以及調試。
C 語言是以函數形式提供給用戶的,這些函數可方便的調用,並具有多種循環、條件語句控製程序流向,從而使程序完全結構化。
㈦ 大一學習c語言快一學期了,准備在寒假裡面好好再深度學習一下,可是不知道該看哪些書,求推薦!
和其它語言作比較,C語言是一個相對較小的語言,它可以在相對較短的時間內學會。但由於C語言表達能力強,細節太多,很難掌握它。想要掌握C語言我認為應該讀經典名著,只閱讀經典名著。然後看看好的源代碼。還有學習軟體設計,並應用於日常編程。C語言是幾本經典的書,不需要花很多時間去看它。語言的優點和缺點更像是一種信念,而不是太多的討論,而且大多數編程原則都適用於任何語言。
當然,其實我比較建議你動手寫大量你喜歡的的程序,並選擇尋找問題和解決問題的書籍。國外非計算機專業的大學課程學習C都要求動手寫過3千行以上代碼,老師也沒推薦過任何書,倒是要求動手寫代碼。我想如果你喜歡C語言編程,你不應該錯過動手實踐。
㈧ 編程必須明確清楚這幾點,學習C語言和C++
一、宏觀:
將C++視為C、面向對象C++、模版C++、STL C++組成的語言聯邦。
任何人不得添加任何東西到STL命名空間
不要輕易忽略編譯器的警告
一定程度的使用測試驅動的開發方法
軟體實體(類、模塊、函數)應該是可擴展的,但是不可修改的
多採用敏捷的設計方法(個體和交互勝過過程和工具、可以工作的軟體勝過面面俱到的文檔、客戶合作勝過合同談判、響應變化勝過遵循計劃)
經常性的交付可以工作的軟體,交付的時間間隔越短越好
在整個項目開發期間,業務人員和開發人員必須天天都在一起工作
圍繞被激勵起來的個人來構建項目
在團隊內部,多進行面對面的交流
提倡可持續的開發速度
使要構造的系統最簡單(不要設計不需要的功能,不要過分設計)
最好的架構、需求和設計出自於自組織團隊
每隔一段時間,團隊會在如何才能更有效的工作方面進行反省,然後相應的對自己的行為進行調整
結對編程是一種比較好的選擇
不能容忍重復的代碼
持續的對代碼進行重構
要做計劃游戲
高層模塊不應該依賴於底層模塊。二者都應該依賴於抽象
盡可能的保證:抽象不應該依賴於細節,細節應該依賴於抽象(任何變數都不應該持有一個指向具體類的指針或引用;任何類都不應該從具體類派生;任何方法都不應該覆寫它的任何基類中已經實現了的方法)
每個編程單元盡可能的向使用者提供使用承諾:例如資源回收保證、數據一致性保證、無異常保證
盡可能的在程序中處理所有可能的異常,而且盡可能的精細。(try...catch)
應該讓程序體面的退出:在出現非計劃內問題時自動產生mp文件。(利用SetUnhandledExceptionFilter調用MiniDumpWriteDump)
要先設計好類,建好各個類的文件,才能寫代碼。
用pragma once代替h文件頭
二、類:
讓介面容易被正確使用,不易被誤用
設計class猶如設計type
將成員變數聲明為private
盡量不要讓類支持隱式類型轉換
friend成員函數是類介面的一種表現方式,但能避免使用就盡量避免
避免使用handles指向對象內部成分
慎重使用inline(小函數的確該用inline,但是考慮到inline函數無法調試,所以應謹慎)
確定public繼承表現出is-a關系(即Liskov替換原則,永遠可以用派生類取代基類)
避免覆蓋繼承而來的名稱(基類函數重載,派生不重載,則其他覆蓋;派生重載基類函數,則基類函數覆蓋;變數也可以覆蓋)
區別介面繼承和實現繼承(純介面(virtual=0),介面+樸素實現(virtual=0+實現),介面+強制實現(non-virtual),以上為public繼承,private繼承全部是為了繼承實現,而不繼承介面)
根據上一條,只要出現virtual,就盡可能讓它=0(成虛基類)
根據上上條,派生類不應該覆寫non-virtual函數
絕不重新定義繼承而來的預設參數值
private繼承意味著繼承實現,是composition,實現的是has-a邏輯。protected繼承盡量少用。兩種繼承在設計層面完全沒有意義,只是實現層面的代碼重用。
凡是獨立的對象都必須有非0大小(空對象會安插一個char)
一個類只負責一件事
一個類只提供一種內聚的介面(不應該讓用戶依賴於他們不使用的方法)
類內部的類型定義盡量放在public,否則不能作為返回值
類中的大屬性都應該用智能指針(或返回STL時應使用move語意)
凡是類內私有變數加m前綴,凡事類似私有仿函數,加or後綴
靜態成員初始化函數用靜態類替代,可以順便用個functor
四大函數(構造函數、拷貝構造、賦值、析構)
若有多態繼承體系,基類析構函數盡量聲明為virtual
如果類內new了對象,並且該類負責delete,則必須要定義拷貝構造函數和賦值操作符。
若不想使用編譯器自動生成的函數,就該默認拒絕(將其聲明在private或protected)
別讓異常逃離析構函數,C++不喜歡析構函數吐出異常
絕不在構造函數或析構函數中調用virtual函數(當然其他函數調用virtual可以實現template method等有趣的模式)
拷貝函數應該確保拷貝了對象內所有成員和基類部分
不要以某個拷貝函數去實現另外一個拷貝函數(一個是函數,一個是 assignment函數),應該把共同部分放在第三個獨立函數
三、函數:
盡量將函數參數聲明為const
另operator =返回一個*this的引用,並且在operator =中處理自我賦值
函數參數的構造順序不確定,所以不要在函數參數中執行new操作,或將多個函數參數都用函數來表示(否則若一個發生異常,其他有可能不會執行)。
盡量用傳遞const 引用代替傳值
non-member,none-friend函數有封裝性好,跨類型操作等能力,因此在需要的時候沒有必要局限於把函數全部放到類里的傳統規則。
若所有參數都需要類型轉換,請為此採用non-memeber函數(典型的是雙目操作符重載)
凡是需要對指針參數做提領操作,都需要檢查是否為BULL
發布版程序維持程序的勉強工作比crash更好;debug版讓程序盡量crash。
希望可以幫到你,謝謝!
㈨ 想買C語言的書,看到豆瓣網《重構》分數比較高!是國內人寫的,對國內的軟體書記我不抱信心!該不該買呢
absolutely not!推薦國外優秀書籍《C Primer Plus》,超級經典,內容太棒了,有中文版。
㈩ c語言是幹嘛的
C語言是用來編寫系統的。
最開始,人們手裡除了機器碼就是匯編,沒有別的語言。但是匯編有很多硬體相關的特性,可移植性差。貝爾實驗室要解決這一問題,就研發了C語言。
C語言可以跨平台,一份代碼,配上不同的編譯器就可以在各大電腦上運行。除此之外,C語言效率驚人,在某些情況中,如果匯編水平中等以下,編出來的匯編甚至沒有C語言生成的機器碼快。
現在,NOIP(現更名為CSP-J和CSP-S)僅允許初賽和復賽使用三種語言:Pascal、C、C++,C語言的重要性不言而喻。
雖然邁入了互聯網時代,但是C語言的地位也沒有低到可以忽略。C語言在對空間和時間要求較高的設備(如嵌入式設備)中發揮著重要功能,也可以編寫各大語言的編譯器,有著比較重要的地位。