当前位置:C++技术网 > 资讯 > 警告C4309: “初始化”: 截断常量值 问题的分析和解决方案

警告C4309: “初始化”: 截断常量值 问题的分析和解决方案

更新时间:2016-03-16 21:31:56浏览次数:1+次

    今天遇到了这样一个警告:
warning C4309: “初始化”: 截断常量值
    这个警告在看一个人的代码时也发现了。只是当时没有在意。不过现在我的代码中出现了,我觉得不能再无视它的存在了。对于一个追求高质量代码的程序员,是无法容忍这样的警告的。况且,如果不搞清楚,谁知道会不会给自己埋下地雷呢。所以,为了让你自己的代码更加完美,给自己铺一个更结实的路,就总结下吧。
    我的代码是这样的:
char Buf[]={0x12,0x00,0xEE,0x45};

    粗略来看,这个代码没有问题。然而VS编译器却给出了警告。既然有警告,还是有他的道理的。如果把0xEE改成0x12这样的比较小的数字,就没有问题了。那么问题就出在这个数字里了。
    难不成这个数字还能有错?0xEE的十进制值位238,而我们知道char占一个字节,也就是8位,所能表示的范围为2的8次方。当然这个范围是0-2^8(256),而238是小于256的。照理说,这是没有问题的。不要看这里用的是char,我们这里只是将char用作一个字节而已。所以我们可以无视字符形式的限制。
    然而,实际的运行逻辑并不是我们这样简单的想想而已。我们将char存储字符时,从来也不会考虑字符编码的正负问题,因为ASCII编码有效值在0-127这个范围里。为什么呢?
    char是字符类型,字符类型变量在存储字符时是存储字符的编码值,ASCII编码表最大的就是127。8个字节最大能够表示的是255(第一个是0)。那么也就是说,编码值只用了数值范围的一半,也就是只用了7位来编制ASCII表的。以前在制定ASCII表时是为了节省内存,所以有一位没有使用,对于美国本土来说,7位足够用了。当时的条件,内存确实很昂贵,所以选择7位也是很自然的事情。
    在很多情况下,我们将char数组用作字节序列数组,所以此时就无视char的字符编码属性,而只是将char数组中存储一个数字而已。默认的情况下,char数组的解释当然就是按照字符标准来处理的。如果超过了127,也就超出了ASCII编码的范围。所以我们将char数组用来存储数字,就不会将范围限制在0-127之内了,而是将范围看成一个字节所能表示的范围,即0-255了。编译器的警告,说截断常量值也就是基于这个道理。编译器看到char的范围,超出后觉得就不正常了。人很灵活,所以指鹿为马也是很常见的事情了。如果你只是按照字节来使用char数组,是没有问题的。因为你始终都是按照数值来处理。注意,不能时而用成字符,时而用成字节数值,这样很容易造成数据错乱,除非你很清楚,就可以这样混用。
    如果你想消除这个警告,很简单。你可以使用unsigned char类型来代替。因为是无符号的,所以将支持的范围改变成0-255,而不是[-128,127]了。这样你使用起来,编译器也明白是这样的用法。unsigned char可以用来支持扩展的ASCII编码,所以编译器就会知道最后一位也是有效的,也就知道编码值可以到255.那么你将无符号char当做一个字节来使用,完全没有问题。虽然编译器还是一位这是字符编码值,但是你却当做一个数值在使用而已。尽管编译器和你理解的不一样,只要达到最终的效果,那就可以了。
    所以,使用char数组,在赋值时超过127就会出现【warning C4309: “初始化”: 截断常量值】警告。只要你用得好,警告也是没有关系的。就好比人家警告你拿刀会很危险,但是你用的好,可以切一手好菜哦。
    将char用作字节是非常常见的,比如串口编程。所以,如果你一直只是将char当做字符类型的话,就有点不适应这样的做法。慢慢适应吧。char类型就是因为它占一个字节,很好的支持了字节序列应用场景。在Windows编程中,如果你包含了Windows.h头文件,那么你可以使用byte这个类型。这个名字叫做字节类型,实际上,它并不是一个新类型,下面是它的定义:
typedef unsigned char byte;

    看到没,byte只是unsigned char类型的别名而已,并不是新类型。不过,你在使用byte时会感觉比较舒服。实际上,还是原来的味道,只是换了一个包装而已。前面分析的无符号字符类型很好的支持字节数值的使用,在Windows中都被定义成了一个专门的别名哦。
    好了,说到这里,应该说清楚了吧。如果还有什么问题,可以留言。