本文總結對符號用法的相關討論。
2010-10-20 wcdj
本文接:Dissection C Chapter 1_3
http://blog.csdn.net/delphiwcdj/archive/2010/10/18/5948666.aspx
1,注釋符號
2, 續行符和轉義符
3,單引號、雙引號
4,邏輯運算子
5,位元運算符
6,花括弧
7,++、--操作符(CSDN上常見的月經貼)
8,運算式2/(-2)的值是多少?
9,運算子的優先順序
【思考】'/'這個符號在C語言裡都用在哪些地方?(能否回答完整)
C語言的基本符號有20多個(28),每個符號可能同時具有多重含義,而且這些符號之間相互組合又使得C語言中的符號變得更加複雜起來。
下面代碼是1988年國際C語言亂碼大賽(IOCCC)的獲獎作品,作者是Ian Phillipps(世界上最頂級的C語言程式員之一)。
關於這段代碼的分析可見:
http://wenku.baidu.com/view/b246f27931b765ce05081452.html
#include <stdio.h><br />main(t,_,a)char *a;{return!0<t?t<3?main(-79,-13,a+main(-87,1-_,<br />main(-86,0,a+1)+a)):1,t<_?main(t+1,_,a):3,main(-94,-27+t,a)&&t==2?_<13?<br />main(2,_+1,"%s %d %d/n"):9:16:t<0?t<-72?main(_,t,<br />"@n'+,#'/*{}w+/w#cdnr/+,{}r/*de}+,/*{*+,/w{%+,/w#q#n+,/#{l+,/n{n+,/+#n+,/#/<br />;#q#n+,/+k#;*+,/'r :'d*'3,}{w+K w'K:'+}e#';dq#'l /<br />q#'+d'K#!/+k#;q#'r}eKK#}w'r}eKK{nl]'/#;#q#n'){)#}w'){){nl]'/+#n';d}rw' i;# /<br />){nl]!/n{n#'; r{#w'r nc{nl]'/#{l,+'K {rw' iK{;[{nl]'/w#q#n'wk nw' /<br />iwk{KK{nl]!/w{%'l##w#' i; :{nl]'/*{q#'ld;r'}{nlwb!/*de}'c /<br />;;{nl'-{}rw]'/+,}##'*}#nc,',#nw]'/+kd'+e}+;#'rdq#w! nr'/ ') }+}{rl#'{n' ')# /<br />}'+}##(!!/")<br />:t<-50?_==*a?putchar(31[a]):main(-65,_,a+1):main((*a=='/')+t,_,a+1)<br /> :0<t?main(2,2,"%s"):*a=='/'||main(0,main(-61,*a,<br />"!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:/nuwloca-O;m .vpbks,fxntdCeghiry"),a+1);}
下面總結這部分內容需要注意的一些知識點。
1,注釋符號
【問題1】C語言的注釋可以出現在C語言代碼的任何地方嗎?
編譯器會將注釋剔除,但不是簡單的刪除,而是用空格代替原來的注釋。因此,下面的注釋[4]是不正確的:
#include <cstdio><br />int main()<br />{<br />// [1], ok<br />int/*...*/i;<br />// [2], ok<br />char* s="abcd //efgh";<br />// [3], ok, note that there is no blank after '/'(backslash) character<br />// Is it a /<br />valid comment?<br />// [4], error, because it equals to " in t i; "<br />in/*...*/t i;<br />return 0;<br />}
【注意】/*...*/這種形式的注釋不能嵌套。因為/*總是與離它最近的*/匹配。
/*This is/*wrong*/*/
【問題2】y=x/*p;正確嗎?
y=x/*p,這是表示x除以p指向的記憶體裡的值,把結果賦給y嗎?我們在編譯器上測試一下,發現出錯。
原因是:實際上,編譯器把/*當作是一段注釋的開始,把/*後面的內容都當作注釋內容,直到出現*/為止。這個運算式其實只是表示把x的值賦給y,/*後面的內容都當作注釋,但是,由於沒有找到*/,所以提示出錯。修改方法為:
(1) y=x/ *p;// 在'/'符號後添加至少一個空格符
(2) y=x/(*p);// 或者添加括弧
修改後,運算式的意思才是,x除以p指向的記憶體裡的值,最後把結果賦給y了。
【注意】只要斜杠(/)和星號(*)之間沒有空格,都會被當作注釋的開始。
【問題3】怎樣才能寫出出色的注釋?(糟糕的注釋只會幫倒忙)
2, 續行符和轉義符
【注意】反斜線(/)(續行符)之後不能有空格。
反斜線除了可以被用作續行符,還能被用作逸出字元的開始標識。
廣義地講,C語言字元集中的任何一個字元均可用逸出字元來表示。即用:
/ddd 1~3位八位元所代表的字元
/xhh 1~2位十六進位數所代表的字元
ddd和hh分別為八進位和十六進位的ASCII碼。如:/102表示字母'B'(66,dec.),/134表示反斜線,/X0A表示換行,/X0D表示斷行符號等。
3,單引號、雙引號
【注意】表示方式不一樣,所佔的記憶體大小也不一樣。
1,'1',"1"
第一個是整型常數,32位系統下佔4B大小。
第二個是字元常量,佔1B大小。
第三個是字串常量,佔2B大小(包括字串結束符('/0'))。
【注意】字元在記憶體裡是以ASCAII碼儲存的,所以字元常量可以與整型常量或變數進行運算。如:'A'+1。
4,邏輯運算子
【注意】||和&&是邏輯運算子,|和&是按位元運算符。
【注意】小心“短路規則”。
5,位元運算符
C語言中位元運算包括下面六種:
& 按位於
| 按位或
^ 按位異或(p^q=~p*q+p*~q)
~ 取反
<< 左移
>> 右移
【注意】用異或^運算子可以實現對兩個數的交換。(想想,交換兩個整數有幾種方法?異或,中間變數,先加後減,……)
【問題1】左移和右移
[1] 左移運算子"<<"是雙目運算子。其功能是把"<<"左邊的運算數的各二進位位全部左移若干位,由"<<"右邊的數指定移動的位元,高位丟棄,低位補0。
[2] 右移運算子">>"是雙目運算子。其功能是把">>"左邊的運算數的各二進位位全部右移若干位,由">>"右邊的數指定移動的位元。
但注意:對於有符號數,在右移時,符號位將隨同移動。當為正數時,最高位補0;而為負數時,符號位為1,最高位是補0還是1取決於編譯系統的規定。Turbo C和很多系統規定為補1。
【問題2】0x01<<2+3的值為多少?結果為7嗎?
// warning C4554: “<<”: 檢查運算子優先順序可能存在的錯誤;使用圓括弧闡明優先順序 (VS2008提示)
int ival=0x01<<2+3;// 32
因為"+"號的優先順序比移位元運算的優先順序高。
思考:下面的行為正確嗎?(發生了溢出!)
// warning C4293: “<<”: Shift 計數為負或過大,其行為未定義
int ival2=0x01<<2+30;// VS2008下為
// warning C4293: “>>”: Shift 計數為負或過大,其行為未定義
int ival2=0x01>>2+30;// VS2008下為
// warning C4293: “>>”: Shift 計數為負或過大,其行為未定義
int ival3=0x01>>2-3;// VS2008下為
結論:左移和右移的位元不能大於資料的長度,而且不能小於0,否者其行為未定義。
6,花括弧
【問題】花括弧的作用是什嗎?
char a[10]="abcd";
char b[10]={"abcd"};
//char c[10] { ="abcd" };// error
簡單地說,花括弧的作用就是:打包,使其中的語句成為一個整體,並與外界絕緣。
7,++、--操作符(CSDN上常見的月經貼 -_- !)
【問題】下面的結果是什嗎?
int i=3, j;
j=(++i)+(++i)+(++i);// j==18 (VS2008)
int i=3, j;
j=(++i)+(++i)+(++i);// j==18 (VC6.0)
j的值是多少呢?15、16、18嗎?
其實對於這種情況,C語言標準並沒有作出規定。
VS2008的計算過程是:i先經過3次自加後變為6,然後3個6相加得18。
VC6.0的計算過程是:先計算前兩個i的和,這個時候i自加2次,2個i的和為10,然後再加上第三次自加的i得16。
8,運算式2/(-2)的值是多少?
#include <cstdio><br />int main()<br />{<br />int ival0=(-2)/2;// -1<br />int ival1=2/(-2);// -1<br />int ival2=2%(-2);// 0equals to 4%2<br />int ival3=(-2)%2;// 0equals to -(2%2)<br />int ival4=3%(-3);// 0equals to 6%3<br />int ival5=(-3)%3;// 0equals to -(3%3)<br />int ival6=2%(-3);// 2equals to 5%3<br />int ival7=(-3)%2;// -1equals to -(3%2)<br />int ival8=5%(-2);// 1equals to 7%2<br />int ival9=(-2)%5;// -2equals to -(2%5)<br />return 0;<br />}<br />
大多數編譯器要求:餘數與被除數的加號或減號相同。
9,運算子的優先順序
【一些容易出錯的優先順序問題】
[1] .的優先順序高於*,*p.f相當於*(p.f)
[2] []高於*,int *ap[]相當於int *(ap[]),是一個指標數組
[3] 函數()高於*,int *fp()相當於int *(fp()),是一個函數
[4] ==和!=高於位操作,(val & mask != 0)相當於val & (mask != 0)
[5] ==和!=高於賦值符,c=getchar()!=EOF相當於c=(getchar()!=EOF)
[6] 算術運算子高於位移運算子,msb<<4+lsb相當於msb<<(4+lsb)
[7] 逗號運算子在所有運算子中優先順序最低,i=1, 2相當於(i=1), 2