| 碧海潮生's profile碧海潮生的小屋PhotosBlogLists | Help |
碧海潮生的小屋大江大水天自高 轻舟穿江两岸 笑看山河绕 |
||||
|
November 22 随记一转眼,工作一年半了,代码没写过几行,感觉大多数时间用在看程序、读文档上了。
虽然也干了些实事,比如L4 support,分析feature什么的。
其实除了工作,也没啥其它需要操心的事情,但就是明显感觉人不如在学校时静得下来了,浮躁得很。
那句话怎么说来着,“一月不读书,智商输给猪”。唉,我已经一年没认真看过书了……
July 15 RHEL5 64bit下的数据类型及其转换环境: gcc 4.1.2 20080704 (Red Hat 4.1.2-44), 使用-Wall编译选项
1. 基本数据类型小结 基本类型包括字节型(char)、整型(int)和浮点型(float/double)。
定义基本类型变量时,可以使用符号属性signed、unsigned(对于char、int), 和长度属性short、long(对于int、double)对变量的取值区间和精度进行说明。 下面列举了rhel5_64bit gcc下基本类型所占位数和取值范围:
符号属性 长度属性 基本型 所占位数 取值范围 输入符举例 输出符举例
-- -- char 8 -2^7 ~ 2^7-1 %c %c、%d、%u
signed -- char 8 -2^7 ~ 2^7-1 %c %c、%d、%u unsigned -- char 8 0 ~ 2^8-1 %c %c、%d、%u [signed] short [int] 16 -2^15 ~ 2^15-1 %hd
unsigned short [int] 16 0 ~ 2^16-1 %hu、%ho、%hx [signed] -- int 32 -2^31 ~ 2^31-1 %d
unsigned -- [int] 32 0 ~ 2^32-1 %u、%o、%x [signed] long [int] 64 -2^63 ~ 2^63-1 %ld
unsigned long [int] 64 0 ~ 2^64-1 %lu、%lo、%lx [signed] long long [int] 64 -2^63 ~ 2^63-1 %lld
unsigned long long [int] 64 0 ~ 2^64-1 %llu、%llo、%llx -- -- float 32 +/- 3.40282e+038 %f、%e、%g
-- -- double 64 +/- 1.79769e+308 %lf、%le、%lg %f、%e、%g -- long double 128 +/- 1.189731e+4932 %Lf、%Le、%Lg Linux采用LP64标准,其中指针和长整数都是64位的,而普通的整数则依然是32位的:
sizeof(long) = 8 sizeof(void *) = 8 无类型的整数常量是int类型的。这可能会导致在位移时出现被截断的问题。
例如,在下面的代码中,a的最大值可以是31(在gcc下实验可知,当a>31时1<<a将进行循环移位而非截断)。 这是因为1<<a是int类型的。 long t = 1 << a; 要在64位系统上进行位移,应该使用1L,如下所示: long t = 1L << a; 在32位系统上,int和long大小相同。由于这一点,有些开发人员会交换使用这两种类型。
这可能会导致指针被赋值给int类型,或者反之。 但是在64位的系统上,将指针赋值给int类型会导致高32位的值被截断。 2. 整型提升和寻常算术转换 在64位平台上,ANSI标准中的整型提升和寻常算术转换规则依然适用,但多少显得有些令人费解.
Integral promotion
You can use a char, short, enumerated type, or bit-field, whether signed or unsigned, in any expression that calls for an integer. If an integer can hold all possible values of the original type, the value is converted to an integer; otherwise, the value is converted to an unsigned integer. 注意,整型提升的结果为int/unsigned int,而非long/unsigned long. 如:
sizeof('A') = 4 sizeof(1) = 4 sizeof(1L) = 8 即使是向printf这类可变参数函数传递整型参数时,也不会提升为long/unsigned long.
Conversion between signed and unsigned integers
When an integer with a negative sign is promoted to an unsigned integer of the same or larger type, it is first promoted to the signed equivalent of the larger type, then converted to the unsigned value. 举例而言
long n; int i = -2; unsigned k = 1; n = i + k; 1> 因为i和k的类型不一致,进行寻常算术转换
"i" is an integer with a negative sign, it is promoted to an unsigned integer of the same type (unsigned). 于是i变为一个大的正整数0xFFFFFFFE 2> 0xFFFFFFFE和k=1相加,成为0xFFFFFFFF, 类型为unsigned int. 3> 赋值运算符两侧类型不一致,进行寻常算术转换(注意!不是整型提升) 由于中间结果0xFFFFFFFF为无符号数,所以不会进行符号扩展,因此直接添0即得到最终结果 0x00000000FFFFFFFF = 4294967295 可见问题出在第1步里,只需将k强制转换为int即可:
n = i + (int)k; 这样运算的中间结果0xFFFFFFFF为有符号数,会进行符号扩展,最终结果为 0xFFFFFFFFFFFFFFFF = -1 其实整型间的算术转换令人迷惑的无非是以下四种情况:
情况 \ 平台 ILP32 LP64
int vs. unsigned int unsigned int unsigned int long vs. unsigned long unsigned long unsigned long int vs. unsigned long unsigned long unsigned long
unsigned int vs. long unsigned long long 具体说来,如果一边是无符号数另一边是有符号数, 那么若...
1> 无符号数的Rank不低于有符号数的Rank,则把有符号数转成另一边的无符号类型。
例如unsigned long和int做算术运算时都转成unsigned long,unsigned long和long做算术运算时也都转成unsigned long。 2> 无符号数的Rank低于有符号数的Rank。这时又分为两种情况,如果这个有符号数类型能够覆盖这个无符号数类型的取值范围,
则把无符号数转成另一边的有符号类型。例如LP64的平台上unsigned int和long在做算术运算时都转成long。 3> 否则,也就是这个符号数类型不足以覆盖这个无符号数类型的取值范围,则把两边都转成两者之中较高Rank的无符号类型。
例如ILP32的平台上unsigned int和long在做算术运算时都转成unsigned long。 这个规则比《C Expert Programming》里讲的简单规则准确,也容易记忆。
3. 基本类型特征及扩展数据类型 标准头文件<limits.h>定义了整型特征:
INT_MIN INT_MAX SHRT_MIN SHRT_MAX USHRT_MAX LONG_MIN LONG_MAX ULONG_MAX LLONG_MIN LLONG_MAX ULLONG_MAX 标准头文件<float.h>定义了浮点特性:
FLT_EPSILON FLT_MIN FLT_MAX DBL_EPSILON DBL_MIN DBL_MAX LDBL_EPSILON LDBL_MIN LDBL_MAX 标准(ISO C99)库中的扩展类型: <stddef.h>
typedef long unsigned int size_t; typedef long int ptrdiff_t; <signal.h>
typedef int sig_atomic_t; <time.h>
typedef long int clock_t; typedef long int time_t; <wctype.h>
typedef unsigned long int wctype_t; typedef const signed int *wctrans_t; <wchar.h>
typedef int wchar_t; typedef unsigned int wint_t; <stdint.h>
typedef signed char int8_t; typedef short int int16_t; typedef int int32_t; typedef long int int64_t; typedef unsigned char uint8_t;
typedef unsigned short int uint16_t; typedef unsigned int uint32_t; typedef unsigned long int uint64_t; typedef long int intptr_t;
typedef unsigned long int uintptr_t; POSIX库中常用的扩展类型:
typedef int pid_t;
typedef int key_t; typedef long int ssize_t; typedef long int off_t; July 11 [ZT] Top 10 reasons why Pascal is better than C1. Pascal, noble language as it is, was named after a famous French mathematician and philosopher, Blaise Pascal. C was named after a Sesame Street character.
2. Pascal's inventor, Nicholas Wirth, and parameter passing conventions coalesce to form a nifty pun: You can pronounce his name by reference: Wirth or by value: Worth. C was invented at Bell Labs, where they wouldn't know a joke from a transistor.
3. There is only one Pascal, as defined by Wirth, while C has (shall we say?) several fathers: Kernighan & Ritchie, Harbison & Steele, Barnum & Bailey, and Laurel & Hardy.
4. In C, the following variable names are all different: thesame, TheSame, theSame, and THESAME. Nuff said.
5. In Pascal, when you fool with a pointer or handle, you know you're fooling around with a pointer or handle. In C, you could be fooling around with anything. C is the ultimate language for computational promiscuity.
6. In Pascal, we *know* how big an integer is.
7. C is used by liberal, Democratic, Mike Dukakis types of programmers. Pascal is a favorite of the GOP. Hey, we know what the big language at Berkeley is, don't we?
8. C is the only language in the civilized world that still refuses to recognize the $ sign for a hexadecimal constant and continues to promote that base pretender to the throne: 0x00.
9. Pascal has well-defined rules for Scope, while C appears to be using Listerine. This accounts for the medicine breath of many C programmers.
10. In C, you can do this:
for(;P("\n").R-;P("|"))for(e=3DC;e-;P("_"+(*u++/8)%2))P("| "+(*u/4)%2);
In Pascal, you CAN'T do this :
for(;P("\n").R-;P("|"))for(e=3DC;e-;P("_"+(*u++/8)%2))P("| "+(*u/4)%2);
|
||||
|
|