Dissection C Chapter 2

本文总结对符号用法的相关讨论。

 

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> main(t,_,a)char *a;{return!0<t?t<3?main(-79,-13,a+main(-87,1-_, main(-86,0,a+1)+a)):1,t<_?main(t+1,_,a):3,main(-94,-27+t,a)&&t==2?_<13? main(2,_+1,"%s %d %d/n"):9:16:t<0?t<-72?main(_,t, "@n'+,#'/*{}w+/w#cdnr/+,{}r/*de}+,/*{*+,/w{%+,/w#q#n+,/#{l+,/n{n+,/+#n+,/#/ ;#q#n+,/+k#;*+,/'r :'d*'3,}{w+K w'K:'+}e#';dq#'l / q#'+d'K#!/+k#;q#'r}eKK#}w'r}eKK{nl]'/#;#q#n'){)#}w'){){nl]'/+#n';d}rw' i;# / ){nl]!/n{n#'; r{#w'r nc{nl]'/#{l,+'K {rw' iK{;[{nl]'/w#q#n'wk nw' / iwk{KK{nl]!/w{%'l##w#' i; :{nl]'/*{q#'ld;r'}{nlwb!/*de}'c / ;;{nl'-{}rw]'/+,}##'*}#nc,',#nw]'/+kd'+e}+;#'rdq#w! nr'/ ') }+}{rl#'{n' ')# / }'+}##(!!/") :t<-50?_==*a?putchar(31[a]):main(-65,_,a+1):main((*a=='/')+t,_,a+1) :0<t?main(2,2,"%s"):*a=='/'||main(0,main(-61,*a, "!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:/nuwloca-O;m .vpbks,fxntdCeghiry"),a+1);}

下面总结这部分内容需要注意的一些知识点。

1,注释符号
【问题1】C语言的注释可以出现在C语言代码的任何地方吗?
编译器会将注释剔除,但不是简单的删除,而是用空格代替原来的注释。因此,下面的注释[4]是不正确的:
#include <cstdio> int main() { // [1], ok int/*...*/i; // [2], ok char* s="abcd //efgh"; // [3], ok, note that there is no blank after '/'(backslash) character // Is it a / valid comment? // [4], error, because it equals to " in t i; " in/*...*/t i; return 0; }

【注意】/*...*/这种形式的注释不能嵌套。因为/*总是与离它最近的*/匹配。
/*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> int main() { int ival0=(-2)/2; // -1 int ival1=2/(-2); // -1 int ival2=2%(-2); // 0 equals to 4%2 int ival3=(-2)%2; // 0 equals to -(2%2) int ival4=3%(-3); // 0 equals to 6%3 int ival5=(-3)%3; // 0 equals to -(3%3) int ival6=2%(-3); // 2 equals to 5%3 int ival7=(-3)%2; // -1 equals to -(3%2) int ival8=5%(-2); // 1 equals to 7%2 int ival9=(-2)%5; // -2 equals to -(2%5) return 0; }

大多数编译器要求:余数与被除数的正负号相同。

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

你可能感兴趣的:(c,equals,语言,FP,编译器,2010)