引入
在大一学习C语言的时候,我习惯的认为以下两个函数是等价的
// 1
float sum_elements(const float a[], size_t length){
float result = 0;
for(size_t i = 0; i <= length - 1; ++i){
result += a[i];
} // @**@
return result;
}
// 2
float sum_elements(const float a[], size_t length){
float result = 0;
for(size_t i = 0; i < length; ++i){
result += a[i];
} // @**@
return result;
}
但是, 当传入的length==0
时,两个函数却有不同的行为
在我原来的观念里
-
函数(1)运行时,是不能进入循环的,因为条件
0 < -1
不满足,因而能得到正确的结果 -
但是,实际情况却是这样
➜ 计算机操作系统 ./test [1] 14319 segmentation fault ./test
-
这就有问题了,为啥呢?
这是深入了解计算机操作系统中的一道习题,笔者用的是原书第三版,位置在题2-25
size_t
的定义
// gcc on linux
// in header stddef.h
typedef __SIZE_TYPE__ size_t;
// __SIZE_TYPE__
#define __SIZE_TYPE long unsigned int
C语言整数比较
同种类型的整数比较结果是遵循算术结果的,关键在于不同类型的比较,特别是有符号数和无符号数的比较
以下是在书中归纳的几条规则
-
不同类型的操作数进行运算时,按以下方向进行隐式类型转化
bool->char->short int->int(默认整数类型)->unsigned int->long
->unsigned->long long->float->double(默认浮点数类型)
->long double
C语言的布尔型变量定义在
C99
标准中,使用时要include
头文件stdbool.h
// stdbool.h部分内容 #ifndef __cplusplus #define bool _Bool #define true 1 #define false 0 #endif // false的字节表示为00000000 // true的字节表示为00000001 // sizeof(bool)=1
-
于是,会有以下几个神奇的现象
size_t
(扩展为unsigned long
) 和int
进行运算时,会转化成unsigned long
进行计算,结果为(size_t)0-(size_t)1=18446744073709551615=(size_t)(-1)
- 然后是
(size_t)i(=0)<=(size_t)(-1)
的结果,自然就为1,于是进入循环,然后数组越界
-
下面是几个示例,来自于课本的第53页(原书第三版)
exp | type | value |
---|---|---|
0==0U | unsigned | 1 |
-1<0 | signed | 1 |
-1<0U | unsigned | 0 |
INT_MAX > INT_MIN | signed | 1 |
2147483647U > INT_MIN | unsigned | 0 |
INT_MAX>(int)2147483648U | signed | 1 |
-1>-2 | signed | 1 |
(unsigned)-1>-2 | unsigned | 1 |
INT_MAX
即INT32_MAX
,INT_MIN
即INT32_MIN