char/unsigned char对比较结果的致命影响

一、字符符号
这个问题以前知道char类型有默认有符号和无符号的区分,但是这两种区分到底有什么区别,概念还是比较模糊的,直到今天因为字符符号搞了一个大乌龙,搞的版本无法启动,才算是有了一次刻骨铭心的认识。
二、比较语句
下面是比较的一个模型,gcc中,char类型在i386/MIPS体系结构默认是有符号的,而PowerPC/ARM是无符号的。现在看一个比较指令
int foo(char cond)
{
  return cond == 0xCC;
}
这个现在假设char传入的值为0xCC,此时这个函数返回值是多少呢?非常惊讶的是,返回值为0,事实上这是一个恒为0的函数,在fedora core上编译该文件
[root@Harry falsealways]# cat falsealways.c
int foo(char cond)
{
    return cond == 0xcc;
}
[root@Harry falsealways]# gcc -c falsealways.c -Wall
[root@Harry falsealways]# objdump -d falsealways.o

falsealways.o:     file format elf32-i386


Disassembly of section .text:

00000000 <foo>:
   0:    55                       push   %ebp
   1:    89 e5                    mov    %esp,%ebp
   3:    83 ec 04                 sub    $0x4,%esp
   6:    8b 45 08                 mov    0x8(%ebp),%eax
   9:    88 45 fc                 mov    %al,-0x4(%ebp)
   c:    b8 00 00 00 00           mov    $0x0,%eax  这里返回值始终为0,也就是无论你传入什么值,这个函数都只会返回零,这个返回值在编译时就确定了
  11:    c9                       leave  
  12:    c3                       ret    
[root@Harry falsealways]# gcc -v
Using built-in specs.
Target: i686-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch=i686 --build=i686-redhat-linux
Thread model: posix
gcc version 4.4.2 20091027 (Red Hat 4.4.2-7) (GCC) 
三、gcc是怎么看这个问题的
对于 
cond == 0xCC;
更为清楚的表达为
(char)cond == 0x000000CC;
也就是说,这个0xcc你看起来是一个字符常量,事实上他是一个整数常量,占用4个字节,所以char类型要向它看齐,从char拔高到int。

1、假设传入的cond值为负数,在进行带符号扩展时,最高3byte全部补充为0xFF,即为0xFFFFFFFXX,由于高3bytes和常量0x000000CC的对应值不同,所以两个值肯定不同;
2、假设cond的值为正值,那么它作为char的最高bit,也就是从右向左的第八bit为0,而常量0x000000cc的第八bit为1,所以也不可能相等。

但是等一下,在4.1编译器中这里还会给一个警告,为什么这个坑爹的4.4即使加了Wall选项还是没有呢?
 
 
 
 
 
原文地址:https://www.cnblogs.com/tsecer/p/10486095.html