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选项还是没有呢?
这个问题以前知道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选项还是没有呢?
分类:
C/C++基础
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架