#include <stdio.h>
int main(void)
{
long a;
unsigned short b;
unsigned long c, d;
short e;
a = -1L;
b = 1U;
d = a + b;
printf("a = %dL, b = %uU, d = %uUL, a>b = %d\n",a, b, d, a > b);
a = -1L;
c = 1UL;
d = c + a;
printf("a = %dL, c = %uUL, d =%uUL, a>c = %d\n", a, c, d, a > c);
e = -1;
c = 1UL;
d = e + c;
printf("e = %d, c = %uUL, d =%uUL, e>c = %d\n", e, c, d, e> c);
}
运行结果如下(在我的环境中compaq Tru64, cc)
a = -1L, b = 1U, d = 0UL, a>b = 0
a = -1L, c = 1UL, d =0UL, a>c = 1
e = -1, c = 1UL, d =0UL, e>c = 1
我们不难发现,在比较操作中,将无符号的短整数扩展为了有符号的长整型。所以有-1L < 1U;又将有符号的短整数提升为了无符号的长整型,所以有-1 > 1UL;还将相同长度的两个数的有符号的长整数转换为无符号的长整数,所以有-1L > 1UL。所以,这里的规则似乎是在类型长短不一时,以较长的为准,长度相同时,有符号的转化为无符号的,但也仅仅是比较操作,其它呢?还是要看实现。在加法操作中,不管数据的长短,一律作为有符号数计算,实际上有符号有无符号的加减法结果是一样的,这里一样指的是操作后变量在内存中的二进制串是一样的,只是它作为有符号数还是无符号数展示而已。所以上例中d始终是0。
为了证明在不同的环境下结果不同,我又在windows下,用Turbo C运行了一下,结果如下:
a = -1L, b = 65535U, d = 1UL, a>b = 0
a = -1L, c = 65535UL, d =1UL, a>c = 0
e = -1, c = 1UL, d =0UL, e>c = 0
这就意味着你编程时要特别注意,在使用前要测试一下你的环境对这个是如何处理的,也就意味你的代码是不可移植的。所以一条很重要的编程规则就是,尽量避免使用无符号数。
二是在函数的调用中的自动类型转换。
C语言中,在将实参传给函数时,如果类型不匹配,会进行自动类型转换。如果在函数声明时没有给出参数列表,则C编译器会认为不知道参数是什么,不进行类型检查,这样可能会导致错误的函数调用。C语言的类型检查也不是太严格,甚至警告也不会给就自动转换了。无参数的则要么提升,要不就原样拷贝。这里,原样拷贝比提升安全,因为有类型检查,所以在函数内部没有转换。
在ANSI C标准之前,处理比较复杂,声明不能有形参,要是一个空列表,而且,调用时,会将单精度转换为双精度的,将short, char转换为int。那这样就有一个问题了,如果函数确实需要一个char怎么办呢?办法是在定义的内部转换。也就是形参全部用int或double型表示,然后在内部定义相应需要类型的局部变量,在内部来一个赋值的再转换,显然这种方法比较笨。但许多编译器为了与老版本兼容,还是采用的这种方式,在函数声明中,不强制要求写出参数列表,调用时也不作类型检查。然后在函数内部转换。当然,还一种方式就是不作任何类型检查,完全取决于程序员,这是最危险的方法。
这些都取决于编译器。
函数的返回值也要注意,如果没有显式的声明,则默认为int,对某些调用会出错。因为调用程序会按照默认的类型来取返回值,这样,如果返回值的类型不是这样,就极有可能得到一个错误的结果。返回值的存储地点由编译器决定,一般通过寄存器来实现。
这些问题本质上都是由于类型的转换引起的,C语言对类型的检查不那么严格,所以容易引起许多潜在的错误。
下面给一个例子说明一下:
#include <stdio.h>
typedef struct tag_data
{
char c1;
char c2;
char c3;
char c4;
}DATA, *PDATA;
int main(void)
{
DATA adata = {-1, 'a', 'b', 'c'};
int iret = -1;
printf("Enter a charactor\n");
iret = scanf("%d", &adata.c1);
printf("iret = %d, adata.c1 = %c, adata.c2 = %c, adata.c3 = %c, adata.c4 = %c\n", iret, adata.c1, adata.c2, adata.c3, adata.c4);
printf("iadata.c1 = %d, adata.c2 = %d, adata.c3 = %d, adata.c4 = %d\n", adata.c1, adata.c2, adata.c3, adata.c4);
return 0;
}
运行结果如下:
Enter a charactor
a
iret = 0, adata.c1 = , adata.c2 = a, adata.c3 = b, adata.c4 = c
adata.c1 = -1, adata.c2 = 97, adata.c3 = 98, adata.c4 = 99
再一次运行如下:
Enter a charactor
2048
iret = 1, adata.c1 = , adata.c2 =, adata.c3 = , adata.c4 =
adata.c1 = 0, adata.c2 = 8, adata.c3 = 0, adata.c4 = 0