首先,我們先來看下面這個經典的**:1
3 5
intint
printf
2
4
6
8
10
12
14
16
f(
)
voidvoid
int
main(
)
你知道這段**會輸出什麼嗎?a) 乙個隨機值,b) 42。a 和 b都對(在「在函式外訪問區域性變數的乙個比喻」文中的最後給過這個例子),不過,你知道為什麼嗎?
下面,我們再來看乙個示例:
1
3
5
7
b(
)
intvoid
printf
return
main(
)
這段程式會輸出什麼?,你會說是,3,4,7。但是我想告訴你,這也有可能輸出,4,3,7。為什麼呢? 這是因為,在c/c++中,表達的評估次序是沒有標準定義的。編譯器可以正著來,也可以反著來,所以,不同的編譯器會有不同的輸出。你知道這個特性以後,你就知道這樣的程式是沒有可移植性的。
我們再來看看下面的這堆**,他們分別輸出什麼呢?1
intprintf
"%d\n"
示例二
a=41; a++ &
(
, a);
1 intprintf
"%d\n"
示例四
a=41;
(a++ < 42)
(
, a);
1 intprintf
"%d\n"
2
4
structint
char
int
(
,
(
x));
structint
char
int
char
(
,
(
y));
這個**會輸出什麼?
a) 9,10
b)12, 12
c)12, 16
答案是c,我想,你一定知道位元組對齊,是向4的倍數對齊。
另外,再提一下,上述程式的printf中的%d並不好,因為,在64位下,sizeof的size_t是unsigned long,而32位下是 unsigned int,所以,c99引入了乙個專門給size_t用的%zu。這點需要注意。在64位平台下,c/c++ 的編譯需要注意很多事。你可以參看《64位平台c/c++開發注意事項》。
下面,我們再說說編譯器的warning,請看**:1
3 5
main(
)
考慮下面兩種編譯**的方式 :
前一種是不會編譯出a未初化的警告資訊的,而只有在-o的情況下,才會有未初始化的警告資訊。這點就是為什麼我們在makefile裡的cflags上總是需要-wall和 -o。
最後,我們再來看乙個指標問題,你看下面的**:1
3 5
7 9
#include
intvoid
int
printf
"%x\n"
printf
"%x\n"
printf
"%x\n"
printf
"%x\n"
}
假如我們的a的位址是:0xbfe2e100, 而且是32位機,那麼這個程式會輸出什麼?
看過這麼多,你可能會覺得c語言設計得真扯淡啊。不過我要告訴下面幾點dennis當初設計c語言的初衷:
1)相信程式設計師,不阻止程式設計師做他們想做的事。
2)保持語言的簡潔,以及概念上的簡單。
3)保證效能,就算犧牲移植性。
今天很多語言進化得很高階了,語法也越來越複雜和強大,但是c語言依然光芒四射,dennis離世了,但是c語言的這些設計思路將永遠不朽。
深入理解C語言 深入理解指標
關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...
深入理解C語言 深入理解指標
關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...
c語言 int轉char 深入理解C語言的指標
指標是c語言的乙個核心特色,它以一種統一方式對不同資料結構中的元素產生引用。對於新手來說,指標總是會帶來很多困惑,但其實指標的基本概念非常簡單。下面是一些指標和它們對映到機器 的關鍵原則。指標型別表明指標指向的是哪一類物件。比如 int ip char cpp 變數ip是乙個指向int型別物件的指標...