《C专家编程》之 安静的改变

先来一道题目:编写一些代码,来确定一个变量是有符号数还是无符号数。

普通程序员可以很快给出一个结果:

#define  ISUNSIGNED(a) ( a >= 0 && -a > 0) 

这个宏定义对int 和unsigned int类型的判断都是正确的,但是总是会有一些让人们觉得匪夷所思的事情发生。在K&R C标准中,这个宏对所有基本数据类型都能正确判断,但是在ANSI C标准中,不适应于 signed / unsigned char/short类型。原因就在于ANSI C所发生的“安静的改变”。

这里所说的改变指代的是“寻常算数转换(usual arithmetic conversion)”. K&R C标准的解释是


而ANSI C标准给的解释是




总结K&R C标准和 ANSI C 标准在算数转换中所描述的,K&R C采用无符号保留(unsigned preserving)原则,即当一个无符号类型和int或更小的数据类型混合使用时,结果仍为无符号类型。这个规则使得有时候会是一个负数丢失符号位:

if( -1 > (unsigned char)1)
  print("-1 is greater than 1, K&R C sematic");
else
  print("-1 is less than 1, ANSI C sematic");

ANSI C 采用值保留(value preserving)原则,当几个整型操作数类型不同时,如果转为signed不丢失信息,则转换为signed,否则转换为unsigned.即转化类型取决于整型的相对大小。如上例中的代码,-1和unsigned char 1都被转换为int.


回到文章的第一个问题,编写如下代码:

#include <stdio.h>


#define  ISUNSIGNED(a) ( a>= 0 && (-a) >0)

int main(int argc, char *argv[])
{
    char c1 = 1;
    unsigned char c2 = 1;

    if(ISUNSIGNED(c1))
        printf("c1 is unsigned char!\n");
    else
        printf("c1 is signed char\n");

    if(ISUNSIGNED(c2))
        printf("c2 is unsigned char\n");
    else
        printf("c2 is signed char\n");
    return 0;
} 

运行结果:

c1 is signed char
c2 is signed char

是的你没有看错,unsigned char被判断成了signed! 原因就在于整形升级,在与signed int 0比较前, unsigned char被升级成signed int, 然后取补码,无论如何此时它都是signed!!!  

想了想解决办法,同时参考网上的一些方法,出现问题的关键在于那个 -a 中的 负号 -  。我们不能对已经发生整型升级的变量再做补码(取负)操作,只能在整型升级前对原始数据类型做补码(取负)操作,这样才是对原始数据类型性质的正确使用:unsigned char 取负仍为正数。下面是修改后的代码:

#include <stdio.h>

int ret, temp;
//#define  ISUNSIGNED(a) ( a>= 0 && (-a) >0)
#define  ISUNSIGNED(a)  (temp = a, ret = ((a=-1)>0), a = temp, ret)

int main(int argc, char *argv[])
{
    char c1 = 1;
    unsigned char c2 = 1;

    if(ISUNSIGNED(c1))
        printf("c1 is unsigned char!\n");
    else
        printf("c1 is signed char\n");

    if(ISUNSIGNED(c2))
        printf("c2 is unsigned char\n");
    else
        printf("c2 is signed char\n");
    return 0;
}

运行结果

c1 is signed char
c2 is unsigned char


猜你喜欢

转载自blog.csdn.net/fang_chuan/article/details/80522264