[分享] 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