對象存儲是雲的基礎組件之一,各大雲廠商都有相關產品。這裡跟大家介紹一下rust與對象存儲交到的基本套路和其中的一些技巧。 ...
本章將開發你的第一個C語言程式:傳統的 "Hello, world!"程式。然後討論一些編輯器和編譯器的選項,並闡述移植性問題。
Hello, world!
#include <stdio.h>
#include <stdlib.h>
int main(void) {
puts("Hello, world!");
return EXIT_SUCCESS;
}
在Linux和其他類似Unix的操作系統上,你可以用cc命令調用系統編譯器:
$cc hello.c
$ls
a.out hello.c
$./a.out
Hello, world!
% cc -o hello hello.c
% ./hello
Hello, world!
cc命令有許多標誌和編譯器選項。例如,-o文件標誌讓你給可執行文件起名字,而不是a.out。
hello.c程式的前兩行使用了#include預處理器指令,它的行為就像你在完全相同的位置用指定文件的內容替換它一樣。我們包括<stdio.h>和<stdlib.h>頭文件來訪問這些頭文件中聲明的函數,然後我們可以在程式中調用這些函數。puts函數在<stdio.h>中聲明,而EXIT_SUCCESS巨集在<stdlib.h>中定義。正如文件名所示,<stdio.h>包含了C語言標準I/O函數的聲明,而<stdlib.h>則包含了一般實用函數的聲明。
C定義了兩種可能的執行環境:獨立的和托管的。獨立環境可能不提供操作系統,通常用於嵌入式編程。這些執行環境提供了一套最小的庫函數,程式啟動時調用的函數的名稱和類型是執行環境定義的。
我們定義main返回int類型的值,並將void放在括弧內,表示該函數不接受參數。int類型是有符號的整數類型,可以用來表示正、負整數值以及零。與其他程式性語言類似,C語言程式由可以接受參數和返回值的過程(稱為函數)組成。每個函數都可重用,你可以根據需要在程式中頻繁調用。在本例中,主函數返回的值表示程式是否成功終止。
puts("Hello, world!")列印出"Hello, world!"。 puts函數是標準庫函數,它將字元串參數寫入stdout(通常代表控制台或終端視窗),併在輸出中附加換行符。如果不需要換行可以使用fputs。
return語句退出程式,向主機環境或調用腳本返回一個整數值。EXIT_SUCCESS是類似對象的巨集,通常擴展為0,通常定義為:#define EXIT_SUCCESS 0。
檢查函數的返回值
函數通常會返回一個計算結果的值,或者表示函數是否成功完成了它的任務。例如,我們在 "Hello, world!"程式中使用的puts函數需要列印字元串並返回int類型的值。如果發生寫入錯誤,puts函數返回巨集EOF的值(負整數);否則,它返回非負的整數值。
儘管對於我們的簡單程式來說,puts函數不太可能失敗並返回EOF,但這是可能的。因為對puts的調用可能會失敗並返回EOF,這意味著你的第一個C程式有bug,或者,可以按以下方法改進。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
if (puts("Hello, world!") == EOF) {
return EXIT_FAILURE;
// code here never executes
}
return EXIT_SUCCESS;
// code here never executes
}
註意(puts("Hello, world!")一定要有括弧,否則編譯會報錯:
c$ cc hello2.c
hello2.c: In function ‘main’:
hello2.c:5:5: error: expected ‘(’ before ‘puts’
5 | if puts("Hello, world!") == EOF {
| ^~~~
| (
格式化的輸出
puts函數是一種將字元串寫入stdout的簡單好方法,但最終你會需要使用printf函數來列印格式化的輸出--例如,列印字元串以外的參數。printf函數接收定義輸出格式的格式化字元串,然後是可變數量的參數,這些參數是你想列印的實際數值。例如,如果你想用printf函數來列印Hello, world!,你可以這樣寫。
printf("%s\n", "Hello, world!")。
第一個參數是格式字元串"%s\n"。%s是轉換規範,指示printf函數讀取第二個參數(字元串字面)並將其列印到stdout。\n是一個字母轉義序列,用於表示非圖形字元,並告訴函數在該字元串後麵包括新行。
註意不要將用戶提供的數據作為第一個參數的一部分傳遞給printf函數,因為這樣做會導致格式化輸出的安全漏洞(Seacord 2013)。
編輯器和集成開發環境
可以使用各種編輯器和集成開發環境來開發你的C語言程式。圖1-1顯示了最常用的編輯器,根據2018年JetBrains的調查。
對於Microsoft Windows,Microsoft的Visual Studio IDE(https://visualstudio.microsoft.com/)是不錯的選擇。Visual Studio有三個版本。社區版、專業版和企業版。社區版的優點是免費,而其他版本的功能則需要付費。
對於Linux來說,Vim、Emacs、Visual Studio Code和Eclipse都可選擇。Vim是許多開發者和高級用戶的首選編輯器。它是一個基於vi編輯器的文本編輯器,由Bill Joy在1970年代為Unix的一個版本編寫。它繼承了vi的按鍵綁定,但也增加了原vi所缺少的功能和可擴展性。你可以選擇安裝Vim插件,如YouCompleteMe(https://github.com/Valloric/YouCompleteMe/)或deoplete(https://github.com/Shougo/deoplete.nvim/),為C語言編程提供本地語義完成。
GNU Emacs是可擴展的、可定製的、免費的文本編輯器。它的核心是Emacs Lisp的解釋器,這是一種Lisp編程語言的方言,具有支持文本編輯的擴展功能--儘管我從未發現這是個問題。
Visual Studio Code(VS Code)是精簡的代碼編輯器,支持開發操作,如調試、任務運行和版本控制。它提供了開發人員所需的工具,以實現快速的代碼構建--調試迴圈。VS Code可以在macOS、Linux和Windows上運行,對私人或商業使用都是免費的。
編譯器
現在有很多C語言編譯器,他麽編譯器實現了不同版本的C標準。許多用於嵌入式系統的編譯器只支持C89/C90。用於Linux和Windows的流行編譯器更努力地支持現代版本的C標準,直到並包括對C2x的支持。
- GNU 編譯器集
GNU編譯器集合(GCC)包括C、C++和Objective-C以及其他語言的前臺(https://gcc.gnu.org/)。GCC的開發在GCC指導委員會的指導下遵循明確的開發計劃。
GCC已經被採納為Linux系統的標準編譯器,儘管也有用於微軟Windows、macOS和其他平臺的版本。在Linux上安裝GCC很容易。例如,下麵的命令在Ubuntu上安裝GCC 8。
$ sudo apt-get install gcc-9
$ gcc --version
gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ sudo dnf install gcc # Fedora
- Clang
另一個流行的編譯器是Clang(https://clang.llvm.org/)。在Linux上安裝Clang也很容易。例如,下麵的命令應該在Ubuntu上安裝Clang。
$ sudo apt-get install clang
你可以用下麵的命令測試你所使用的Clang的版本。
% clang --version
$ clang --version
clang version 10.0.0-4ubuntu1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
- 微軟Visual Studio
Windows最流行的開發環境是Microsoft Visual Studio,它包括IDE和編譯器。它與Visual C++ 2019捆綁在一起,其中包括C和C++編譯器。
你可以在項目屬性頁上為Visual Studio設置選項。在C/C++下的高級選項卡上,確保你通過使用編譯為C代碼(/TC)選項而不是編譯為C++代碼(/TP)選項來編譯為C代碼。預設情況下,當你命名一個以.c為擴展名的文件時,它是用/TC編譯的。如果文件被命名為.cpp、.cxx或其他一些擴展名,則用/TP編譯。
參考資料
- 本文涉及的python測試開發庫 謝謝點贊! https://github.com/china-testing/python_cn_resouce
- python精品書籍下載 https://github.com/china-testing/python_cn_resouce/blob/main/python_good_books.md
- 本書英文原版: Effective C An Introduction to Professional C Programming 2020 a4.5-103--.epub
https://url97.ctfile.com/f/18113597-810419181-1f9306 下載密碼 訂閱號pythontesting 發送 密碼 。
移植性
每個C語言編譯器的實現都至少有一點不同。編譯器不斷發展,因此,例如,像GCC這樣的編譯器可能提供對C17的完全支持,但正在努力實現對C2x的支持,在這種情況下,它可能有一些C2x的功能實現,但沒有其他。因此,編譯器支持全部的C標準版本(包括中間的版本)。C語言實現的總體發展是緩慢的,許多編譯器明顯落後於C標準。
如果為C語言編寫的程式只使用標準中規定的語言和庫的那些功能,就可以認為是嚴格符合標準的。這些程式的目的是為了最大限度地提高可移植性。然而,由於實現行為的範圍,現實世界中沒有一個C語言程式是嚴格符合要求的,也不會是(可能也不應該是)。相反,C標準允許你編寫符合要求的程式,這些程式可能依賴於非可移植的語言和庫特性。
通常的做法是為一個參考實現編寫代碼,或者有時為幾個實現編寫代碼,這取決於你打算在哪個平臺上部署你的代碼。C標準是確保這些實現不會有太大的差異,並允許你一次針對幾個實現,而不必每次都學習一種新的語言。
在C標準文件的附件J中列舉了五種可移植性問題。
-
實現定義的行為
-
未指定的行為
-
未定義的行為
-
針對本地的行為
-
常見的擴展
-
實現定義的行為
實現定義的行為是指C語言標準中沒有規定的程式行為,它可能在不同的實現中提供不同的結果,但在一個實現中具有一致的、有記錄的行為。實現定義的行為的一個例子是一個位元組中的位數。
實現定義的行為大多是無害的,但在移植到不同的實現時可能會導致缺陷。在可能的情況下,避免編寫依賴於實現定義的行為的代碼,這些行為在你可能用來編譯你的代碼的C實現中是不同的。C標準的附件J.3中列舉了實現定義行為的完整列表。你可以通過使用static_assert聲明來記錄你對這些實現定義的行為的依賴。
- 未指定的行為
未指定的行為是指標準提供了兩個或多個選項的程式行為。該標準對在任何情況下選擇哪個選項沒有要求。每次執行一個給定的表達式可能會有不同的結果,或者產生與之前執行相同表達式不同的值。未指定行為的一個例子是函數參數存儲佈局,它在同一程式中的不同函數調用中可能會有所不同。避免編寫依賴於C標準附件J.1中列舉的非指定行為的代碼。
-
未定義的行為
未定義的行為是指C標準沒有定義的行為,或者說是 "在使用不可移植的或錯誤的程式結構或錯誤的數據時,標準沒有規定的行為"。未定義行為的例子包括有符號的整數溢出和解讀一個無效的指針值。具有未定義行為的代碼往往是錯誤的,但比這更有細微差別。標準中對未定義行為的識別如下。 -
當違反了 "應當 "或 "不應當 "的要求,並且該要求出現在約束條件之外時,該行為是未定義的
-
當行為被明確規定為 "未定義行為 "時
-
通過省略任何明確的行為定義
前兩種未定義行為經常被稱為顯式未定義行為,而第三種則被稱為隱式未定義行為。這三者之間的重點沒有區別,它們都描述了未定義的行為。C語言標準附件J.2 "未定義行為 "包含了C語言中顯式未定義行為的列表。
開發者經常誤認為未定義的行為是C標準中的錯誤或遺漏,但將行為歸為未定義的決定是有意的,也是經過考慮的。C標準委員會將行為歸類為未定義的行為是為了做到以下幾點。
- 給予實現者許可,使其不去捕捉難以診斷的程式錯誤
- 避免定義晦澀難懂的案例,使之有利於一種實現策略而不是另一種策略
- 識別可能的符合要求的語言擴展領域,在這些領域中,實現者可以通過提供官方未定義行為的定義來增強語言。
這三個原因實際上是完全不同的,但都被認為是可移植性問題。編譯器(實現)有做以下事情的餘地。 - 完全忽略未定義的行為,產生不可預測的結果
- 以環境特征的文件方式行事(有或沒有發出診斷書)。
- 終止翻譯或執行(發出診斷)。
這些選項都不是很好(尤其是第一個),所以最好避免未定義的行為,除非實現指定這些行為的定義是為了讓你調用一個語言增強功能。
- 特定於本地的行為和通用擴展
特定於本地的行為取決於每個實現所記錄的國籍、文化和語言的本地慣例。通用擴展在許多系統中被廣泛使用,但並不能移植到所有的實現中。
小結
在這章中,你學會瞭如何編寫簡單的C語言程式,編譯它,並運行它。然後,我們看了幾個編輯器和互動式開發環境,以及一些編譯器,你可以用它們來開發Windows、Linux和macOS系統上的C語言程式。一般來說,你應該使用較新版本的編譯器和其他工具,因為它們往往支持C編程語言的較新功能,並提供更好的診斷和優化。如果較新版本的編譯器破壞了你現有的代碼,或者你正準備部署你的代碼,你可能不想使用較新版本的編譯器,以避免在你已經測試過的應用程式中引入不必要的變化。在本章的最後,我們討論了C語言程式的可移植性。
釘釘或微信號: pythontesting 微信公眾號:pythontesting