尽管有些编译器同意这样的行为。可是这样的写法是不值得提倡的。
5.空指针
除了一个重要的例外情况,在C语言中将一个整数转换为一个指针,最后得到的结果都取决于详细的C编译器实现。
这个特殊情况就是常数0。编译器保证由0转换而来的指针不等于不论什么有效的指针,出于代码文档化的考虑,常数0这个值经经常使用一个符号来取代:
#define NULL 0
须要记住的是当常数0被转换为指针使用时,这个指针绝对不能被解除引用(解除引用即是使用(*p)这类取该地址中内容的操作),换句话说。当我们将0赋值为一个指针变量时,绝对不能企图使用该指针所指向的内存中所存储的内容。
6.C语言中“不正确称边界”的优点
在C语言中定义了一个数组int a[10]之后,数组的下标0~9为合法的下标,而下标10已经超出了数组的范围。这样做的优点是什么呢?
第一个优点,请看以下的一个样例:
for(i = 0; i < 10; i++)
a[i] = *p++;
假设用户给出了begin(0)和end(10)的范围之后要求对这之间的单元进行操作,假设用户给定的begin和end是同样的话,上面这样的写法全然能够避免出现错误。同一时候要操作的单元个数能够通过end-begin简单的就算出来,这样做的前提就是用户给出的begin和end都是遵守C语言的“不正确称边界”用法。而假设不使用不正确称边界时候(这时候数组的下标为1~10合法)的诸如代码:
for(i = 1; i <= 10; i++)
a[i] = *p++;
才干够完毕对数组的初始化或者遍历等操作,这样写之后。实际操作的单元个数为10-1+1=10个,这种计算过程假设程序猿在编程的时候忘了加上一个1那么非常easy造成程序的bug。同一时候假设将1和10换成begin和end变量的话,那么用户在调用这个函数的时候传递的begin和end值就算是同一个值,这段代码也会操作到数组中的a[begin]值,这个也会造成调用者使用的困难。
第二个优点是我们能够将&a[10]来作为一个推断条件。作为缓冲区或者数组操作完毕的一个标志,这在实际编程中也是相当方便的。尽管对a[10]的值进行操作是属于非法的行为,可是在ANSI中明白规定了&a[10]这样的操作是合法的。
7.--n >= 0和n-- > 0
在大多数的C语言实现中,--n >= 0至少与等效的n-- > 0一样快,甚至在某些C实现中还要更快,第一个表达式--n >= 0的计算是首先从n中减去1,然后将结果与0比較。第二个表达式的计算则首先保存n,然后从n中减去1,最后比較保存值与0的大小。
8.求值顺序
C语言中仅仅有四个运算符(&&、||、?:、,)存在规定的求值顺序,运算符&&和运算符||首先对左側的操作数求值,仅仅有在须要的时候才会对右側的操作数求值。运算符?:有三个操作数。在a?b:c中,操作数a首先被求值,依据a的值在求操作数b或者c的值(b和c仅仅有一个表达式会被计算)。
而逗号运算符。首先对左側的操作数求值,然后该值被“丢弃”,在对右側操作数求值,整个表达式的值是最右側表达式的值。
逗号运算符举例:a = (1, 2, 3);
a最后被赋值为3。
注意:分隔函数參数的逗号并不是逗号运算符。比如:f(x, y)中的求值顺序是没有定义的,而在函数g((x,y))中却是确定的先x后y的顺序,在后一个样例中,函数g仅仅有一个參数。这个參数的值就是括号里逗号运算符的值。
注意:在C语言中其它全部运算符对其操作数求值的顺序是没有定义的。特别地,赋值运算符并不保证不论什么求值顺序。假设在一个表达式中出现对同一变量的多次使用中出现了++或者--等操作后果有时是不可估计的。比如:
y[i] = x[i++];
9.逻辑运算的结果
逻辑运算符的结果是一个逻辑值,即真(1)或假(0)。而逻辑推断的时候通常约定将0视作假。非0视作真。所以!10表达式的值为假(0),由于10非0在进行非运算的时候被视作真,真的非即为假。
10.溢出
C语言中存在两类整数算术运算,有符号数与无符号数运算。
无符号数运算中没有溢出的说法,然而有符号数操作就可能会发生溢出的情况,当一个运算的结果发生“溢出”时。作出不论什么如果都是不安全的。当碰到可能溢出的情况应该採取的方法是将两个操作数a和b都强制转换为无符号整数:
if((unsigned)a + (unsigned)b > INT_MAX)
complain();
此处的INT_MAX是一个已定义常量,代表可能的最大整数值。
ANSI C标准在<limits.h>中定义了INT_MAX;假设在其他的C语言实现上,读者可能须要自己又一次定义这个值。
原文:http://www.cnblogs.com/mengfanrong/p/5185887.html