[分享] Deep C (by Olve Maudal et al.) 心得

作者: wtchen (沒有存在感的人)   2016-03-30 04:34:56
本文同步分享在:http://gnitnawtw.blogspot.fr/2016/03/deep-c-c.html
為了增進對C語言的認識,我這幾天看了些成大資工"2016年系統軟體課程"分享的資料
以下是我看Olve Maudal 的投影片:Deep C 的心得
(為了了解內容我有參考wiki跟jserv大的C語言講座)
本文只有提到C的部份,C++的部份會另外寫。
(有錯請不吝指正)
投影片連結:
http://slideshare.net/olvemaudal/deep-c
1. 指出以下程式碼的結果與缺失
int main()
{
int a = 42;
printf("%d\n", a);
}
- 需 #include <stdio.h> 以明確宣告printf函式
+ 若使用C++編譯器編譯會失敗,因為C++編譯器需要明確(explicit)宣告使用函式。
+ 一般的C編譯器在函式未宣告的情況下會自動新增implicit宣告函式。
- 當連結(link)到標準函式庫,編譯器會找到prinf這個函式
- main為int型態卻沒有回傳值(return 0)
+ C99或更新的版本,main的回傳值為執行的成功(0)與否
+ 但是ANSI C或K&R C,在這種情況下回傳值為未定義(undefined)
- 有可能是3(因為printf的回傳值為輸出的char數)
+ 標準C應該要用main(void) (void表示不需要額外參數)
+ 標準C表示程式碼必須以一個空行做結。
============================================================
2.C語言的變數宣告
- static變數和global(全域)變數(被宣告在main外面)被宣告時自動被預設為0,
非static變數(在{}之內時被自動設為auto)宣告時預設值為undefined,這是因為
+ "預設變數為0"這個動作是要額外消耗CPU的,而C語言是非常在乎程式效能的,
所以在不需要的情況下不會刻意去做這種消耗CPU的事。
+ static跟global變數是被存在Data(有初始值)或BSS(無初始值)內,這兩個區塊
中的變數都是在編譯期就會固定住變數的位址,所以被預設為0不會影響到執行
的效率。此兩種變數的生命期跟程式的執行期一樣長
+ 而auto變數是被儲存在stack裏面,其位址並沒有被固定住。此種變數的生命期
只限於宣告位置前後的{}。
- static變數的影響力只限宣告該變數的檔案,global變數的影響力括及其他的obj檔案。
- 但是在C++的情況下,static變數是被預設成"某個預設值"(naive的情況就是0)
- 使用malloc/calloc/realloc宣告的某pointer空間,其生命期截止於
free該pointer的時候
============================================================
3.預測以下程式碼的結果
#include <stdio.h>
void foo(void)
{
int a;
++a;
printf("%d\n", a);
}
int main(void)
{
foo();
foo();
foo();
}
- a預設值為undefined
- 但在除錯模式的情況下,執行期有可能代為執行memset使得預設值為0
- 依本程式來看,a宣告的時候有可能都出現在stack內同樣的address中,
所以本程式的執行結果可能會顯示出3個連續的數列
(ex: 1,2,3 or 0,1,2 or 22,23,24),不過這視編譯最佳化的結果而定。
===================================================================
4.最佳化參數的影響
預測以下程式碼的結果並解釋原因
#include <stdio.h>
void foo(void)
{
int a;
printf("%d\n", a);
}
void bar(void)
{
int a=42;
}
int main(void)
{
bar();
foo();
}
- 沒最佳化的情況會是42
- 有最佳化的可能情況:
+ 省去bar(),反正沒影響
+ foo會變成main內的inline函式(反正沒其他函式會呼叫,這樣節省函式調用時間)
+ 所以結果可能會變成某個奇怪的數字(undefined)
- 平常儘可能用最佳化參數,以發現潛在的問題。
==============================================================
5.關於sequence point(順序點):
順序點是副作用發生與否的分界點,在順序點左邊的表示已經發生,右邊的還未發生。
在兩個順序點之間變量只能改變一次,不然結果會是undefined。
ex: (i=i++; 在分號前i的值改變兩次,結果會是undefined)。
C/C++裡的順序點其實不多,大致如下:
- &&, ||, 或?(三元運算符)
ex: (*a++ != 0 && *b++ != 0)
-> 會先算出*a++ != 0,再算出*b++ != 0,然後比較&&
- 完整表達式(用;當然這有點廢話)
以逗號分開的變數初始化
- ex: int a[3] = {b++,c
作者: Schottky (順風相送)   2016-03-30 07:25:00
「給你一條夠長的繩子,相信你不會簡簡單單就勒死自己」
作者: MOONRAKER (㊣牛鶴鰻毛人)   2016-03-30 12:10:00
printf(%d\n, a); 第一頁我只看到這個無敵大缺失大概跟通古斯卡大爆炸一樣大 相形之下其他微不足道
作者: descent (「雄辯是銀,沉默是金」)   2016-03-30 17:59:00
感謝分享
作者: FRAXIS (喔喔)   2016-03-30 19:19:00
第二點 其實是在討論 scope/linkage/namespace/life time不知道書上有沒有深入探討第五點 f/g/h哪個函式先開始呼叫 <- 應該是 unspecifiedbehavior 而不是 undefined behavior而且我不太理解 I/O 那部分跟 sequence point 有什麼關係
作者: WorkForFree (---)   2016-03-31 01:39:00
https://goo.gl/idBJ55也可以看這個,卡內基美隆分享的一系列安全的規範,不只有C還有其他的語言。
作者: littleshan (我要加入劍道社!)   2016-03-31 01:47:00
C的精神其實是worse is better,C code一點也不好維護C刻意設計得讓compiler容易做,這和「讓語言簡單扼要」有相當微妙的差異。不一定是你會錯意,作者可能也沒區分出兩者的不同worse is better 可以看看這篇 https://goo.gl/q7rDZ4
作者: Caesar08 (Caesar)   2016-03-31 11:43:00
C++ Philosophy https://goo.gl/udVmr8

Links booklink

Contact Us: admin [ a t ] ucptt.com