本章將開發你的第一個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語言程式的可移植性,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/552079.html
標籤:C++
上一篇:怎樣成為優秀的后端工程師
下一篇:返回列表