碧海潮生's profile碧海潮生的小屋PhotosBlogLists Tools Help

碧海潮生的小屋

大江大水天自高 轻舟穿江两岸 笑看山河绕
Photo 1 of 10

碧海潮生 Kingwei

Windows Media Player

November 22

随记

一转眼,工作一年半了,代码没写过几行,感觉大多数时间用在看程序、读文档上了。
虽然也干了些实事,比如L4 support,分析feature什么的。
其实除了工作,也没啥其它需要操心的事情,但就是明显感觉人不如在学校时静得下来了,浮躁得很。
 
那句话怎么说来着,“一月不读书,智商输给猪”。唉,我已经一年没认真看过书了……
 
November 07

图+名章

October 01

巴黎即景

 
 
 
 
 
 
 
 
 
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 C

1. 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);
 
 

天气预告/访问统计

free web hit counter