一、字符符号
这个问题以前知道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选项还是没有呢?
这个问题以前知道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选项还是没有呢?