关于C语言输出ASCII码128~255和有符号char型溢出的问题。此处大坑弄明白了后记录下来分享……

以下代码在Windows控制台正常输出会出现乱码

#include<stdio.h>
int main(){
    char a=197;
    printf("%c",a);
    return 0;
}

为什么呢?

1. 我们先说明前提条件:C语言中char类型默认是有符号类型(范围是-128~127之间),当然也可以声明无符号类型的(unsigned char),这不在本文讨论范围之内。

在上列中,a = 197对应的字符是在标准ASCII表中是不存在的,标准ASCII表只定义了0~127的字符,而我们都知道一个字节可以表示0~255,因此多余的字节ASCII并没有使用,而是作为了扩展编码。因此之所以会输出问号或则其它乱码符号,是因为我们的ASCII编码中没有这个位置的编码符号。

2. 接下来接着说,我们中文家庭版的Windows10电脑里面,CMD中默认的编码格式是936(ANSI/OEM - 简体中文GBK)

通过以下一个引用大家可以高明白GBK编码和ASCII编码的关系。

【1】ASCII: 每个字符占据1bytes,用二进制表示的话最高位必须为0(扩展的ASCII不在考虑范围内),因此ASCII只能表示128个字
【2】GB2312: 最早一版的中文编码,每个字占据2bytes。由于要和ASCII兼容,那这2bytes最高位不可以为0了(否则和ASCII会有冲突)。在GB2312中收录了6763个汉字以及682个特殊符号,已经囊括了生活中最常用的所有汉字。
【3】GBK: 由于GB2312只有6763个汉字,我汉语博大精深,只有6763个字怎么够?于是GBK中在保证不和GB2312、ASCII冲突(即兼容GB2312和ASCII)的前提下,也用每个字占据2bytes的方式又编码了许多汉字。经过GBK编码后,可以表示的汉字达到了20902个,另有984个汉语标点符号、部首等。值得注意的是这20902个汉字还包含了繁体字。

补充:

【4】GB18030: 然而,GBK的两万多字也已经无法满足我们的需求了,还有更多可能你自己从来没见过的汉字需要编码。这时候显然只用2bytes表示一个字已经不够用了(2bytes最多只有65536种组合,然而为了和ASCII兼容,最高位不能为0就已经直接淘汰了一半的组合,只剩下3万多种组合无法满足全部汉字要求)。因此GB18030多出来的汉字使用4bytes编码。当然,为了兼容GBK,这个四字节的前两位显然不能与GBK冲突(实操中发现后两位也并没有和GBK冲突)。我国在2000年和2005年分别颁布的两次GB18030编码,其中2005年的是在2000年基础上进一步补充。至此,GB18030编码的中文文件已经有七万多个汉字了,甚至包含了少数民族文字。

  • 最终要的一点就是GBK编码格式适合ASCII编码格式兼容的,因此197自然也没有为它设计对应的字符。

  • 如果需要显示出来128~255的字符,我们就需要将控制台的编码格式改变,比如改成美国的一种编码标准:437(OEM-美国),就可以正常显示显示SCII码中128-255的特殊字符。

  • 最简单的方法就是在程序中加上以下的头文件和命令就可以修改代码页的默认显示方式:

#include<windows.h>
#include<stdio.h>
int main(){
    SetConsoleOutputCP(437);
    char a=197,b=198;
    printf("%c %c",a,b);
}
  • 通过以上修改,就可以正常显示197和198对应的字符,分别是 ┼ 和 ╞ ,当然这只是在一种编码格式下,如果再更换一种编码格式,可能又不一样。

3. 除此之外,C语言中,当char是有符号类型的时,即表示范围为-128~127。在有符号char类型当中0 ~ 127和-128~-1这两段在存储上分为两个不同的段。

十进制对应的补码表示
-1281000 0000
-1271000 0001
-1261000 0010
-1251000 0011
-21111 1110
-11111 1111
00000 0000
10000 0001
1270111 1111

这就是计算机中采用的补码表示法,二进制最高位代表符号位,1为负数,0为整数。

综上所述,数据在计算机中的存储形式是以补码的形式存储的,并且在C语言中有符号的char型,其负数段与正数段在内存的存储形式不一样(最高位),但其任然满足溢出取模原理

如有不足,欢迎指出。

  • 17
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值